- Added history reading and parsing
- Added evaulation of history data (still work in progress)
- Added custom actions (#1455), so that we can manually do "Wake Up and Tune" (new button in actions)
- Started decoding DailyTotals records (need TDD for bolus and basal).
This commit is contained in:
Andy Rozman 2018-11-05 16:49:59 +00:00
parent 5b9bd2adfc
commit b4ce95902b
49 changed files with 2952 additions and 1214 deletions

View file

@ -64,7 +64,7 @@ android {
multiDexEnabled true
versionCode 1500
// dev_version: 2.0i
version "medtronic-0.4"
version "medtronic-0.5.1-SNAPSHOT"
buildConfigField "String", "VERSION", '"' + version + '"'
buildConfigField "String", "BUILDVERSION", '"' + generateGitBuild() + '-' + generateDate() + '"'
buildConfigField "String", "HEAD", '"' + generateGitBuild() + '"'

View file

@ -69,6 +69,7 @@ import info.nightscout.androidaps.plugins.PumpDanaRv2.DanaRv2Plugin;
import info.nightscout.androidaps.plugins.PumpInsight.InsightPlugin;
import info.nightscout.androidaps.plugins.PumpMDI.MDIPlugin;
import info.nightscout.androidaps.plugins.PumpMedtronic.MedtronicPumpPlugin;
import info.nightscout.androidaps.plugins.PumpMedtronic.util.MedtronicConst;
import info.nightscout.androidaps.plugins.PumpVirtual.VirtualPumpPlugin;
import info.nightscout.androidaps.plugins.Sensitivity.SensitivityAAPSPlugin;
import info.nightscout.androidaps.plugins.Sensitivity.SensitivityOref0Plugin;
@ -89,6 +90,7 @@ import info.nightscout.androidaps.receivers.KeepAliveReceiver;
import info.nightscout.androidaps.receivers.NSAlarmReceiver;
import info.nightscout.androidaps.services.Intents;
import info.nightscout.utils.FabricPrivacy;
import info.nightscout.utils.SP;
import io.fabric.sdk.android.Fabric;
public class MainApp extends Application {
@ -268,7 +270,7 @@ public class MainApp extends Application {
private void setBTReceiver() {
// SP.putDouble(RileyLinkConst.Prefs.LastGoodDeviceFrequency, null);
// SP.remove(RileyLinkConst.Prefs.LastGoodDeviceFrequency);
SP.remove(MedtronicConst.Statistics.LastPumpHistoryEntry); // FIXME remove
// RileyLink framework needs to know, when BT was reconnected, so that we can reconnect to RL device
btReceiver = new BroadcastReceiver() {

View file

@ -1,12 +1,11 @@
package info.nightscout.androidaps.db;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Objects;
import com.google.common.base.MoreObjects;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;
import info.nightscout.androidaps.logging.L;
@ -14,9 +13,9 @@ import info.nightscout.androidaps.logging.L;
* Created by mike on 20.09.2017.
*/
@DatabaseTable(tableName = DatabaseHelper.DATABASE_TDDS)
public class TDD {
private static Logger log = LoggerFactory.getLogger(L.DATABASE);
@DatabaseField(id = true)
@ -32,17 +31,30 @@ public class TDD {
public double total;
public double getTotal(){
return (total > 0d) ? total:(bolus+basal);
public double getTotal() {
return (total > 0d) ? total : (bolus + basal);
}
public TDD() { }
public TDD() {
}
public TDD(long date, double bolus, double basal, double total){
public TDD(long date, double bolus, double basal, double total) {
this.date = date;
this.bolus = bolus;
this.basal = basal;
this.total = total;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this) //
.add("date", date) //
.add("bolus", bolus) //
.add("basal", basal) //
.add("total", total) //
.toString();
}
}

View file

@ -1,10 +1,14 @@
package info.nightscout.androidaps.interfaces;
import java.util.List;
import org.json.JSONObject;
import info.nightscout.androidaps.data.DetailedBolusInfo;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.data.PumpEnactResult;
import info.nightscout.androidaps.plugins.Actions.defs.CustomAction;
import info.nightscout.androidaps.plugins.Actions.defs.CustomActionType;
/**
* Created by mike on 04.06.2016.
@ -12,49 +16,99 @@ import info.nightscout.androidaps.data.PumpEnactResult;
public interface PumpInterface {
boolean isInitialized(); // true if pump status has been read and is ready to accept commands
boolean isSuspended(); // true if suspended (not delivering insulin)
boolean isBusy(); // if true pump is not ready to accept commands right now
boolean isConnected(); // true if BT connection is established
boolean isConnecting(); // true if BT connection is in progress
boolean isSuspended(); // true if suspended (not delivering insulin)
boolean isBusy(); // if true pump is not ready to accept commands right now
boolean isConnected(); // true if BT connection is established
boolean isConnecting(); // true if BT connection is in progress
boolean isHandshakeInProgress(); // true if BT is connected but initial handshake is still in progress
void finishHandshaking(); // set initial handshake completed
void connect(String reason);
void disconnect(String reason);
void stopConnecting();
void getPumpStatus();
// Upload to pump new basal profile
PumpEnactResult setNewBasalProfile(Profile profile);
boolean isThisProfileSet(Profile profile);
long lastDataTime();
double getBaseBasalRate(); // base basal rate, not temp basal
PumpEnactResult deliverTreatment(DetailedBolusInfo detailedBolusInfo);
void stopBolusDelivering();
PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes, Profile profile, boolean enforceNew);
PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes, Profile profile,
boolean enforceNew);
PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes, Profile profile, boolean enforceNew);
PumpEnactResult setExtendedBolus(Double insulin, Integer durationInMinutes);
//some pumps might set a very short temp close to 100% as cancelling a temp can be noisy
//when the cancel request is requested by the user (forced), the pump should always do a real cancel
// some pumps might set a very short temp close to 100% as cancelling a temp can be noisy
// when the cancel request is requested by the user (forced), the pump should always do a real cancel
PumpEnactResult cancelTempBasal(boolean enforceNew);
PumpEnactResult cancelExtendedBolus();
// Status to be passed to NS
JSONObject getJSONStatus(Profile profile, String profileName);
String deviceID();
// Pump capabilities
PumpDescription getPumpDescription();
// Short info for SMS, Wear etc
String shortStatus(boolean veryShort);
boolean isFakingTempsByExtendedBoluses();
PumpEnactResult loadTDDs();
List<CustomAction> getCustomActions();
PumpEnactResult executeCustomAction(CustomActionType customActionType);
}

View file

@ -1,22 +1,28 @@
package info.nightscout.androidaps.plugins.Actions;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import android.app.Activity;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import com.crashlytics.android.answers.CustomEvent;
import com.squareup.otto.Subscribe;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.activities.HistoryBrowseActivity;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.activities.HistoryBrowseActivity;
import info.nightscout.androidaps.activities.TDDStatsActivity;
import info.nightscout.androidaps.db.ExtendedBolus;
import info.nightscout.androidaps.db.TemporaryBasal;
@ -25,12 +31,13 @@ import info.nightscout.androidaps.events.EventInitializationChanged;
import info.nightscout.androidaps.events.EventRefreshOverview;
import info.nightscout.androidaps.events.EventTempBasalChange;
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.plugins.Actions.defs.CustomAction;
import info.nightscout.androidaps.plugins.Actions.dialogs.FillDialog;
import info.nightscout.androidaps.plugins.Actions.dialogs.NewExtendedBolusDialog;
import info.nightscout.androidaps.plugins.Actions.dialogs.NewTempBasalDialog;
import info.nightscout.androidaps.plugins.Careportal.CareportalFragment;
import info.nightscout.androidaps.plugins.Careportal.Dialogs.NewNSTreatmentDialog;
import info.nightscout.androidaps.plugins.Careportal.OptionsToShow;
import info.nightscout.androidaps.plugins.Careportal.Dialogs.NewNSTreatmentDialog;
import info.nightscout.androidaps.plugins.Common.SubscriberFragment;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.ConfigBuilder.ProfileFunctions;
@ -45,10 +52,12 @@ public class ActionsFragment extends SubscriberFragment implements View.OnClickL
static ActionsPlugin actionsPlugin = new ActionsPlugin();
static public ActionsPlugin getPlugin() {
return actionsPlugin;
}
View actionsFragmentView;
SingleClickButton profileSwitch;
SingleClickButton tempTarget;
SingleClickButton extendedBolus;
@ -59,24 +68,24 @@ public class ActionsFragment extends SubscriberFragment implements View.OnClickL
SingleClickButton tddStats;
SingleClickButton history;
public ActionsFragment() {
super();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
try {
View view = inflater.inflate(R.layout.actions_fragment, container, false);
profileSwitch = (SingleClickButton) view.findViewById(R.id.actions_profileswitch);
tempTarget = (SingleClickButton) view.findViewById(R.id.actions_temptarget);
extendedBolus = (SingleClickButton) view.findViewById(R.id.actions_extendedbolus);
extendedBolusCancel = (SingleClickButton) view.findViewById(R.id.actions_extendedbolus_cancel);
tempBasal = (SingleClickButton) view.findViewById(R.id.actions_settempbasal);
tempBasalCancel = (SingleClickButton) view.findViewById(R.id.actions_canceltempbasal);
fill = (SingleClickButton) view.findViewById(R.id.actions_fill);
profileSwitch = (SingleClickButton)view.findViewById(R.id.actions_profileswitch);
tempTarget = (SingleClickButton)view.findViewById(R.id.actions_temptarget);
extendedBolus = (SingleClickButton)view.findViewById(R.id.actions_extendedbolus);
extendedBolusCancel = (SingleClickButton)view.findViewById(R.id.actions_extendedbolus_cancel);
tempBasal = (SingleClickButton)view.findViewById(R.id.actions_settempbasal);
tempBasalCancel = (SingleClickButton)view.findViewById(R.id.actions_canceltempbasal);
fill = (SingleClickButton)view.findViewById(R.id.actions_fill);
tddStats = view.findViewById(R.id.actions_tddstats);
history = view.findViewById(R.id.actions_historybrowser);
@ -90,6 +99,8 @@ public class ActionsFragment extends SubscriberFragment implements View.OnClickL
history.setOnClickListener(this);
tddStats.setOnClickListener(this);
actionsFragmentView = view;
updateGUI();
return view;
} catch (Exception e) {
@ -99,34 +110,41 @@ public class ActionsFragment extends SubscriberFragment implements View.OnClickL
return null;
}
@Subscribe
public void onStatusEvent(final EventInitializationChanged ev) {
updateGUI();
}
@Subscribe
public void onStatusEvent(final EventRefreshOverview ev) {
updateGUI();
}
@Subscribe
public void onStatusEvent(final EventExtendedBolusChange ev) {
updateGUI();
}
@Subscribe
public void onStatusEvent(final EventTempBasalChange ev) {
updateGUI();
}
@Override
protected void updateGUI() {
Activity activity = getActivity();
if (activity != null)
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
if (ConfigBuilderPlugin.getPlugin().getActiveProfileInterface() != null && ConfigBuilderPlugin.getPlugin().getActiveProfileInterface().getProfile() != null) {
if (ConfigBuilderPlugin.getPlugin().getActiveProfileInterface() != null
&& ConfigBuilderPlugin.getPlugin().getActiveProfileInterface().getProfile() != null) {
profileSwitch.setVisibility(View.VISIBLE);
} else {
profileSwitch.setVisibility(View.GONE);
@ -144,34 +162,37 @@ public class ActionsFragment extends SubscriberFragment implements View.OnClickL
final PumpInterface pump = ConfigBuilderPlugin.getPlugin().getActivePump();
final boolean basalprofileEnabled = MainApp.isEngineeringModeOrRelease()
&& pump.getPumpDescription().isSetBasalProfileCapable;
&& pump.getPumpDescription().isSetBasalProfileCapable;
if (!basalprofileEnabled || !pump.isInitialized() || pump.isSuspended())
profileSwitch.setVisibility(View.GONE);
else
profileSwitch.setVisibility(View.VISIBLE);
if (!pump.getPumpDescription().isExtendedBolusCapable || !pump.isInitialized() || pump.isSuspended() || pump.isFakingTempsByExtendedBoluses()) {
if (!pump.getPumpDescription().isExtendedBolusCapable || !pump.isInitialized()
|| pump.isSuspended() || pump.isFakingTempsByExtendedBoluses()) {
extendedBolus.setVisibility(View.GONE);
extendedBolusCancel.setVisibility(View.GONE);
} else {
ExtendedBolus activeExtendedBolus = TreatmentsPlugin.getPlugin().getExtendedBolusFromHistory(System.currentTimeMillis());
ExtendedBolus activeExtendedBolus = TreatmentsPlugin.getPlugin().getExtendedBolusFromHistory(
System.currentTimeMillis());
if (activeExtendedBolus != null) {
extendedBolus.setVisibility(View.GONE);
extendedBolusCancel.setVisibility(View.VISIBLE);
extendedBolusCancel.setText(MainApp.gs(R.string.cancel) + " " + activeExtendedBolus.toString());
extendedBolusCancel.setText(MainApp.gs(R.string.cancel) + " "
+ activeExtendedBolus.toString());
} else {
extendedBolus.setVisibility(View.VISIBLE);
extendedBolusCancel.setVisibility(View.GONE);
}
}
if (!pump.getPumpDescription().isTempBasalCapable || !pump.isInitialized() || pump.isSuspended()) {
tempBasal.setVisibility(View.GONE);
tempBasalCancel.setVisibility(View.GONE);
} else {
final TemporaryBasal activeTemp = TreatmentsPlugin.getPlugin().getTempBasalFromHistory(System.currentTimeMillis());
final TemporaryBasal activeTemp = TreatmentsPlugin.getPlugin().getTempBasalFromHistory(
System.currentTimeMillis());
if (activeTemp != null) {
tempBasal.setVisibility(View.GONE);
tempBasalCancel.setVisibility(View.VISIBLE);
@ -192,12 +213,89 @@ public class ActionsFragment extends SubscriberFragment implements View.OnClickL
else
tempTarget.setVisibility(View.VISIBLE);
if (!ConfigBuilderPlugin.getPlugin().getActivePump().getPumpDescription().supportsTDDs) tddStats.setVisibility(View.GONE);
else tddStats.setVisibility(View.VISIBLE);
if (!ConfigBuilderPlugin.getPlugin().getActivePump().getPumpDescription().supportsTDDs)
tddStats.setVisibility(View.GONE);
else
tddStats.setVisibility(View.VISIBLE);
checkCustomActions();
}
});
}
private String activePumpName;
private Map<String, CustomAction> currentCustomActions = new HashMap<>();
private List<SingleClickButton> customButtons = new ArrayList<>();
View.OnClickListener customActionsListener = v -> {
SingleClickButton btn = (SingleClickButton)v;
CustomAction customAction = this.currentCustomActions.get(btn.getText().toString());
ConfigBuilderPlugin.getPlugin().getActivePump().executeCustomAction(customAction.getCustomActionType());
};
private void checkCustomActions() {
PumpInterface activePump = ConfigBuilderPlugin.getPlugin().getActivePump();
removeCustomActions();
if (activePump == null) {
return;
}
// add new actions
List<CustomAction> customActions = activePump.getCustomActions();
if (customActions != null) {
LinearLayout ll = actionsFragmentView.findViewById(R.id.action_buttons_layout);
for (CustomAction customAction : customActions) {
SingleClickButton btn = new SingleClickButton(getContext(), null, android.R.attr.buttonStyle);
btn.setText(MainApp.gs(customAction.getName()));
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT, 0.5f);
layoutParams.setMargins(20, 8, 20, 8); // 10,3,10,3
btn.setLayoutParams(layoutParams);
btn.setOnClickListener(customActionsListener);
Drawable top = getResources().getDrawable(R.drawable.icon_actions_profileswitch);
btn.setCompoundDrawablesWithIntrinsicBounds(null, top, null, null);
ll.addView(btn);
this.currentCustomActions.put(MainApp.gs(customAction.getName()), customAction);
this.customButtons.add(btn);
}
}
}
private void removeCustomActions() {
if (currentCustomActions.size() == 0)
return;
LinearLayout ll = actionsFragmentView.findViewById(R.id.action_buttons_layout);
for (SingleClickButton customButton : customButtons) {
ll.removeView(customButton);
}
customButtons.clear();
currentCustomActions.clear();
}
@Override
public void onClick(View view) {

View file

@ -0,0 +1,48 @@
package info.nightscout.androidaps.plugins.Actions.defs;
/**
* Created by andy on 9/20/18.
*/
public class CustomAction {
private int name;
private String iconName;
private CustomActionType customActionType;
public CustomAction(int nameResourceId, CustomActionType actionType) {
this.name = nameResourceId;
this.customActionType = actionType;
}
public int getName() {
return name;
}
public String getIconName() {
return iconName;
}
public void setIconName(String iconName) {
this.iconName = iconName;
}
public CustomActionType getCustomActionType() {
return customActionType;
}
public void setCustomActionType(CustomActionType customActionType) {
this.customActionType = customActionType;
}
}

View file

@ -0,0 +1,11 @@
package info.nightscout.androidaps.plugins.Actions.defs;
/**
* Created by andy on 9/20/18.
*/
public interface CustomActionType {
String getKey();
}

View file

@ -42,71 +42,32 @@ import info.nightscout.utils.DecimalFormatter;
// When using this class, make sure that your first step is to create mConnection (see MedtronicPumpPlugin)
// FIXME remove PumpDriver instances, just keep methods that do something here
public abstract class PumpPluginAbstract extends PluginBase implements PumpInterface, ConstraintsInterface {
private static final Logger LOG = LoggerFactory.getLogger(PumpPluginAbstract.class);
protected static final PumpEnactResult OPERATION_NOT_SUPPORTED = new PumpEnactResult().success(false)
.enacted(false).comment(MainApp.gs(R.string.pump_operation_not_supported_by_pump_driver));
protected static final PumpEnactResult OPERATION_NOT_YET_SUPPORTED = new PumpEnactResult().success(false)
.enacted(false).comment(MainApp.gs(R.string.pump_operation_not_yet_supported_by_pump));
// protected PumpStatus pumpStatusData;
private static final Logger LOG = LoggerFactory.getLogger(PumpPluginAbstract.class);
protected PumpDescription pumpDescription = new PumpDescription();
// protected PumpDriverInterface pumpDriver;
protected PumpStatus pumpStatus;
protected String internalName;
protected ServiceConnection serviceConnection = null;
protected boolean serviceRunning = false;
protected boolean isInitialized = false;
// protected boolean isInitialized = false;
protected PumpDriverState pumpState = PumpDriverState.NotInitialized;
protected boolean displayConnectionMessages = false;
// protected PumpPluginAbstract(PumpDriverInterface pumpDriverInterface, //
// String internalName, //
// String fragmentClassName, //
// int pluginName, //
// int pluginShortName, //
// PumpType pumpType) {
// this(pumpDriverInterface, //
// internalName, //
// new PluginDescription() //
// .mainType(PluginType.PUMP) //
// .fragmentClass(fragmentClassName) //
// .pluginName(pluginName) //
// .shortName(pluginShortName), //
// pumpType //
// );
// }
protected PumpPluginAbstract(PluginDescription pluginDescription, PumpType pumpType) {
super(pluginDescription);
LOG.error("After super called.");
// this.pumpDriver = pumpDriverInterface;
this.internalName = internalName;
LOG.error("Before Init Pump Statis Data called.");
pumpDescription.setPumpDescription(pumpType);
initPumpStatusData();
LOG.error("Before set description");
LOG.error("Before pumpDriver");
// this.pumpDriver.initDriver(this.pumpStatus, this.pumpDescription);
// initPumpStatusData();
}
protected String getInternalName() {
return this.internalName;
}
@ -165,7 +126,7 @@ public abstract class PumpPluginAbstract extends PluginBase implements PumpInter
public boolean isInitialized() {
return pumpState != PumpDriverState.NotInitialized;
return PumpDriverState.isInitialized(pumpState);
}
@ -195,26 +156,26 @@ public abstract class PumpPluginAbstract extends PluginBase implements PumpInter
public void connect(String reason) {
if (displayConnectionMessages)
LOG.warn("connect (reason={}) [PumpPluginAbstract] - Not implemented.", reason);
LOG.warn("connect (reason={}) [PumpPluginAbstract] - default (empty) implementation.", reason);
}
public void disconnect(String reason) {
if (displayConnectionMessages)
LOG.warn("disconnect (reason={}) [PumpPluginAbstract] - Not implemented.", reason);
LOG.warn("disconnect (reason={}) [PumpPluginAbstract] - default (empty) implementation.", reason);
}
public void stopConnecting() {
if (displayConnectionMessages)
LOG.warn("stopConnecting [PumpPluginAbstract] - Not implemented.");
LOG.warn("stopConnecting [PumpPluginAbstract] - default (empty) implementation.");
}
@Override
public boolean isHandshakeInProgress() {
if (displayConnectionMessages)
LOG.warn("isHandshakeInProgress [PumpPluginAbstract] - Not implemented.");
LOG.warn("isHandshakeInProgress [PumpPluginAbstract] - default (empty) implementation.");
return false;
}
@ -222,7 +183,7 @@ public abstract class PumpPluginAbstract extends PluginBase implements PumpInter
@Override
public void finishHandshaking() {
if (displayConnectionMessages)
LOG.warn("finishHandshaking [PumpPluginAbstract] - Not implemented.");
LOG.warn("finishHandshaking [PumpPluginAbstract] - default (empty) implementation.");
}

View file

@ -21,8 +21,8 @@ public enum PumpCapability {
ComboCapabilities(Bolus, TempBasal, BasalProfileSet, Refill, TDD, ManualTDDLoad), //
DanaCapabilities(Bolus, ExtendedBolus, TempBasal, BasalProfileSet, Refill, TDD, ManualTDDLoad), //
DanaWithHistoryCapabilities(Bolus, ExtendedBolus, TempBasal, BasalProfileSet, Refill, StoreCarbInfo, TDD, ManualTDDLoad), //
InsightCapabilities(Bolus, ExtendedBolus, TempBasal, BasalProfileSet, Refill,TDD,BasalRate30min), //
InsightCapabilities(Bolus, ExtendedBolus, TempBasal, BasalProfileSet, Refill, TDD), //
MedtronicCapabilities(Bolus, TempBasal, BasalProfileSet, Refill, TDD), //
// BasalRates (separately grouped)
BasalRate_Duration15minAllowed, //
@ -34,19 +34,16 @@ public enum PumpCapability {
PumpCapability[] children;
PumpCapability()
{
PumpCapability() {
}
PumpCapability(PumpCapability...children)
{
PumpCapability(PumpCapability... children) {
this.children = children;
}
public boolean hasCapability(PumpCapability capability)
{
public boolean hasCapability(PumpCapability capability) {
// we can only check presense of simple capabilities
if (capability.children != null)
return false;
@ -54,18 +51,15 @@ public enum PumpCapability {
if (this == capability)
return true;
if (this.children!=null) {
if (this.children != null) {
for (PumpCapability child : children) {
if (child == capability)
return true;
}
return false;
}
else
} else
return false;
}
}

View file

@ -8,12 +8,19 @@ public enum PumpDriverState {
NotInitialized, //
Connecting, //
Connected, //
Initialized, //
Ready,
Busy, //
Suspended, //
;
public static boolean isConnected(PumpDriverState pumpState) {
return pumpState == Connected || pumpState == Initialized || pumpState == Busy || pumpState == Suspended;
}
public static boolean isInitialized(PumpDriverState pumpState) {
return pumpState == Initialized || pumpState == Busy || pumpState == Suspended;
}
}

View file

@ -1,6 +1,5 @@
package info.nightscout.androidaps.plugins.PumpCommon.defs;
import java.util.HashMap;
import java.util.Map;
@ -8,8 +7,6 @@ import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.plugins.PumpCommon.data.DoseSettings;
/**
* Created by andy on 02/05/2018.
*
@ -19,107 +16,102 @@ import info.nightscout.androidaps.plugins.PumpCommon.data.DoseSettings;
public enum PumpType {
GenericAAPS("Generic AAPS", 0.1d, null, //
new DoseSettings(0.05d, 30, 8*60, 0.05d), //
PumpTempBasalType.Percent, //
new DoseSettings(10,30, 24*60, 0d, 500d), PumpCapability.BasalRate_Duration15and30minAllowed, //
0.01d, 0.01d, null, PumpCapability.VirtualPumpCapabilities), //
new DoseSettings(0.05d, 30, 8 * 60, 0.05d), //
PumpTempBasalType.Percent, //
new DoseSettings(10, 30, 24 * 60, 0d, 500d), PumpCapability.BasalRate_Duration15and30minAllowed, //
0.01d, 0.01d, null, PumpCapability.VirtualPumpCapabilities), //
// Cellnovo
Cellnovo1("Cellnovo", 0.05d, null, //
new DoseSettings(0.05d, 30, 24*60, 1d, null),
PumpTempBasalType.Percent,
new DoseSettings(5,30, 24*60, 0d, 200d), PumpCapability.BasalRate_Duration30minAllowed, //
0.05d, 0.05d, null, PumpCapability.VirtualPumpCapabilities), //
new DoseSettings(0.05d, 30, 24 * 60, 1d, null), //
PumpTempBasalType.Percent, //
new DoseSettings(5, 30, 24 * 60, 0d, 200d), PumpCapability.BasalRate_Duration30minAllowed, //
0.05d, 0.05d, null, PumpCapability.VirtualPumpCapabilities), //
// Accu-Chek
AccuChekCombo("Accu-Chek Combo", 0.1d, null, //
new DoseSettings(0.1d, 15, 12*60, 0.1d), //
PumpTempBasalType.Percent,
new DoseSettings(10, 15, 12*60,0d, 500d), PumpCapability.BasalRate_Duration15and30minAllowed, //
0.01d, 0.01d, DoseStepSize.ComboBasal, PumpCapability.ComboCapabilities), //
new DoseSettings(0.1d, 15, 12 * 60, 0.1d), //
PumpTempBasalType.Percent, new DoseSettings(10, 15, 12 * 60, 0d, 500d), PumpCapability.BasalRate_Duration15and30minAllowed, //
0.01d, 0.01d, DoseStepSize.ComboBasal, PumpCapability.ComboCapabilities), //
AccuChekSpirit("Accu-Chek Spirit", 0.1d, null, //
new DoseSettings(0.1d, 15, 12*60, 0.1d), //
PumpTempBasalType.Percent,
new DoseSettings(10, 15, 12*60,0d, 500d), PumpCapability.BasalRate_Duration15and30minAllowed, //
0.01d, 0.1d, null, PumpCapability.VirtualPumpCapabilities), //
new DoseSettings(0.1d, 15, 12 * 60, 0.1d), //
PumpTempBasalType.Percent, new DoseSettings(10, 15, 12 * 60, 0d, 500d), PumpCapability.BasalRate_Duration15and30minAllowed, //
0.01d, 0.1d, null, PumpCapability.VirtualPumpCapabilities), //
AccuChekInsight("Accu-Chek Insight", 0.05d, DoseStepSize.InsightBolus, //
new DoseSettings(0.05d, 15, 24*60, 0.05d), //
PumpTempBasalType.Percent,
new DoseSettings(10, 15, 12*60,0d, 250d), PumpCapability.BasalRate_Duration15and30minAllowed, //
0.02d, 0.01d, null, PumpCapability.InsightCapabilities), //
new DoseSettings(0.05d, 15, 24 * 60, 0.05d), //
PumpTempBasalType.Percent, new DoseSettings(10, 15, 12 * 60, 0d, 250d), PumpCapability.BasalRate_Duration15and30minAllowed, //
0.02d, 0.01d, null, PumpCapability.InsightCapabilities), //
// Animas
AnimasVibe("Animas Vibe", 0.05d, null, // AnimasBolus?
new DoseSettings(0.05d, 30, 12*60, 0.05d), //
PumpTempBasalType.Percent, //
new DoseSettings(10, 30, 24*60, 0d, 300d), PumpCapability.BasalRate_Duration30minAllowed, //
0.025d, 5d, 0d, null, PumpCapability.VirtualPumpCapabilities), //
new DoseSettings(0.05d, 30, 12 * 60, 0.05d), //
PumpTempBasalType.Percent, //
new DoseSettings(10, 30, 24 * 60, 0d, 300d), PumpCapability.BasalRate_Duration30minAllowed, //
0.025d, 5d, 0d, null, PumpCapability.VirtualPumpCapabilities), //
AnimasPing("Animas Ping", AnimasVibe),
// Dana
DanaR("DanaR", 0.05d, null, //
new DoseSettings(0.05d, 30, 8*60, 0.05d), //
PumpTempBasalType.Percent, //
new DoseSettings(10d, 60, 24*60, 0d, 200d), PumpCapability.BasalRate_Duration15and30minNotAllowed, //
0.04d, 0.01d, null, PumpCapability.DanaCapabilities),
new DoseSettings(0.05d, 30, 8 * 60, 0.05d), //
PumpTempBasalType.Percent, //
new DoseSettings(10d, 60, 24 * 60, 0d, 200d), PumpCapability.BasalRate_Duration15and30minNotAllowed, //
0.04d, 0.01d, null, PumpCapability.DanaCapabilities),
DanaRKorean("DanaR Korean", 0.05d, null, //
new DoseSettings(0.05d, 30, 8*60, 0.05d), //
PumpTempBasalType.Percent, //
new DoseSettings(10d, 60, 24*60, 0d, 200d), PumpCapability.BasalRate_Duration15and30minNotAllowed, //
0.1d, 0.01d, null, PumpCapability.DanaCapabilities),
new DoseSettings(0.05d, 30, 8 * 60, 0.05d), //
PumpTempBasalType.Percent, //
new DoseSettings(10d, 60, 24 * 60, 0d, 200d), PumpCapability.BasalRate_Duration15and30minNotAllowed, //
0.1d, 0.01d, null, PumpCapability.DanaCapabilities),
DanaRS("DanaRS", 0.05d, null, //
new DoseSettings(0.05d, 30, 8*60, 0.05d), //
PumpTempBasalType.Percent, //
new DoseSettings(10d, 60, 24*60, 0d, 200d), PumpCapability.BasalRate_Duration15and30minAllowed, //
0.04d, 0.01d, null, PumpCapability.DanaWithHistoryCapabilities),
new DoseSettings(0.05d, 30, 8 * 60, 0.05d), //
PumpTempBasalType.Percent, //
new DoseSettings(10d, 60, 24 * 60, 0d, 200d), PumpCapability.BasalRate_Duration15and30minAllowed, //
0.04d, 0.01d, null, PumpCapability.DanaWithHistoryCapabilities),
DanaRv2("DanaRv2", DanaRS),
// Insulet
Insulet_Omnipod("Insulet Omnipod", 0.05d, null, //
new DoseSettings(0.05d, 30, 8*60, 0.05d), //
PumpTempBasalType.Absolute, //
new DoseSettings(0.05d, 30, 12*60, 0d, 30.0d), PumpCapability.BasalRate_Duration30minAllowed, // cannot exceed max basal rate 30u/hr
0.05d, 0.05d, null, PumpCapability.VirtualPumpCapabilities),
new DoseSettings(0.05d, 30, 8 * 60, 0.05d), //
PumpTempBasalType.Absolute, //
new DoseSettings(0.05d, 30, 12 * 60, 0d, 30.0d), PumpCapability.BasalRate_Duration30minAllowed, // cannot exceed max
// basal rate 30u/hr
0.05d, 0.05d, null, PumpCapability.VirtualPumpCapabilities),
// Medtronic
Medtronic_512_712("Medtronic 512/712", 0.05d, null, //
new DoseSettings(0.05d, 30, 8*60, 0.05d), //
PumpTempBasalType.Absolute, //
new DoseSettings(0.05d, 30, 24*60, 0d, 35d), PumpCapability.BasalRate_Duration30minAllowed, //
0.05d, 0.05d, null, PumpCapability.VirtualPumpCapabilities), // TODO
new DoseSettings(0.05d, 30, 8 * 60, 0.05d), //
PumpTempBasalType.Absolute, //
new DoseSettings(0.05d, 30, 24 * 60, 0d, 35d), PumpCapability.BasalRate_Duration30minAllowed, //
0.05d, 0.05d, null, PumpCapability.MedtronicCapabilities),
Medtronic_515_715("Medtronic 515/715", Medtronic_512_712),
Medtronic_522_722("Medtronic 522/722", Medtronic_512_712),
Medtronic_523_723_Revel("Medtronic 523/723 (Revel)", 0.05d, null, //
new DoseSettings(0.05d, 30, 8*60, 0.05d), //
PumpTempBasalType.Absolute, //
new DoseSettings(0.05d, 30, 24*60, 0d, 35d), PumpCapability.BasalRate_Duration30minAllowed, //
0.025d, 0.025d, DoseStepSize.MedtronicVeoBasal, PumpCapability.VirtualPumpCapabilities), //
Medtronic_523_723_Revel("Medtronic 523/723 (Revel)", //
0.05d, null, new DoseSettings(0.05d, 30, 8 * 60, 0.05d), //
PumpTempBasalType.Absolute, //
new DoseSettings(0.05d, 30, 24 * 60, 0d, 35d), PumpCapability.BasalRate_Duration30minAllowed, //
0.025d, 0.025d, DoseStepSize.MedtronicVeoBasal, PumpCapability.MedtronicCapabilities), //
Medtronic_554_754_Veo("Medtronic 554/754 (Veo)", Medtronic_523_723_Revel), // TODO
Medtronic_554_754_Veo("Medtronic 554/754 (Veo)", Medtronic_523_723_Revel), //
Medtronic_640G("Medtronic 640G", 0.025d, null, //
new DoseSettings(0.05d, 30, 8*60, 0.05d), //
PumpTempBasalType.Absolute, //
new DoseSettings(0.05d, 30, 24*60, 0d, 35d), PumpCapability.BasalRate_Duration30minAllowed, //
0.025d, 0.025d, DoseStepSize.MedtronicVeoBasal, PumpCapability.VirtualPumpCapabilities), //
new DoseSettings(0.05d, 30, 8 * 60, 0.05d), //
PumpTempBasalType.Absolute, //
new DoseSettings(0.05d, 30, 24 * 60, 0d, 35d), PumpCapability.BasalRate_Duration30minAllowed, //
0.025d, 0.025d, DoseStepSize.MedtronicVeoBasal, PumpCapability.VirtualPumpCapabilities), //
// Tandem
TandemTSlim("Tandem t:slim", 0.01d, null, //
new DoseSettings(0.01d,15, 8*60, 0.4d),
PumpTempBasalType.Percent,
new DoseSettings(1,15, 8*60, 0d, 250d), PumpCapability.BasalRate_Duration15and30minAllowed, //
0.1d, 0.001d, null, PumpCapability.VirtualPumpCapabilities),
new DoseSettings(0.01d, 15, 8 * 60, 0.4d), PumpTempBasalType.Percent, new DoseSettings(1, 15, 8 * 60, 0d, 250d), PumpCapability.BasalRate_Duration15and30minAllowed, //
0.1d, 0.001d, null, PumpCapability.VirtualPumpCapabilities),
TandemTFlex("Tandem t:flex", TandemTSlim), //
TandemTSlimG4("Tandem t:slim G4", TandemTSlim), //
@ -140,10 +132,9 @@ public enum PumpType {
private PumpCapability pumpCapability;
private PumpType parent;
private static Map<String,PumpType> mapByDescription;
private static Map<String, PumpType> mapByDescription;
static
{
static {
mapByDescription = new HashMap<>();
for (PumpType pumpType : values()) {
@ -152,32 +143,38 @@ public enum PumpType {
}
PumpType(String description, PumpType parent)
{
PumpType(String description, PumpType parent) {
this.description = description;
this.parent = parent;
}
PumpType(String description, PumpType parent, PumpCapability pumpCapability)
{
PumpType(String description, PumpType parent, PumpCapability pumpCapability) {
this.description = description;
this.parent = parent;
this.pumpCapability = pumpCapability;
}
PumpType(String description, double bolusSize, DoseStepSize specialBolusSize, //
DoseSettings extendedBolusSettings, //
PumpTempBasalType pumpTempBasalType, DoseSettings tbrSettings, PumpCapability specialBasalDurations, //
double baseBasalMinValue, double baseBasalStep, DoseStepSize baseBasalSpecialSteps, PumpCapability pumpCapability)
{
this(description, bolusSize, specialBolusSize, extendedBolusSettings, pumpTempBasalType, tbrSettings, specialBasalDurations, baseBasalMinValue, null, baseBasalStep, baseBasalSpecialSteps, pumpCapability);
PumpType(String description, double bolusSize,
DoseStepSize specialBolusSize, //
DoseSettings extendedBolusSettings, //
PumpTempBasalType pumpTempBasalType, DoseSettings tbrSettings,
PumpCapability specialBasalDurations, //
double baseBasalMinValue, double baseBasalStep, DoseStepSize baseBasalSpecialSteps,
PumpCapability pumpCapability) {
this(description, bolusSize, specialBolusSize, extendedBolusSettings, pumpTempBasalType, tbrSettings,
specialBasalDurations, baseBasalMinValue, null, baseBasalStep, baseBasalSpecialSteps, pumpCapability);
}
PumpType(String description, double bolusSize, DoseStepSize specialBolusSize, //
DoseSettings extendedBolusSettings, //
PumpTempBasalType pumpTempBasalType, DoseSettings tbrSettings, PumpCapability specialBasalDurations, //
double baseBasalMinValue, Double baseBasalMaxValue, double baseBasalStep, DoseStepSize baseBasalSpecialSteps, PumpCapability pumpCapability)
{
PumpType(String description, double bolusSize,
DoseStepSize specialBolusSize, //
DoseSettings extendedBolusSettings, //
PumpTempBasalType pumpTempBasalType, DoseSettings tbrSettings,
PumpCapability specialBasalDurations, //
double baseBasalMinValue, Double baseBasalMaxValue, double baseBasalStep,
DoseStepSize baseBasalSpecialSteps, PumpCapability pumpCapability) {
this.description = description;
this.bolusSize = bolusSize;
this.specialBolusSize = specialBolusSize;
@ -206,6 +203,7 @@ public enum PumpType {
return this.pumpCapability;
}
public double getBolusSize() {
return isParentSet() ? parent.bolusSize : bolusSize;
}
@ -272,33 +270,33 @@ public enum PumpType {
public String getFullDescription(String i18nTemplate, boolean hasExtendedBasals) {
String unit = getPumpTempBasalType()==PumpTempBasalType.Percent ? "%" : "";
String unit = getPumpTempBasalType() == PumpTempBasalType.Percent ? "%" : "";
DoseSettings eb = getExtendedBolusSettings();
DoseSettings tbr = getTbrSettings();
String extendedNote = hasExtendedBasals ? MainApp.gs(R.string.virtualpump_pump_def_extended_note) : "";
return String.format(i18nTemplate, //
getStep("" + getBolusSize(), getSpecialBolusSize()), //
eb.getStep(), eb.getDurationStep(), eb.getMaxDuration()/60, //
getStep(getBaseBasalRange(), getBaseBasalSpecialSteps()), //
tbr.getMinDose() + unit + "-" + tbr.getMaxDose() + unit, tbr.getStep() + unit,
tbr.getDurationStep(), tbr.getMaxDuration()/60, extendedNote);
return String.format(
i18nTemplate, //
getStep("" + getBolusSize(), getSpecialBolusSize()), //
eb.getStep(), eb.getDurationStep(),
eb.getMaxDuration() / 60, //
getStep(getBaseBasalRange(), getBaseBasalSpecialSteps()), //
tbr.getMinDose() + unit + "-" + tbr.getMaxDose() + unit, tbr.getStep() + unit, tbr.getDurationStep(),
tbr.getMaxDuration() / 60, extendedNote);
}
private String getBaseBasalRange()
{
private String getBaseBasalRange() {
Double maxValue = getBaseBasalMaxValue();
return maxValue==null ? "" + getBaseBasalMinValue() : getBaseBasalMinValue() + "-" + maxValue;
return maxValue == null ? "" + getBaseBasalMinValue() : getBaseBasalMinValue() + "-" + maxValue;
}
private String getStep(String step, DoseStepSize stepSize)
{
if (stepSize!=null)
private String getStep(String step, DoseStepSize stepSize) {
if (stepSize != null)
return step + " [" + stepSize.getDescription() + "] *";
else
return "" + step;
@ -306,23 +304,22 @@ public enum PumpType {
public boolean hasExtendedBasals() {
return ((getBaseBasalSpecialSteps() !=null) || (getSpecialBolusSize() != null));
return ((getBaseBasalSpecialSteps() != null) || (getSpecialBolusSize() != null));
}
public PumpCapability getSpecialBasalDurations() {
if (isParentSet())
{
if (isParentSet()) {
return parent.getSpecialBasalDurations();
}
else
{
} else {
return specialBasalDurations == null ? //
PumpCapability.BasalRate_Duration15and30minNotAllowed : specialBasalDurations;
PumpCapability.BasalRate_Duration15and30minNotAllowed
: specialBasalDurations;
}
}
public double determineCorrectBolusSize(double bolusAmount) {
if (bolusAmount == 0.0d) {
return bolusAmount;
@ -377,7 +374,7 @@ public enum PumpType {
} else {
DoseStepSize specialBolusSize = getBaseBasalSpecialSteps();
basalStepSize = specialBolusSize.getStepSizeForAmount((double) basalAmount);
basalStepSize = specialBolusSize.getStepSizeForAmount((double)basalAmount);
}
if (basalAmount > getTbrSettings().getMaxDose())

View file

@ -15,8 +15,6 @@ import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.data.Radio
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.data.RadioResponse;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.defs.RLMessageType;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.defs.RileyLinkTargetFrequency;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.defs.RileyLinkError;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.defs.RileyLinkServiceState;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.service.RileyLinkServiceData;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.service.tasks.ServiceTaskExecutor;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.service.tasks.WakeAndTuneTask;
@ -35,6 +33,8 @@ public abstract class RileyLinkCommunicationManager {
private static final Logger LOG = LoggerFactory.getLogger(RileyLinkCommunicationManager.class);
private static final int SCAN_TIMEOUT = 1500;
private static final int ALLOWED_PUMP_UNREACHABLE = 10 * 60 * 1000; // 10 minutes
protected final RFSpy rfspy;
protected final Context context;
protected int receiverDeviceAwakeForMinutes = 1; // override this in constructor of specific implementation
@ -51,10 +51,10 @@ public abstract class RileyLinkCommunicationManager {
private int timeoutCount = 0;
public RileyLinkCommunicationManager(Context context, RFSpy rfspy, RileyLinkTargetFrequency targetFrequency) {
public RileyLinkCommunicationManager(Context context, RFSpy rfspy) {
this.context = context;
this.rfspy = rfspy;
this.targetFrequency = targetFrequency;
this.targetFrequency = RileyLinkUtil.getRileyLinkTargetFrequency();
this.scanFrequencies = targetFrequency.getScanFrequencies();
this.rileyLinkServiceData = RileyLinkUtil.getRileyLinkServiceData();
RileyLinkUtil.setRileyLinkCommunicationManager(this);
@ -66,6 +66,15 @@ public abstract class RileyLinkCommunicationManager {
protected abstract void configurePumpSpecificSettings();
public void refreshRileyLinkTargetFrequency() {
if (this.targetFrequency != RileyLinkUtil.getRileyLinkTargetFrequency()) {
this.targetFrequency = RileyLinkUtil.getRileyLinkTargetFrequency();
this.scanFrequencies = targetFrequency.getScanFrequencies();
}
}
// All pump communications go through this function.
protected <E extends RLMessage> E sendAndListen(RLMessage msg, int timeout_ms, Class<E> clazz) {
@ -87,11 +96,12 @@ public abstract class RileyLinkCommunicationManager {
if (rfSpyResponse.wasTimeout()) {
timeoutCount++;
if (timeoutCount >= 5) {
RileyLinkUtil.setServiceState(RileyLinkServiceState.PumpConnectorError,
RileyLinkError.NoContactWithDevice);
timeoutCount = 0;
long diff = System.currentTimeMillis() - pumpStatus.lastConnection;
if (diff > ALLOWED_PUMP_UNREACHABLE) {
LOG.warn("We reached max time that Pump can be unreachable. Starting Tuning.");
ServiceTaskExecutor.startTask(new WakeAndTuneTask());
timeoutCount = 0;
}
}
}
@ -117,6 +127,19 @@ public abstract class RileyLinkCommunicationManager {
}
public boolean changeTargetFrequency(RileyLinkTargetFrequency targetFrequency) {
if (this.targetFrequency == targetFrequency) {
return false;
}
this.targetFrequency = targetFrequency;
this.scanFrequencies = targetFrequency.getScanFrequencies();
return true;
}
// FIXME change wakeup
// TODO we might need to fix this. Maybe make pump awake for shorter time (battery factor for pump) - Andy
public void wakeUp(int duration_minutes, boolean force) {
@ -211,7 +234,7 @@ public abstract class RileyLinkCommunicationManager {
byte[] pumpMsgContent = createPumpMessageContent(RLMessageType.ReadSimpleData);
RFSpyResponse resp = rfspy.transmitThenReceive(new RadioPacket(pumpMsgContent), (byte)0, (byte)0,
(byte)0, (byte)0, 1000, (byte)0);
(byte)0, (byte)0, 1500, (byte)0);
if (resp.wasTimeout()) {
LOG.error("scanForPump: Failed to find pump at frequency {}", frequencies[i]);
} else if (resp.looksLikeRadioPacket()) {

View file

@ -184,7 +184,7 @@ public class RFSpy {
if (resp.looksLikeRadioPacket()) {
// RadioResponse radioResp = resp.getRadioResponse();
// byte[] responsePayload = radioResp.getPayload();
LOG.info("writeToData: received radio response. Will decode at upper level");
LOG.trace("writeToData: received radio response. Will decode at upper level");
resetNotConnectedCount();
}
// Log.i(TAG, "writeToData: raw response is " + ByteUtil.shortHexString(rawResponse));

View file

@ -17,7 +17,6 @@ import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.RileyLinkUtil;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.RFSpy;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.RileyLinkBLE;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.defs.RileyLinkEncodingType;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.defs.RileyLinkTargetFrequency;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.defs.RileyLinkError;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.defs.RileyLinkServiceState;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.defs.RileyLinkTargetDevice;
@ -41,9 +40,10 @@ public abstract class RileyLinkService extends Service {
protected Context context;
protected RileyLinkBroadcastReceiver mBroadcastReceiver;
protected RileyLinkServiceData rileyLinkServiceData;
protected RileyLinkTargetFrequency rileyLinkTargetFrequency;
// protected RileyLinkTargetFrequency rileyLinkTargetFrequency;
// protected static final String WAKELOCKNAME = "com.gxwtech.roundtrip2.RoundtripServiceWakeLock";
// protected static volatile PowerManager.WakeLock lockStatic = null;
// Our hardware/software connection
@ -57,7 +57,7 @@ public abstract class RileyLinkService extends Service {
RileyLinkUtil.setContext(this.context);
determineRileyLinkTargetFrequency();
RileyLinkUtil.setRileyLinkService(this);
RileyLinkUtil.setRileyLinkTargetFrequency(rileyLinkTargetFrequency);
// RileyLinkUtil.setRileyLinkTargetFrequency(rileyLinkTargetFrequency);
RileyLinkUtil.setEncoding(getEncoding());
initRileyLinkServiceData();
}

View file

@ -223,6 +223,11 @@ public class ByteUtil {
}
public static int toInt(int b1, int b2, int b3) {
return toInt(b1, b2, b3, null, BitConversion.BIG_ENDIAN);
}
public static int toInt(int b1, int b2, BitConversion flag) {
return toInt(b1, b2, null, null, flag);
}
@ -286,6 +291,14 @@ public class ByteUtil {
}
public static String getHex(List<Byte> list) {
byte[] abyte0 = getByteArrayFromList(list);
return abyte0 != null ? getHex(abyte0, abyte0.length) : null;
}
public static String getHex(byte abyte0[], int i) {
StringBuffer stringbuffer = new StringBuffer();
if (abyte0 != null) {

View file

@ -35,7 +35,7 @@ public class DateTimeUtil {
int second = (int)atechDateTime;
return new LocalDateTime(year, month, dayOfMonth, minute, second);
return new LocalDateTime(year, month, dayOfMonth, hourOfDay, minute, second);
}
@ -52,4 +52,56 @@ public class DateTimeUtil {
return atechDateTime;
}
public static boolean isSameDay(LocalDateTime ldt1, LocalDateTime ldt2) {
return (ldt1.getYear() == ldt2.getYear() && //
ldt1.getMonthOfYear() == ldt2.getMonthOfYear() && //
ldt1.getDayOfMonth() == ldt2.getDayOfMonth());
}
public static long toATechDate(int year, int month, int dayOfMonth, int hour, int minutes, int seconds) {
long atechDateTime = 0L;
atechDateTime += year * 10000000000L;
atechDateTime += month * 100000000L;
atechDateTime += dayOfMonth * 1000000L;
atechDateTime += hour * 10000L;
atechDateTime += minutes * 100L;
atechDateTime += seconds;
return atechDateTime;
}
public static String toString(long atechDateTime) {
int year = (int)(atechDateTime / 10000000000L);
atechDateTime -= year * 10000000000L;
int month = (int)(atechDateTime / 100000000L);
atechDateTime -= month * 100000000L;
int dayOfMonth = (int)(atechDateTime / 1000000L);
atechDateTime -= dayOfMonth * 1000000L;
int hourOfDay = (int)(atechDateTime / 10000L);
atechDateTime -= hourOfDay * 10000L;
int minute = (int)(atechDateTime / 100L);
atechDateTime -= minute * 100L;
int second = (int)atechDateTime;
return getZeroPrefixed(dayOfMonth) + "." + getZeroPrefixed(month) + "." + year + " " + //
getZeroPrefixed(hourOfDay) + ":" + getZeroPrefixed(minute) + ":" + getZeroPrefixed(second);
}
private static String getZeroPrefixed(int number) {
return (number < 10) ? "0" + number : "" + number;
}
}

View file

@ -95,4 +95,9 @@ public class StringUtil {
return val.toString();
}
public static void splitString(String s, int characters) {
}
}

View file

@ -1,13 +1,14 @@
package info.nightscout.androidaps.plugins.PumpDanaR;
import android.support.annotation.Nullable;
import java.util.Date;
import java.util.List;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Date;
import android.support.annotation.Nullable;
import info.nightscout.androidaps.BuildConfig;
import info.nightscout.androidaps.MainApp;
@ -27,6 +28,8 @@ import info.nightscout.androidaps.interfaces.ProfileInterface;
import info.nightscout.androidaps.interfaces.PumpDescription;
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.Actions.defs.CustomAction;
import info.nightscout.androidaps.plugins.Actions.defs.CustomActionType;
import info.nightscout.androidaps.plugins.Overview.events.EventDismissNotification;
import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.Overview.notifications.Notification;
@ -44,6 +47,7 @@ import info.nightscout.utils.SP;
*/
public abstract class AbstractDanaRPlugin extends PluginBase implements PumpInterface, DanaRInterface, ConstraintsInterface, ProfileInterface {
protected Logger log = LoggerFactory.getLogger(L.PUMP);
protected AbstractDanaRExecutionService sExecutionService;
@ -52,17 +56,14 @@ public abstract class AbstractDanaRPlugin extends PluginBase implements PumpInte
public PumpDescription pumpDescription = new PumpDescription();
protected AbstractDanaRPlugin() {
super(new PluginDescription()
.mainType(PluginType.PUMP)
.fragmentClass(DanaRFragment.class.getName())
.pluginName(R.string.danarspump)
.shortName(R.string.danarpump_shortname)
.preferencesId(R.xml.pref_danars)
.description(R.string.description_pump_dana_r)
);
super(new PluginDescription().mainType(PluginType.PUMP).fragmentClass(DanaRFragment.class.getName())
.pluginName(R.string.danarspump).shortName(R.string.danarpump_shortname).preferencesId(R.xml.pref_danars)
.description(R.string.description_pump_dana_r));
}
@Override
public void onStateChange(PluginType type, State oldState, State newState) {
// if pump profile was enabled need to switch to another too
@ -73,17 +74,21 @@ public abstract class AbstractDanaRPlugin extends PluginBase implements PumpInte
}
}
@Override
public boolean isSuspended() {
return DanaRPump.getInstance().pumpSuspended;
}
@Override
public boolean isBusy() {
if (sExecutionService == null) return false;
if (sExecutionService == null)
return false;
return sExecutionService.isConnected() || sExecutionService.isConnecting();
}
// Pump interface
@Override
public PumpEnactResult setNewBasalProfile(Profile profile) {
@ -96,7 +101,8 @@ public abstract class AbstractDanaRPlugin extends PluginBase implements PumpInte
}
if (!isInitialized()) {
log.error("setNewBasalProfile not initialized");
Notification notification = new Notification(Notification.PROFILE_NOT_SET_NOT_INITIALIZED, MainApp.gs(R.string.pumpNotInitializedProfileNotSet), Notification.URGENT);
Notification notification = new Notification(Notification.PROFILE_NOT_SET_NOT_INITIALIZED,
MainApp.gs(R.string.pumpNotInitializedProfileNotSet), Notification.URGENT);
MainApp.bus().post(new EventNewNotification(notification));
result.comment = MainApp.gs(R.string.pumpNotInitializedProfileNotSet);
return result;
@ -104,14 +110,16 @@ public abstract class AbstractDanaRPlugin extends PluginBase implements PumpInte
MainApp.bus().post(new EventDismissNotification(Notification.PROFILE_NOT_SET_NOT_INITIALIZED));
}
if (!sExecutionService.updateBasalsInPump(profile)) {
Notification notification = new Notification(Notification.FAILED_UDPATE_PROFILE, MainApp.gs(R.string.failedupdatebasalprofile), Notification.URGENT);
Notification notification = new Notification(Notification.FAILED_UDPATE_PROFILE,
MainApp.gs(R.string.failedupdatebasalprofile), Notification.URGENT);
MainApp.bus().post(new EventNewNotification(notification));
result.comment = MainApp.gs(R.string.failedupdatebasalprofile);
return result;
} else {
MainApp.bus().post(new EventDismissNotification(Notification.PROFILE_NOT_SET_NOT_INITIALIZED));
MainApp.bus().post(new EventDismissNotification(Notification.FAILED_UDPATE_PROFILE));
Notification notification = new Notification(Notification.PROFILE_SET_OK, MainApp.gs(R.string.profile_set_ok), Notification.INFO, 60);
Notification notification = new Notification(Notification.PROFILE_SET_OK,
MainApp.gs(R.string.profile_set_ok), Notification.INFO, 60);
MainApp.bus().post(new EventNewNotification(notification));
result.success = true;
result.enacted = true;
@ -120,6 +128,7 @@ public abstract class AbstractDanaRPlugin extends PluginBase implements PumpInte
}
}
@Override
public boolean isThisProfileSet(Profile profile) {
if (!isInitialized())
@ -132,7 +141,8 @@ public abstract class AbstractDanaRPlugin extends PluginBase implements PumpInte
for (int h = 0; h < basalValues; h++) {
Double pumpValue = pump.pumpProfiles[pump.activeProfile][h];
Double profileValue = profile.getBasalTimeFromMidnight(h * basalIncrement);
if (profileValue == null) return true;
if (profileValue == null)
return true;
if (Math.abs(pumpValue - profileValue) > getPumpDescription().basalStep) {
if (L.isEnabled(L.PUMP))
log.debug("Diff found. Hour: " + h + " Pump: " + pumpValue + " Profile: " + profileValue);
@ -142,16 +152,19 @@ public abstract class AbstractDanaRPlugin extends PluginBase implements PumpInte
return true;
}
@Override
public long lastDataTime() {
return DanaRPump.getInstance().lastConnection;
}
@Override
public double getBaseBasalRate() {
return DanaRPump.getInstance().currentBasal;
}
@Override
public void stopBolusDelivering() {
if (sExecutionService == null) {
@ -161,11 +174,14 @@ public abstract class AbstractDanaRPlugin extends PluginBase implements PumpInte
sExecutionService.bolusStop();
}
@Override
public PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes, Profile profile, boolean enforceNew) {
public PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes, Profile profile,
boolean enforceNew) {
DanaRPump pump = DanaRPump.getInstance();
PumpEnactResult result = new PumpEnactResult();
percent = MainApp.getConstraintChecker().applyBasalPercentConstraints(new Constraint<>(percent), profile).value();
percent = MainApp.getConstraintChecker().applyBasalPercentConstraints(new Constraint<>(percent), profile)
.value();
if (percent < 0) {
result.isTempCancel = false;
result.enacted = false;
@ -211,6 +227,7 @@ public abstract class AbstractDanaRPlugin extends PluginBase implements PumpInte
return result;
}
@Override
public PumpEnactResult setExtendedBolus(Double insulin, Integer durationInMinutes) {
DanaRPump pump = DanaRPump.getInstance();
@ -230,11 +247,13 @@ public abstract class AbstractDanaRPlugin extends PluginBase implements PumpInte
result.isPercent = false;
result.isTempCancel = false;
if (L.isEnabled(L.PUMP))
log.debug("setExtendedBolus: Correct extended bolus already set. Current: " + pump.extendedBolusAmount + " Asked: " + insulin);
log.debug("setExtendedBolus: Correct extended bolus already set. Current: " + pump.extendedBolusAmount
+ " Asked: " + insulin);
return result;
}
boolean connectionOK = sExecutionService.extendedBolus(insulin, durationInHalfHours);
if (connectionOK && pump.isExtendedInProgress && Math.abs(pump.extendedBolusAmount - insulin) < getPumpDescription().extendedBolusStep) {
if (connectionOK && pump.isExtendedInProgress
&& Math.abs(pump.extendedBolusAmount - insulin) < getPumpDescription().extendedBolusStep) {
result.enacted = true;
result.success = true;
result.comment = MainApp.gs(R.string.virtualpump_resultok);
@ -255,6 +274,7 @@ public abstract class AbstractDanaRPlugin extends PluginBase implements PumpInte
return result;
}
@Override
public PumpEnactResult cancelExtendedBolus() {
PumpEnactResult result = new PumpEnactResult();
@ -278,6 +298,7 @@ public abstract class AbstractDanaRPlugin extends PluginBase implements PumpInte
}
}
@Override
public void connect(String from) {
if (sExecutionService != null) {
@ -287,26 +308,33 @@ public abstract class AbstractDanaRPlugin extends PluginBase implements PumpInte
}
}
@Override
public boolean isConnected() {
return sExecutionService != null && sExecutionService.isConnected();
}
@Override
public boolean isConnecting() {
return sExecutionService != null && sExecutionService.isConnecting();
}
@Override
public void disconnect(String from) {
if (sExecutionService != null) sExecutionService.disconnect(from);
if (sExecutionService != null)
sExecutionService.disconnect(from);
}
@Override
public void stopConnecting() {
if (sExecutionService != null) sExecutionService.stopConnecting();
if (sExecutionService != null)
sExecutionService.stopConnecting();
}
@Override
public void getPumpStatus() {
if (sExecutionService != null) {
@ -316,6 +344,7 @@ public abstract class AbstractDanaRPlugin extends PluginBase implements PumpInte
}
}
@Override
public JSONObject getJSONStatus(Profile profile, String profilename) {
DanaRPump pump = DanaRPump.getInstance();
@ -358,7 +387,7 @@ public abstract class AbstractDanaRPlugin extends PluginBase implements PumpInte
pumpjson.put("battery", battery);
pumpjson.put("status", status);
pumpjson.put("extended", extended);
pumpjson.put("reservoir", (int) pump.reservoirRemainingUnits);
pumpjson.put("reservoir", (int)pump.reservoirRemainingUnits);
pumpjson.put("clock", DateUtil.toISOString(new Date()));
} catch (JSONException e) {
log.error("Unhandled exception", e);
@ -366,16 +395,19 @@ public abstract class AbstractDanaRPlugin extends PluginBase implements PumpInte
return pumpjson;
}
@Override
public String deviceID() {
return DanaRPump.getInstance().serialNumber;
}
@Override
public PumpDescription getPumpDescription() {
return pumpDescription;
}
/**
* DanaR interface
*/
@ -385,35 +417,51 @@ public abstract class AbstractDanaRPlugin extends PluginBase implements PumpInte
return sExecutionService.loadHistory(type);
}
/**
* Constraint interface
*/
@Override
public Constraint<Double> applyBasalConstraints(Constraint<Double> absoluteRate, Profile profile) {
absoluteRate.setIfSmaller(DanaRPump.getInstance().maxBasal, String.format(MainApp.gs(R.string.limitingbasalratio), DanaRPump.getInstance().maxBasal, MainApp.gs(R.string.pumplimit)), this);
absoluteRate.setIfSmaller(
DanaRPump.getInstance().maxBasal,
String.format(MainApp.gs(R.string.limitingbasalratio), DanaRPump.getInstance().maxBasal,
MainApp.gs(R.string.pumplimit)), this);
return absoluteRate;
}
@Override
public Constraint<Integer> applyBasalPercentConstraints(Constraint<Integer> percentRate, Profile profile) {
percentRate.setIfGreater(0, String.format(MainApp.gs(R.string.limitingpercentrate), 0, MainApp.gs(R.string.itmustbepositivevalue)), this);
percentRate.setIfSmaller(getPumpDescription().maxTempPercent, String.format(MainApp.gs(R.string.limitingpercentrate), getPumpDescription().maxTempPercent, MainApp.gs(R.string.pumplimit)), this);
percentRate.setIfGreater(0,
String.format(MainApp.gs(R.string.limitingpercentrate), 0, MainApp.gs(R.string.itmustbepositivevalue)),
this);
percentRate.setIfSmaller(
getPumpDescription().maxTempPercent,
String.format(MainApp.gs(R.string.limitingpercentrate), getPumpDescription().maxTempPercent,
MainApp.gs(R.string.pumplimit)), this);
return percentRate;
}
@Override
public Constraint<Double> applyBolusConstraints(Constraint<Double> insulin) {
insulin.setIfSmaller(DanaRPump.getInstance().maxBolus, String.format(MainApp.gs(R.string.limitingbolus), DanaRPump.getInstance().maxBolus, MainApp.gs(R.string.pumplimit)), this);
insulin.setIfSmaller(
DanaRPump.getInstance().maxBolus,
String.format(MainApp.gs(R.string.limitingbolus), DanaRPump.getInstance().maxBolus,
MainApp.gs(R.string.pumplimit)), this);
return insulin;
}
@Override
public Constraint<Double> applyExtendedBolusConstraints(Constraint<Double> insulin) {
return applyBolusConstraints(insulin);
}
@Nullable
@Override
public ProfileStore getProfile() {
@ -422,49 +470,69 @@ public abstract class AbstractDanaRPlugin extends PluginBase implements PumpInte
return DanaRPump.getInstance().createConvertedProfile();
}
@Override
public String getUnits() {
return DanaRPump.getInstance().getUnits();
}
@Override
public String getProfileName() {
return DanaRPump.getInstance().createConvertedProfileName();
}
@Override
public PumpEnactResult loadTDDs() {
return loadHistory(RecordTypes.RECORD_TYPE_DAILY);
}
// Reply for sms communicator
public String shortStatus(boolean veryShort) {
DanaRPump pump = DanaRPump.getInstance();
String ret = "";
if (pump.lastConnection != 0) {
Long agoMsec = System.currentTimeMillis() - pump.lastConnection;
int agoMin = (int) (agoMsec / 60d / 1000d);
int agoMin = (int)(agoMsec / 60d / 1000d);
ret += "LastConn: " + agoMin + " minago\n";
}
if (pump.lastBolusTime != 0) {
ret += "LastBolus: " + DecimalFormatter.to2Decimal(pump.lastBolusAmount) + "U @" + android.text.format.DateFormat.format("HH:mm", pump.lastBolusTime) + "\n";
ret += "LastBolus: " + DecimalFormatter.to2Decimal(pump.lastBolusAmount) + "U @"
+ android.text.format.DateFormat.format("HH:mm", pump.lastBolusTime) + "\n";
}
TemporaryBasal activeTemp = TreatmentsPlugin.getPlugin().getRealTempBasalFromHistory(System.currentTimeMillis());
TemporaryBasal activeTemp = TreatmentsPlugin.getPlugin()
.getRealTempBasalFromHistory(System.currentTimeMillis());
if (activeTemp != null) {
ret += "Temp: " + activeTemp.toStringFull() + "\n";
}
ExtendedBolus activeExtendedBolus = TreatmentsPlugin.getPlugin().getExtendedBolusFromHistory(System.currentTimeMillis());
ExtendedBolus activeExtendedBolus = TreatmentsPlugin.getPlugin().getExtendedBolusFromHistory(
System.currentTimeMillis());
if (activeExtendedBolus != null) {
ret += "Extended: " + activeExtendedBolus.toString() + "\n";
}
if (!veryShort) {
ret += "TDD: " + DecimalFormatter.to0Decimal(pump.dailyTotalUnits) + " / " + pump.maxDailyTotalUnits + " U\n";
ret += "TDD: " + DecimalFormatter.to0Decimal(pump.dailyTotalUnits) + " / " + pump.maxDailyTotalUnits
+ " U\n";
}
ret += "IOB: " + pump.iob + "U\n";
ret += "Reserv: " + DecimalFormatter.to0Decimal(pump.reservoirRemainingUnits) + "U\n";
ret += "Batt: " + pump.batteryRemaining + "\n";
return ret;
}
// TODO: daily total constraint
@Override
public List<CustomAction> getCustomActions() {
return null;
}
@Override
public PumpEnactResult executeCustomAction(CustomActionType customActionType) {
return null;
}
}

View file

@ -1,5 +1,12 @@
package info.nightscout.androidaps.plugins.PumpDanaRS;
import java.util.List;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@ -11,11 +18,6 @@ import android.support.v7.app.AlertDialog;
import com.squareup.otto.Subscribe;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.BuildConfig;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
@ -36,6 +38,8 @@ import info.nightscout.androidaps.interfaces.ProfileInterface;
import info.nightscout.androidaps.interfaces.PumpDescription;
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.Actions.defs.CustomAction;
import info.nightscout.androidaps.plugins.Actions.defs.CustomActionType;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderFragment;
import info.nightscout.androidaps.plugins.ConfigBuilder.DetailedBolusInfoStorage;
import info.nightscout.androidaps.plugins.ConfigBuilder.ProfileFunctions;
@ -63,9 +67,11 @@ import info.nightscout.utils.T;
*/
public class DanaRSPlugin extends PluginBase implements PumpInterface, DanaRInterface, ConstraintsInterface, ProfileInterface {
private Logger log = LoggerFactory.getLogger(L.PUMP);
private static DanaRSPlugin plugin = null;
public static DanaRSPlugin getPlugin() {
if (plugin == null)
plugin = new DanaRSPlugin();
@ -79,19 +85,16 @@ public class DanaRSPlugin extends PluginBase implements PumpInterface, DanaRInte
public static PumpDescription pumpDescription = new PumpDescription();
private DanaRSPlugin() {
super(new PluginDescription()
.mainType(PluginType.PUMP)
.fragmentClass(DanaRFragment.class.getName())
.pluginName(R.string.danarspump)
.shortName(R.string.danarspump_shortname)
.preferencesId(R.xml.pref_danars)
.description(R.string.description_pump_dana_rs)
);
super(new PluginDescription().mainType(PluginType.PUMP).fragmentClass(DanaRFragment.class.getName())
.pluginName(R.string.danarspump).shortName(R.string.danarspump_shortname).preferencesId(R.xml.pref_danars)
.description(R.string.description_pump_dana_rs));
pumpDescription.setPumpDescription(PumpType.DanaRS);
}
@Override
public void onStateChange(PluginType type, State oldState, State newState) {
// if pump profile was enabled need to switch to another too
@ -102,6 +105,7 @@ public class DanaRSPlugin extends PluginBase implements PumpInterface, DanaRInte
}
}
@Override
protected void onStart() {
Context context = MainApp.instance().getApplicationContext();
@ -113,6 +117,7 @@ public class DanaRSPlugin extends PluginBase implements PumpInterface, DanaRInte
super.onStart();
}
@Override
protected void onStop() {
Context context = MainApp.instance().getApplicationContext();
@ -121,25 +126,25 @@ public class DanaRSPlugin extends PluginBase implements PumpInterface, DanaRInte
MainApp.bus().unregister(this);
}
@Override
public void switchAllowed(ConfigBuilderFragment.PluginViewHolder.PluginSwitcher pluginSwitcher, FragmentActivity context) {
public void switchAllowed(ConfigBuilderFragment.PluginViewHolder.PluginSwitcher pluginSwitcher,
FragmentActivity context) {
boolean allowHardwarePump = SP.getBoolean("allow_hardware_pump", false);
if (allowHardwarePump || context == null) {
pluginSwitcher.invoke();
} else {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setMessage(R.string.allow_hardware_pump_text)
.setPositiveButton(R.string.yes, (dialog, id) -> {
pluginSwitcher.invoke();
SP.putBoolean("allow_hardware_pump", true);
if (L.isEnabled(L.PUMP))
log.debug("First time HW pump allowed!");
})
.setNegativeButton(R.string.cancel, (dialog, id) -> {
pluginSwitcher.cancel();
if (L.isEnabled(L.PUMP))
log.debug("User does not allow switching to HW pump!");
});
builder.setMessage(R.string.allow_hardware_pump_text).setPositiveButton(R.string.yes, (dialog, id) -> {
pluginSwitcher.invoke();
SP.putBoolean("allow_hardware_pump", true);
if (L.isEnabled(L.PUMP))
log.debug("First time HW pump allowed!");
}).setNegativeButton(R.string.cancel, (dialog, id) -> {
pluginSwitcher.cancel();
if (L.isEnabled(L.PUMP))
log.debug("User does not allow switching to HW pump!");
});
builder.create().show();
}
}
@ -152,26 +157,30 @@ public class DanaRSPlugin extends PluginBase implements PumpInterface, DanaRInte
danaRSService = null;
}
public void onServiceConnected(ComponentName name, IBinder service) {
if (L.isEnabled(L.PUMP))
log.debug("Service is connected");
DanaRSService.LocalBinder mLocalBinder = (DanaRSService.LocalBinder) service;
DanaRSService.LocalBinder mLocalBinder = (DanaRSService.LocalBinder)service;
danaRSService = mLocalBinder.getServiceInstance();
}
};
@SuppressWarnings("UnusedParameters")
@Subscribe
public void onStatusEvent(final EventAppExit e) {
MainApp.instance().getApplicationContext().unbindService(mConnection);
}
@Subscribe
public void onStatusEvent(final EventDanaRSDeviceChange e) {
mDeviceAddress = SP.getString(R.string.key_danars_address, "");
mDeviceName = SP.getString(R.string.key_danars_name, "");
}
@Override
public void connect(String from) {
if (L.isEnabled(L.PUMP))
@ -183,37 +192,46 @@ public class DanaRSPlugin extends PluginBase implements PumpInterface, DanaRInte
}
}
@Override
public boolean isConnected() {
return danaRSService != null && danaRSService.isConnected();
}
@Override
public boolean isConnecting() {
return danaRSService != null && danaRSService.isConnecting();
}
@Override
public boolean isHandshakeInProgress() {
return false;
}
@Override
public void finishHandshaking() {
}
@Override
public void disconnect(String from) {
if (L.isEnabled(L.PUMP))
log.debug("RS disconnect from: " + from);
if (danaRSService != null) danaRSService.disconnect(from);
if (danaRSService != null)
danaRSService.disconnect(from);
}
@Override
public void stopConnecting() {
if (danaRSService != null) danaRSService.stopConnecting();
if (danaRSService != null)
danaRSService.stopConnecting();
}
@Override
public void getPumpStatus() {
if (danaRSService != null) {
@ -223,6 +241,7 @@ public class DanaRSPlugin extends PluginBase implements PumpInterface, DanaRInte
}
}
// DanaR interface
@Override
@ -230,28 +249,40 @@ public class DanaRSPlugin extends PluginBase implements PumpInterface, DanaRInte
return danaRSService.loadHistory(type);
}
@Override
public PumpEnactResult loadEvents() {
return danaRSService.loadEvents();
}
@Override
public PumpEnactResult setUserOptions() {
return danaRSService.setUserSettings();
}
// Constraints interface
@Override
public Constraint<Double> applyBasalConstraints(Constraint<Double> absoluteRate, Profile profile) {
absoluteRate.setIfSmaller(DanaRPump.getInstance().maxBasal, String.format(MainApp.gs(R.string.limitingbasalratio), DanaRPump.getInstance().maxBasal, MainApp.gs(R.string.pumplimit)), this);
absoluteRate.setIfSmaller(
DanaRPump.getInstance().maxBasal,
String.format(MainApp.gs(R.string.limitingbasalratio), DanaRPump.getInstance().maxBasal,
MainApp.gs(R.string.pumplimit)), this);
return absoluteRate;
}
@Override
public Constraint<Integer> applyBasalPercentConstraints(Constraint<Integer> percentRate, Profile profile) {
percentRate.setIfGreater(0, String.format(MainApp.gs(R.string.limitingpercentrate), 0, MainApp.gs(R.string.itmustbepositivevalue)), this);
percentRate.setIfSmaller(getPumpDescription().maxTempPercent, String.format(MainApp.gs(R.string.limitingpercentrate), getPumpDescription().maxTempPercent, MainApp.gs(R.string.pumplimit)), this);
percentRate.setIfGreater(0,
String.format(MainApp.gs(R.string.limitingpercentrate), 0, MainApp.gs(R.string.itmustbepositivevalue)),
this);
percentRate.setIfSmaller(
getPumpDescription().maxTempPercent,
String.format(MainApp.gs(R.string.limitingpercentrate), getPumpDescription().maxTempPercent,
MainApp.gs(R.string.pumplimit)), this);
return percentRate;
}
@ -259,15 +290,20 @@ public class DanaRSPlugin extends PluginBase implements PumpInterface, DanaRInte
@Override
public Constraint<Double> applyBolusConstraints(Constraint<Double> insulin) {
insulin.setIfSmaller(DanaRPump.getInstance().maxBolus, String.format(MainApp.gs(R.string.limitingbolus), DanaRPump.getInstance().maxBolus, MainApp.gs(R.string.pumplimit)), this);
insulin.setIfSmaller(
DanaRPump.getInstance().maxBolus,
String.format(MainApp.gs(R.string.limitingbolus), DanaRPump.getInstance().maxBolus,
MainApp.gs(R.string.pumplimit)), this);
return insulin;
}
@Override
public Constraint<Double> applyExtendedBolusConstraints(Constraint<Double> insulin) {
return applyBolusConstraints(insulin);
}
// Profile interface
@Nullable
@ -278,16 +314,19 @@ public class DanaRSPlugin extends PluginBase implements PumpInterface, DanaRInte
return DanaRPump.getInstance().createConvertedProfile();
}
@Override
public String getUnits() {
return DanaRPump.getInstance().getUnits();
}
@Override
public String getProfileName() {
return DanaRPump.getInstance().createConvertedProfileName();
}
// Pump interface
@Override
@ -295,17 +334,21 @@ public class DanaRSPlugin extends PluginBase implements PumpInterface, DanaRInte
return DanaRPump.getInstance().lastConnection > 0 && DanaRPump.getInstance().maxBasal > 0;
}
@Override
public boolean isSuspended() {
return DanaRPump.getInstance().pumpSuspended;
}
@Override
public boolean isBusy() {
if (danaRSService == null) return false;
if (danaRSService == null)
return false;
return danaRSService.isConnected() || danaRSService.isConnecting();
}
@Override
public PumpEnactResult setNewBasalProfile(Profile profile) {
PumpEnactResult result = new PumpEnactResult();
@ -317,7 +360,8 @@ public class DanaRSPlugin extends PluginBase implements PumpInterface, DanaRInte
}
if (!isInitialized()) {
log.error("setNewBasalProfile not initialized");
Notification notification = new Notification(Notification.PROFILE_NOT_SET_NOT_INITIALIZED, MainApp.gs(R.string.pumpNotInitializedProfileNotSet), Notification.URGENT);
Notification notification = new Notification(Notification.PROFILE_NOT_SET_NOT_INITIALIZED,
MainApp.gs(R.string.pumpNotInitializedProfileNotSet), Notification.URGENT);
MainApp.bus().post(new EventNewNotification(notification));
result.comment = MainApp.gs(R.string.pumpNotInitializedProfileNotSet);
return result;
@ -325,14 +369,16 @@ public class DanaRSPlugin extends PluginBase implements PumpInterface, DanaRInte
MainApp.bus().post(new EventDismissNotification(Notification.PROFILE_NOT_SET_NOT_INITIALIZED));
}
if (!danaRSService.updateBasalsInPump(profile)) {
Notification notification = new Notification(Notification.FAILED_UDPATE_PROFILE, MainApp.gs(R.string.failedupdatebasalprofile), Notification.URGENT);
Notification notification = new Notification(Notification.FAILED_UDPATE_PROFILE,
MainApp.gs(R.string.failedupdatebasalprofile), Notification.URGENT);
MainApp.bus().post(new EventNewNotification(notification));
result.comment = MainApp.gs(R.string.failedupdatebasalprofile);
return result;
} else {
MainApp.bus().post(new EventDismissNotification(Notification.PROFILE_NOT_SET_NOT_INITIALIZED));
MainApp.bus().post(new EventDismissNotification(Notification.FAILED_UDPATE_PROFILE));
Notification notification = new Notification(Notification.PROFILE_SET_OK, MainApp.gs(R.string.profile_set_ok), Notification.INFO, 60);
Notification notification = new Notification(Notification.PROFILE_SET_OK,
MainApp.gs(R.string.profile_set_ok), Notification.INFO, 60);
MainApp.bus().post(new EventNewNotification(notification));
result.success = true;
result.enacted = true;
@ -341,6 +387,7 @@ public class DanaRSPlugin extends PluginBase implements PumpInterface, DanaRInte
}
}
@Override
public boolean isThisProfileSet(Profile profile) {
if (!isInitialized())
@ -352,8 +399,9 @@ public class DanaRSPlugin extends PluginBase implements PumpInterface, DanaRInte
int basalIncrement = pump.basal48Enable ? 30 * 60 : 60 * 60;
for (int h = 0; h < basalValues; h++) {
Double pumpValue = pump.pumpProfiles[pump.activeProfile][h];
Double profileValue = profile.getBasalTimeFromMidnight((Integer) (h * basalIncrement));
if (profileValue == null) return true;
Double profileValue = profile.getBasalTimeFromMidnight((Integer)(h * basalIncrement));
if (profileValue == null)
return true;
if (Math.abs(pumpValue - profileValue) > getPumpDescription().basalStep) {
if (L.isEnabled(L.PUMP))
log.debug("Diff found. Hour: " + h + " Pump: " + pumpValue + " Profile: " + profileValue);
@ -363,19 +411,23 @@ public class DanaRSPlugin extends PluginBase implements PumpInterface, DanaRInte
return true;
}
@Override
public long lastDataTime() {
return DanaRPump.getInstance().lastConnection;
}
@Override
public double getBaseBasalRate() {
return DanaRPump.getInstance().currentBasal;
}
@Override
public synchronized PumpEnactResult deliverTreatment(DetailedBolusInfo detailedBolusInfo) {
detailedBolusInfo.insulin = MainApp.getConstraintChecker().applyBolusConstraints(new Constraint<>(detailedBolusInfo.insulin)).value();
detailedBolusInfo.insulin = MainApp.getConstraintChecker()
.applyBolusConstraints(new Constraint<>(detailedBolusInfo.insulin)).value();
if (detailedBolusInfo.insulin > 0 || detailedBolusInfo.carbs > 0) {
int preferencesSpeed = SP.getInt(R.string.key_danars_bolusspeed, 0);
int speed = 12;
@ -392,13 +444,14 @@ public class DanaRSPlugin extends PluginBase implements PumpInterface, DanaRInte
}
// RS stores end time for bolus, we need to adjust time
// default delivery speed is 12 sec/U
detailedBolusInfo.date = DateUtil.now() + (long) (speed * detailedBolusInfo.insulin * 1000);
detailedBolusInfo.date = DateUtil.now() + (long)(speed * detailedBolusInfo.insulin * 1000);
// clean carbs to prevent counting them as twice because they will picked up as another record
// I don't think it's necessary to copy DetailedBolusInfo right now for carbs records
double carbs = detailedBolusInfo.carbs;
detailedBolusInfo.carbs = 0;
int carbTime = detailedBolusInfo.carbTime;
if (carbTime == 0) carbTime--; // better set 1 min back to prevents clash with insulin
if (carbTime == 0)
carbTime--; // better set 1 min back to prevents clash with insulin
detailedBolusInfo.carbTime = 0;
DetailedBolusInfoStorage.add(detailedBolusInfo); // will be picked up on reading history
@ -407,15 +460,17 @@ public class DanaRSPlugin extends PluginBase implements PumpInterface, DanaRInte
t.isSMB = detailedBolusInfo.isSMB;
boolean connectionOK = false;
if (detailedBolusInfo.insulin > 0 || carbs > 0)
connectionOK = danaRSService.bolus(detailedBolusInfo.insulin, (int) carbs, DateUtil.now() + T.mins(carbTime).msecs(), t);
connectionOK = danaRSService.bolus(detailedBolusInfo.insulin, (int)carbs,
DateUtil.now() + T.mins(carbTime).msecs(), t);
PumpEnactResult result = new PumpEnactResult();
result.success = connectionOK && Math.abs(detailedBolusInfo.insulin - t.insulin) < pumpDescription.bolusStep;
result.success = connectionOK
&& Math.abs(detailedBolusInfo.insulin - t.insulin) < pumpDescription.bolusStep;
result.bolusDelivered = t.insulin;
result.carbsDelivered = detailedBolusInfo.carbs;
if (!result.success) {
String error = "" + DanaRS_Packet_Bolus_Set_Step_Bolus_Start.errorCode;
switch (DanaRS_Packet_Bolus_Set_Step_Bolus_Start.errorCode) {
// 4 reported as max bolus violation. Check later
// 4 reported as max bolus violation. Check later
case 0x10:
error = MainApp.gs(R.string.maxbolusviolation);
break;
@ -429,11 +484,13 @@ public class DanaRSPlugin extends PluginBase implements PumpInterface, DanaRInte
error = MainApp.gs(R.string.insulinlimitviolation);
break;
}
result.comment = String.format(MainApp.gs(R.string.boluserrorcode), detailedBolusInfo.insulin, t.insulin, error);
result.comment = String.format(MainApp.gs(R.string.boluserrorcode), detailedBolusInfo.insulin,
t.insulin, error);
} else
result.comment = MainApp.gs(R.string.virtualpump_resultok);
if (L.isEnabled(L.PUMP))
log.debug("deliverTreatment: OK. Asked: " + detailedBolusInfo.insulin + " Delivered: " + result.bolusDelivered);
log.debug("deliverTreatment: OK. Asked: " + detailedBolusInfo.insulin + " Delivered: "
+ result.bolusDelivered);
return result;
} else {
PumpEnactResult result = new PumpEnactResult();
@ -446,6 +503,7 @@ public class DanaRSPlugin extends PluginBase implements PumpInterface, DanaRInte
}
}
@Override
public void stopBolusDelivering() {
if (danaRSService == null) {
@ -455,19 +513,22 @@ public class DanaRSPlugin extends PluginBase implements PumpInterface, DanaRInte
danaRSService.bolusStop();
}
// This is called from APS
@Override
public synchronized PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes, Profile profile, boolean enforceNew) {
public synchronized PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes,
Profile profile, boolean enforceNew) {
// Recheck pump status if older than 30 min
//This should not be needed while using queue because connection should be done before calling this
//if (pump.lastConnection.getTime() + 30 * 60 * 1000L < System.currentTimeMillis()) {
// connect("setTempBasalAbsolute old data");
//}
// This should not be needed while using queue because connection should be done before calling this
// if (pump.lastConnection.getTime() + 30 * 60 * 1000L < System.currentTimeMillis()) {
// connect("setTempBasalAbsolute old data");
// }
PumpEnactResult result = new PumpEnactResult();
absoluteRate = MainApp.getConstraintChecker().applyBasalConstraints(new Constraint<>(absoluteRate), profile).value();
absoluteRate = MainApp.getConstraintChecker().applyBasalConstraints(new Constraint<>(absoluteRate), profile)
.value();
final boolean doTempOff = getBaseBasalRate() - absoluteRate == 0d;
final boolean doLowTemp = absoluteRate < getBaseBasalRate();
@ -492,12 +553,15 @@ public class DanaRSPlugin extends PluginBase implements PumpInterface, DanaRInte
if (doLowTemp || doHighTemp) {
Integer percentRate = Double.valueOf(absoluteRate / getBaseBasalRate() * 100).intValue();
if (percentRate < 100) percentRate = Round.ceilTo((double) percentRate, 10d).intValue();
else percentRate = Round.floorTo((double) percentRate, 10d).intValue();
if (percentRate < 100)
percentRate = Round.ceilTo((double)percentRate, 10d).intValue();
else
percentRate = Round.floorTo((double)percentRate, 10d).intValue();
if (percentRate > 500) // Special high temp 500/15min
percentRate = 500;
// Check if some temp is already in progress
TemporaryBasal activeTemp = TreatmentsPlugin.getPlugin().getTempBasalFromHistory(System.currentTimeMillis());
TemporaryBasal activeTemp = TreatmentsPlugin.getPlugin()
.getTempBasalFromHistory(System.currentTimeMillis());
if (activeTemp != null) {
if (L.isEnabled(L.PUMP))
log.debug("setTempBasalAbsolute: currently running: " + activeTemp.toString());
@ -518,7 +582,8 @@ public class DanaRSPlugin extends PluginBase implements PumpInterface, DanaRInte
}
// Convert duration from minutes to hours
if (L.isEnabled(L.PUMP))
log.debug("setTempBasalAbsolute: Setting temp basal " + percentRate + "% for " + durationInMinutes + " mins (doLowTemp || doHighTemp)");
log.debug("setTempBasalAbsolute: Setting temp basal " + percentRate + "% for " + durationInMinutes
+ " mins (doLowTemp || doHighTemp)");
if (percentRate == 0 && durationInMinutes > 30) {
result = setTempBasalPercent(percentRate, durationInMinutes, profile, false);
} else {
@ -540,11 +605,14 @@ public class DanaRSPlugin extends PluginBase implements PumpInterface, DanaRInte
return result;
}
@Override
public synchronized PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes, Profile profile, boolean enforceNew) {
public synchronized PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes,
Profile profile, boolean enforceNew) {
DanaRPump pump = DanaRPump.getInstance();
PumpEnactResult result = new PumpEnactResult();
percent = MainApp.getConstraintChecker().applyBasalPercentConstraints(new Constraint<>(percent), profile).value();
percent = MainApp.getConstraintChecker().applyBasalPercentConstraints(new Constraint<>(percent), profile)
.value();
if (percent < 0) {
result.isTempCancel = false;
result.enacted = false;
@ -595,6 +663,7 @@ public class DanaRSPlugin extends PluginBase implements PumpInterface, DanaRInte
return result;
}
private synchronized PumpEnactResult setHighTempBasalPercent(Integer percent) {
DanaRPump pump = DanaRPump.getInstance();
PumpEnactResult result = new PumpEnactResult();
@ -618,6 +687,7 @@ public class DanaRSPlugin extends PluginBase implements PumpInterface, DanaRInte
return result;
}
@Override
public synchronized PumpEnactResult setExtendedBolus(Double insulin, Integer durationInMinutes) {
DanaRPump pump = DanaRPump.getInstance();
@ -636,11 +706,13 @@ public class DanaRSPlugin extends PluginBase implements PumpInterface, DanaRInte
result.isPercent = false;
result.isTempCancel = false;
if (L.isEnabled(L.PUMP))
log.debug("setExtendedBolus: Correct extended bolus already set. Current: " + pump.extendedBolusAmount + " Asked: " + insulin);
log.debug("setExtendedBolus: Correct extended bolus already set. Current: " + pump.extendedBolusAmount
+ " Asked: " + insulin);
return result;
}
boolean connectionOK = danaRSService.extendedBolus(insulin, durationInHalfHours);
if (connectionOK && pump.isExtendedInProgress && Math.abs(pump.extendedBolusAbsoluteRate - insulin) < getPumpDescription().extendedBolusStep) {
if (connectionOK && pump.isExtendedInProgress
&& Math.abs(pump.extendedBolusAbsoluteRate - insulin) < getPumpDescription().extendedBolusStep) {
result.enacted = true;
result.success = true;
result.comment = MainApp.gs(R.string.virtualpump_resultok);
@ -660,6 +732,7 @@ public class DanaRSPlugin extends PluginBase implements PumpInterface, DanaRInte
return result;
}
@Override
public synchronized PumpEnactResult cancelTempBasal(boolean force) {
PumpEnactResult result = new PumpEnactResult();
@ -685,6 +758,7 @@ public class DanaRSPlugin extends PluginBase implements PumpInterface, DanaRInte
}
}
@Override
public synchronized PumpEnactResult cancelExtendedBolus() {
PumpEnactResult result = new PumpEnactResult();
@ -708,6 +782,7 @@ public class DanaRSPlugin extends PluginBase implements PumpInterface, DanaRInte
}
}
@Override
public JSONObject getJSONStatus(Profile profile, String profileName) {
DanaRPump pump = DanaRPump.getInstance();
@ -750,7 +825,7 @@ public class DanaRSPlugin extends PluginBase implements PumpInterface, DanaRInte
pumpjson.put("battery", battery);
pumpjson.put("status", status);
pumpjson.put("extended", extended);
pumpjson.put("reservoir", (int) pump.reservoirRemainingUnits);
pumpjson.put("reservoir", (int)pump.reservoirRemainingUnits);
pumpjson.put("clock", DateUtil.toISOString(now));
} catch (JSONException e) {
log.error("Unhandled exception", e);
@ -758,38 +833,45 @@ public class DanaRSPlugin extends PluginBase implements PumpInterface, DanaRInte
return pumpjson;
}
@Override
public String deviceID() {
return DanaRPump.getInstance().serialNumber;
}
@Override
public PumpDescription getPumpDescription() {
return pumpDescription;
}
@Override
public String shortStatus(boolean veryShort) {
DanaRPump pump = DanaRPump.getInstance();
String ret = "";
if (pump.lastConnection != 0) {
Long agoMsec = System.currentTimeMillis() - pump.lastConnection;
int agoMin = (int) (agoMsec / 60d / 1000d);
int agoMin = (int)(agoMsec / 60d / 1000d);
ret += "LastConn: " + agoMin + " minago\n";
}
if (pump.lastBolusTime != 0) {
ret += "LastBolus: " + DecimalFormatter.to2Decimal(pump.lastBolusAmount) + "U @" + android.text.format.DateFormat.format("HH:mm", pump.lastBolusTime) + "\n";
ret += "LastBolus: " + DecimalFormatter.to2Decimal(pump.lastBolusAmount) + "U @"
+ android.text.format.DateFormat.format("HH:mm", pump.lastBolusTime) + "\n";
}
TemporaryBasal activeTemp = TreatmentsPlugin.getPlugin().getRealTempBasalFromHistory(System.currentTimeMillis());
TemporaryBasal activeTemp = TreatmentsPlugin.getPlugin()
.getRealTempBasalFromHistory(System.currentTimeMillis());
if (activeTemp != null) {
ret += "Temp: " + activeTemp.toStringFull() + "\n";
}
ExtendedBolus activeExtendedBolus = TreatmentsPlugin.getPlugin().getExtendedBolusFromHistory(System.currentTimeMillis());
ExtendedBolus activeExtendedBolus = TreatmentsPlugin.getPlugin().getExtendedBolusFromHistory(
System.currentTimeMillis());
if (activeExtendedBolus != null) {
ret += "Extended: " + activeExtendedBolus.toString() + "\n";
}
if (!veryShort) {
ret += "TDD: " + DecimalFormatter.to0Decimal(pump.dailyTotalUnits) + " / " + pump.maxDailyTotalUnits + " U\n";
ret += "TDD: " + DecimalFormatter.to0Decimal(pump.dailyTotalUnits) + " / " + pump.maxDailyTotalUnits
+ " U\n";
}
ret += "IOB: " + pump.iob + "U\n";
ret += "Reserv: " + DecimalFormatter.to0Decimal(pump.reservoirRemainingUnits) + "U\n";
@ -797,14 +879,27 @@ public class DanaRSPlugin extends PluginBase implements PumpInterface, DanaRInte
return ret;
}
@Override
public boolean isFakingTempsByExtendedBoluses() {
return false;
}
@Override
public PumpEnactResult loadTDDs() {
return loadHistory(RecordTypes.RECORD_TYPE_DAILY);
}
@Override
public List<CustomAction> getCustomActions() {
return null;
}
@Override
public PumpEnactResult executeCustomAction(CustomActionType customActionType) {
return null;
}
}

View file

@ -1,18 +1,35 @@
package info.nightscout.androidaps.plugins.PumpInsight;
import android.content.DialogInterface;
import android.os.SystemClock;
import android.support.v4.app.FragmentActivity;
import android.support.v7.app.AlertDialog;
import static info.nightscout.androidaps.plugins.PumpInsight.history.PumpIdCache.getRecordUniqueID;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import sugar.free.sightparser.applayer.descriptors.ActiveBolus;
import sugar.free.sightparser.applayer.descriptors.ActiveBolusType;
import sugar.free.sightparser.applayer.descriptors.MessagePriority;
import sugar.free.sightparser.applayer.descriptors.PumpStatus;
import sugar.free.sightparser.applayer.descriptors.configuration_blocks.BRProfileBlock;
import sugar.free.sightparser.applayer.messages.AppLayerMessage;
import sugar.free.sightparser.applayer.messages.remote_control.BolusMessage;
import sugar.free.sightparser.applayer.messages.remote_control.CancelBolusMessage;
import sugar.free.sightparser.applayer.messages.remote_control.ExtendedBolusMessage;
import sugar.free.sightparser.applayer.messages.remote_control.StandardBolusMessage;
import sugar.free.sightparser.applayer.messages.status.ActiveBolusesMessage;
import sugar.free.sightparser.handling.SingleMessageTaskRunner;
import sugar.free.sightparser.handling.TaskRunner;
import sugar.free.sightparser.pipeline.Status;
import android.content.DialogInterface;
import android.os.SystemClock;
import android.support.v4.app.FragmentActivity;
import android.support.v7.app.AlertDialog;
import info.nightscout.androidaps.BuildConfig;
import info.nightscout.androidaps.Config;
@ -32,6 +49,8 @@ import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.interfaces.PumpDescription;
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.Actions.defs.CustomAction;
import info.nightscout.androidaps.plugins.Actions.defs.CustomActionType;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderFragment;
import info.nightscout.androidaps.plugins.ConfigBuilder.ProfileFunctions;
import info.nightscout.androidaps.plugins.NSClientInternal.NSUpload;
@ -56,23 +75,6 @@ import info.nightscout.androidaps.plugins.Treatments.Treatment;
import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin;
import info.nightscout.utils.DateUtil;
import info.nightscout.utils.SP;
import sugar.free.sightparser.applayer.descriptors.ActiveBolus;
import sugar.free.sightparser.applayer.descriptors.ActiveBolusType;
import sugar.free.sightparser.applayer.descriptors.MessagePriority;
import sugar.free.sightparser.applayer.descriptors.PumpStatus;
import sugar.free.sightparser.applayer.descriptors.configuration_blocks.BRProfileBlock;
import sugar.free.sightparser.applayer.messages.AppLayerMessage;
import sugar.free.sightparser.applayer.messages.remote_control.BolusMessage;
import sugar.free.sightparser.applayer.messages.remote_control.CancelBolusMessage;
import sugar.free.sightparser.applayer.messages.remote_control.ExtendedBolusMessage;
import sugar.free.sightparser.applayer.messages.remote_control.StandardBolusMessage;
import sugar.free.sightparser.applayer.messages.status.ActiveBolusesMessage;
import sugar.free.sightparser.handling.SingleMessageTaskRunner;
import sugar.free.sightparser.handling.TaskRunner;
import sugar.free.sightparser.pipeline.Status;
import static info.nightscout.androidaps.plugins.PumpInsight.history.PumpIdCache.getRecordUniqueID;
/**
* Created by jamorham on 23/01/2018.
@ -86,10 +88,12 @@ import static info.nightscout.androidaps.plugins.PumpInsight.history.PumpIdCache
@SuppressWarnings("AccessStaticViaInstance")
public class InsightPlugin extends PluginBase implements PumpInterface, ConstraintsInterface {
private Logger log = LoggerFactory.getLogger(L.PUMP);
private static volatile InsightPlugin plugin;
public static InsightPlugin getPlugin() {
if (plugin == null) {
plugin = new InsightPlugin();
@ -112,15 +116,11 @@ public class InsightPlugin extends PluginBase implements PumpInterface, Constrai
private volatile boolean connector_enabled = false;
private List<BRProfileBlock.ProfileBlock> profileBlocks;
private InsightPlugin() {
super(new PluginDescription()
.mainType(PluginType.PUMP)
.fragmentClass(InsightFragment.class.getName())
.pluginName(R.string.insightpump)
.shortName(R.string.insightpump_shortname)
.preferencesId(R.xml.pref_insightpump)
.description(R.string.description_pump_insight)
);
super(new PluginDescription().mainType(PluginType.PUMP).fragmentClass(InsightFragment.class.getName())
.pluginName(R.string.insightpump).shortName(R.string.insightpump_shortname)
.preferencesId(R.xml.pref_insightpump).description(R.string.description_pump_insight));
if (L.isEnabled(L.PUMP))
log.debug("InsightPlugin instantiated");
pumpDescription.setPumpDescription(PumpType.AccuChekInsight);
@ -132,10 +132,12 @@ public class InsightPlugin extends PluginBase implements PumpInterface, Constrai
MainApp.bus().post(new EventInsightUpdateGui());
}
private static void pushCallbackEvent(EventInsightCallback e) {
MainApp.bus().post(e);
}
@Override
protected void onStart() {
if (!connector_enabled) {
@ -152,6 +154,7 @@ public class InsightPlugin extends PluginBase implements PumpInterface, Constrai
super.onStart();
}
protected void onStop() {
if (connector_enabled) {
synchronized (this) {
@ -165,11 +168,13 @@ public class InsightPlugin extends PluginBase implements PumpInterface, Constrai
}
}
@Override
public boolean isFakingTempsByExtendedBoluses() {
return true;
}
@Override
public PumpEnactResult loadTDDs() {
PumpEnactResult result = new PumpEnactResult();
@ -177,65 +182,76 @@ public class InsightPlugin extends PluginBase implements PumpInterface, Constrai
return result;
}
@Override
public void switchAllowed(ConfigBuilderFragment.PluginViewHolder.PluginSwitcher pluginSwitcher, FragmentActivity context) {
public void switchAllowed(ConfigBuilderFragment.PluginViewHolder.PluginSwitcher pluginSwitcher,
FragmentActivity context) {
boolean allowHardwarePump = SP.getBoolean("allow_hardware_pump", false);
if (allowHardwarePump || context == null) {
pluginSwitcher.invoke();
} else {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setMessage(R.string.allow_hardware_pump_text)
.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
pluginSwitcher.invoke();
SP.putBoolean("allow_hardware_pump", true);
log.debug("First time HW pump allowed!");
}
})
.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
pluginSwitcher.cancel();
log.debug("User does not allow switching to HW pump!");
}
});
.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
pluginSwitcher.invoke();
SP.putBoolean("allow_hardware_pump", true);
log.debug("First time HW pump allowed!");
}
}).setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
pluginSwitcher.cancel();
log.debug("User does not allow switching to HW pump!");
}
});
builder.create().show();
}
}
@Override
public boolean isInitialized() {
return initialized;
}
@Override
public boolean isSuspended() {
return !isPumpRunning();
}
@Override
public boolean isBusy() {
return false;
}
@Override
public boolean isConnected() {
return Connector.get().isPumpConnected();
}
@Override
public boolean isConnecting() {
return Connector.get().isPumpConnecting();
}
@Override
public boolean isHandshakeInProgress() {
return false;
}
@Override
public void finishHandshaking() {
}
@Override
public void connect(String reason) {
if (L.isEnabled(L.PUMP))
@ -260,6 +276,7 @@ public class InsightPlugin extends PluginBase implements PumpInterface, Constrai
NSUpload.uploadDeviceStatus();
}
@Override
public void disconnect(String reason) {
if (L.isEnabled(L.PUMP))
@ -278,6 +295,7 @@ public class InsightPlugin extends PluginBase implements PumpInterface, Constrai
}
}
@Override
public void stopConnecting() {
if (L.isEnabled(L.PUMP))
@ -301,6 +319,7 @@ public class InsightPlugin extends PluginBase implements PumpInterface, Constrai
}
}
@Override
public void getPumpStatus() {
if (L.isEnabled(L.PUMP))
@ -309,7 +328,8 @@ public class InsightPlugin extends PluginBase implements PumpInterface, Constrai
if (L.isEnabled(L.PUMP))
log.debug("is connected.. requesting status");
try {
setStatusResult(fetchTaskRunner(new StatusTaskRunner(connector.getServiceConnector()), StatusTaskRunner.Result.class));
setStatusResult(fetchTaskRunner(new StatusTaskRunner(connector.getServiceConnector()),
StatusTaskRunner.Result.class));
if (L.isEnabled(L.PUMP))
log.debug("GOT STATUS RESULT!!! PARTY WOOHOO!!!");
statusResultTime = Helpers.tsl();
@ -319,7 +339,8 @@ public class InsightPlugin extends PluginBase implements PumpInterface, Constrai
connector.requestHistorySync();
} catch (Exception e) {
log.error("StatusTaskRunner wasn't successful.");
if (connector.getServiceConnector().isConnectedToService() && connector.getServiceConnector().getStatus() != Status.CONNECTED) {
if (connector.getServiceConnector().isConnectedToService()
&& connector.getServiceConnector().getStatus() != Status.CONNECTED) {
if (Helpers.ratelimit("insight-reconnect", 2)) {
Connector.connectToPump();
updateGui();
@ -332,18 +353,21 @@ public class InsightPlugin extends PluginBase implements PumpInterface, Constrai
}
}
public void setStatusResult(StatusTaskRunner.Result result) {
this.statusResult = result;
this.pumpDescription.basalMinimumRate = result.minimumBasalAmount;
this.pumpDescription.basalMaximumRate = result.maximumBasalAmount;
}
@Override
public PumpEnactResult setNewBasalProfile(Profile profile) {
PumpEnactResult result = new PumpEnactResult();
if (!isInitialized()) {
log.error("setNewBasalProfile not initialized");
Notification notification = new Notification(Notification.PROFILE_NOT_SET_NOT_INITIALIZED, MainApp.gs(R.string.pumpNotInitializedProfileNotSet), Notification.URGENT);
Notification notification = new Notification(Notification.PROFILE_NOT_SET_NOT_INITIALIZED,
MainApp.gs(R.string.pumpNotInitializedProfileNotSet), Notification.URGENT);
MainApp.bus().post(new EventNewNotification(notification));
result.comment = MainApp.gs(R.string.pumpNotInitializedProfileNotSet);
return result;
@ -355,31 +379,41 @@ public class InsightPlugin extends PluginBase implements PumpInterface, Constrai
Profile.BasalValue nextValue = null;
if (profile.getBasalValues().length > i + 1)
nextValue = profile.getBasalValues()[i + 1];
profileBlocks.add(new BRProfileBlock.ProfileBlock((((nextValue != null ? nextValue.timeAsSeconds : 24 * 60 * 60) - basalValue.timeAsSeconds) / 60), Helpers.roundDouble(basalValue.value, 2)));
profileBlocks.add(new BRProfileBlock.ProfileBlock((((nextValue != null ? nextValue.timeAsSeconds
: 24 * 60 * 60) - basalValue.timeAsSeconds) / 60), Helpers.roundDouble(basalValue.value, 2)));
if (L.isEnabled(L.PUMP))
log.debug("setNewBasalProfile: " + basalValue.value + " for " + Integer.toString(((nextValue != null ? nextValue.timeAsSeconds : 24 * 60 * 60) - basalValue.timeAsSeconds) / 60));
log.debug("setNewBasalProfile: "
+ basalValue.value
+ " for "
+ Integer
.toString(((nextValue != null ? nextValue.timeAsSeconds : 24 * 60 * 60) - basalValue.timeAsSeconds) / 60));
}
try {
fetchTaskRunner(new WriteBasalProfileTaskRunner(connector.getServiceConnector(), profileBlocks));
MainApp.bus().post(new EventDismissNotification(Notification.FAILED_UDPATE_PROFILE));
Notification notification = new Notification(Notification.PROFILE_SET_OK, MainApp.gs(R.string.profile_set_ok), Notification.INFO, 60);
Notification notification = new Notification(Notification.PROFILE_SET_OK,
MainApp.gs(R.string.profile_set_ok), Notification.INFO, 60);
MainApp.bus().post(new EventNewNotification(notification));
result.success = true;
result.enacted = true;
result.comment = "OK";
this.profileBlocks = profileBlocks;
} catch (Exception e) {
Notification notification = new Notification(Notification.FAILED_UDPATE_PROFILE, MainApp.gs(R.string.failedupdatebasalprofile), Notification.URGENT);
Notification notification = new Notification(Notification.FAILED_UDPATE_PROFILE,
MainApp.gs(R.string.failedupdatebasalprofile), Notification.URGENT);
MainApp.bus().post(new EventNewNotification(notification));
result.comment = MainApp.gs(R.string.failedupdatebasalprofile);
}
return result;
}
@Override
public boolean isThisProfileSet(Profile profile) {
if (!isInitialized() || profileBlocks == null) return true;
if (profile.getBasalValues().length != profileBlocks.size()) return false;
if (!isInitialized() || profileBlocks == null)
return true;
if (profile.getBasalValues().length != profileBlocks.size())
return false;
for (int i = 0; i < profileBlocks.size(); i++) {
BRProfileBlock.ProfileBlock profileBlock = profileBlocks.get(i);
Profile.BasalValue basalValue = profile.getBasalValues()[i];
@ -387,32 +421,44 @@ public class InsightPlugin extends PluginBase implements PumpInterface, Constrai
if (profile.getBasalValues().length > i + 1)
nextValue = profile.getBasalValues()[i + 1];
if (L.isEnabled(L.PUMP))
log.debug("isThisProfileSet - Comparing block: Pump: " + profileBlock.getAmount() + " for " + profileBlock.getDuration()
+ " Profile: " + basalValue.value + " for " + Integer.toString(((nextValue != null ? nextValue.timeAsSeconds : 24 * 60 * 60) - basalValue.timeAsSeconds) / 60));
if (profileBlock.getDuration() * 60 != (nextValue != null ? nextValue.timeAsSeconds : 24 * 60 * 60) - basalValue.timeAsSeconds)
log.debug("isThisProfileSet - Comparing block: Pump: "
+ profileBlock.getAmount()
+ " for "
+ profileBlock.getDuration()
+ " Profile: "
+ basalValue.value
+ " for "
+ Integer
.toString(((nextValue != null ? nextValue.timeAsSeconds : 24 * 60 * 60) - basalValue.timeAsSeconds) / 60));
if (profileBlock.getDuration() * 60 != (nextValue != null ? nextValue.timeAsSeconds : 24 * 60 * 60)
- basalValue.timeAsSeconds)
return false;
//Allow a little imprecision due to rounding errors
// Allow a little imprecision due to rounding errors
if (Math.abs(profileBlock.getAmount() - Helpers.roundDouble(basalValue.value, 2)) >= 0.01D)
return false;
}
return true;
}
@Override
public long lastDataTime() {
return lastDataTime;
}
@Override
public double getBaseBasalRate() {
return basalRate;
}
public String getBaseBasalRateString() {
final DecimalFormat df = new DecimalFormat("#.##");
return df.format(basalRate);
}
@Override
public PumpEnactResult deliverTreatment(DetailedBolusInfo detailedBolusInfo) {
final PumpEnactResult result = new PumpEnactResult();
@ -457,39 +503,50 @@ public class InsightPlugin extends PluginBase implements PumpInterface, Constrai
}
if (L.isEnabled(L.PUMP))
log.debug("Delivering treatment insulin: " + detailedBolusInfo.insulin + "U carbs: " + detailedBolusInfo.carbs + "g " + result);
log.debug("Delivering treatment insulin: " + detailedBolusInfo.insulin + "U carbs: "
+ detailedBolusInfo.carbs + "g " + result);
updateGui();
connector.tryToGetPumpStatusAgain();
if (result.success) while (true) {
try {
Thread.sleep(500);
final EventOverviewBolusProgress bolusingEvent = EventOverviewBolusProgress.getInstance();
ActiveBolusesMessage activeBolusesMessage = fetchSingleMessage(new ActiveBolusesMessage(), ActiveBolusesMessage.class);
ActiveBolus activeBolus = null;
if (activeBolusesMessage.getBolus1() != null && activeBolusesMessage.getBolus1().getBolusID() == bolusingEvent.bolusId)
activeBolus = activeBolusesMessage.getBolus1();
else if (activeBolusesMessage.getBolus2() != null && activeBolusesMessage.getBolus2().getBolusID() == bolusingEvent.bolusId)
activeBolus = activeBolusesMessage.getBolus2();
else if (activeBolusesMessage.getBolus3() != null && activeBolusesMessage.getBolus3().getBolusID() == bolusingEvent.bolusId)
activeBolus = activeBolusesMessage.getBolus3();
if (activeBolus == null) break;
else {
int percentBefore = bolusingEvent.percent;
bolusingEvent.percent = (int) (100D / activeBolus.getInitialAmount() * (activeBolus.getInitialAmount() - activeBolus.getLeftoverAmount()));
bolusingEvent.status = String.format(MainApp.gs(R.string.bolusdelivering), activeBolus.getInitialAmount() - activeBolus.getLeftoverAmount());
if (percentBefore != bolusingEvent.percent) MainApp.bus().post(bolusingEvent);
if (result.success)
while (true) {
try {
Thread.sleep(500);
final EventOverviewBolusProgress bolusingEvent = EventOverviewBolusProgress.getInstance();
ActiveBolusesMessage activeBolusesMessage = fetchSingleMessage(new ActiveBolusesMessage(),
ActiveBolusesMessage.class);
ActiveBolus activeBolus = null;
if (activeBolusesMessage.getBolus1() != null
&& activeBolusesMessage.getBolus1().getBolusID() == bolusingEvent.bolusId)
activeBolus = activeBolusesMessage.getBolus1();
else if (activeBolusesMessage.getBolus2() != null
&& activeBolusesMessage.getBolus2().getBolusID() == bolusingEvent.bolusId)
activeBolus = activeBolusesMessage.getBolus2();
else if (activeBolusesMessage.getBolus3() != null
&& activeBolusesMessage.getBolus3().getBolusID() == bolusingEvent.bolusId)
activeBolus = activeBolusesMessage.getBolus3();
if (activeBolus == null)
break;
else {
int percentBefore = bolusingEvent.percent;
bolusingEvent.percent = (int)(100D / activeBolus.getInitialAmount() * (activeBolus
.getInitialAmount() - activeBolus.getLeftoverAmount()));
bolusingEvent.status = String.format(MainApp.gs(R.string.bolusdelivering),
activeBolus.getInitialAmount() - activeBolus.getLeftoverAmount());
if (percentBefore != bolusingEvent.percent)
MainApp.bus().post(bolusingEvent);
}
} catch (Exception e) {
break;
}
} catch (Exception e) {
break;
}
}
connector.requestHistorySync(2000);
return result;
}
@Override
public void stopBolusDelivering() {
CancelBolusMessage cancelBolusMessage = new CancelBolusMessage();
@ -501,10 +558,12 @@ public class InsightPlugin extends PluginBase implements PumpInterface, Constrai
}
}
// Temporary Basals
@Override
public PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes, Profile profile, boolean enforceNew) {
public PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes, Profile profile,
boolean enforceNew) {
if (L.isEnabled(L.PUMP))
log.debug("Set TBR absolute: " + absoluteRate);
if (getBaseBasalRate() == 0) {
@ -514,24 +573,27 @@ public class InsightPlugin extends PluginBase implements PumpInterface, Constrai
}
double percent = 100D / getBaseBasalRate() * absoluteRate;
if (L.isEnabled(L.PUMP))
log.debug("Calculated requested rate: " + absoluteRate + " base rate: " + getBaseBasalRate() + " percentage: " + percent + "%");
log.debug("Calculated requested rate: " + absoluteRate + " base rate: " + getBaseBasalRate()
+ " percentage: " + percent + "%");
try {
if (percent > 250) {
if (L.isEnabled(L.PUMP))
log.debug("Calculated rate is above 250%, switching to emulation using extended boluses");
cancelTempBasal(true);
if (!setExtendedBolus((absoluteRate - getBaseBasalRate()) / 60D * ((double) durationInMinutes), durationInMinutes).success) {
//Fallback to TBR if setting an extended bolus didn't work
if (!setExtendedBolus((absoluteRate - getBaseBasalRate()) / 60D * ((double)durationInMinutes),
durationInMinutes).success) {
// Fallback to TBR if setting an extended bolus didn't work
if (L.isEnabled(L.PUMP))
log.debug("Setting an extended bolus didn't work, falling back to normal TBR");
return setTempBasalPercent((int) percent, durationInMinutes, profile, true);
return setTempBasalPercent((int)percent, durationInMinutes, profile, true);
}
return new PumpEnactResult().success(true).enacted(true).absolute(absoluteRate).duration(durationInMinutes);
return new PumpEnactResult().success(true).enacted(true).absolute(absoluteRate)
.duration(durationInMinutes);
} else {
if (L.isEnabled(L.PUMP))
log.debug("Calculated rate is below or equal to 250%, using normal TBRs");
cancelExtendedBolus();
return setTempBasalPercent((int) percent, durationInMinutes, profile, true);
return setTempBasalPercent((int)percent, durationInMinutes, profile, true);
}
} catch (Exception e) {
return pumpEnactFailure();
@ -540,23 +602,22 @@ public class InsightPlugin extends PluginBase implements PumpInterface, Constrai
@Override
public PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes, Profile profile, boolean enforceNew) {
public PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes, Profile profile,
boolean enforceNew) {
if (L.isEnabled(L.PUMP))
log.debug("Set TBR %");
percent = (int) Math.round(((double) percent) / 10d) * 10;
percent = (int)Math.round(((double)percent) / 10d) * 10;
if (percent == 100) {
// This would cause a cancel if a tbr is in progress so treat as a cancel
return cancelTempBasal(false);
} else if (percent > 250) percent = 250;
} else if (percent > 250)
percent = 250;
try {
fetchTaskRunner(new SetTBRTaskRunner(connector.getServiceConnector(), percent, durationInMinutes));
final TemporaryBasal tempBasal = new TemporaryBasal()
.date(System.currentTimeMillis())
.percent(percent)
.duration(durationInMinutes)
.source(Source.USER);
final TemporaryBasal tempBasal = new TemporaryBasal().date(System.currentTimeMillis()).percent(percent)
.duration(durationInMinutes).source(Source.USER);
TreatmentsPlugin.getPlugin().addToHistoryTempBasal(tempBasal);
updateGui();
if (L.isEnabled(L.PUMP))
@ -589,8 +650,10 @@ public class InsightPlugin extends PluginBase implements PumpInterface, Constrai
}
}
private void realTBRCancel() throws Exception {
if (fetchTaskRunner(new CancelTBRSilentlyTaskRunner(connector.getServiceConnector()), Boolean.class) && TreatmentsPlugin.getPlugin().isTempBasalInProgress()) {
if (fetchTaskRunner(new CancelTBRSilentlyTaskRunner(connector.getServiceConnector()), Boolean.class)
&& TreatmentsPlugin.getPlugin().isTempBasalInProgress()) {
TemporaryBasal tempStop = new TemporaryBasal().date(System.currentTimeMillis()).source(Source.USER);
TreatmentsPlugin.getPlugin().addToHistoryTempBasal(tempStop);
}
@ -608,22 +671,21 @@ public class InsightPlugin extends PluginBase implements PumpInterface, Constrai
extendedBolusMessage.setAmount(insulin);
extendedBolusMessage.setDuration(durationInMinutes);
BolusMessage bolusMessage = fetchSingleMessage(extendedBolusMessage, BolusMessage.class);
final ExtendedBolus extendedBolus = new ExtendedBolus()
.date(System.currentTimeMillis())
.insulin(insulin)
.durationInMinutes(durationInMinutes)
.source(Source.USER)
.pumpId(getRecordUniqueID(bolusMessage.getBolusId()));
final ExtendedBolus extendedBolus = new ExtendedBolus().date(System.currentTimeMillis()).insulin(insulin)
.durationInMinutes(durationInMinutes).source(Source.USER)
.pumpId(getRecordUniqueID(bolusMessage.getBolusId()));
TreatmentsPlugin.getPlugin().addToHistoryExtendedBolus(extendedBolus);
updateGui();
connector.requestHistorySync(30000);
connector.tryToGetPumpStatusAgain();
return new PumpEnactResult().success(true).enacted(true).duration(durationInMinutes).bolusDelivered(insulin);
return new PumpEnactResult().success(true).enacted(true).duration(durationInMinutes)
.bolusDelivered(insulin);
} catch (Exception e) {
return pumpEnactFailure();
}
}
@Override
public PumpEnactResult cancelExtendedBolus() {
if (L.isEnabled(L.PUMP))
@ -632,13 +694,15 @@ public class InsightPlugin extends PluginBase implements PumpInterface, Constrai
Integer bolusId = null;
try {
bolusId = fetchTaskRunner(new CancelBolusSilentlyTaskRunner(connector.getServiceConnector(), ActiveBolusType.EXTENDED), Integer.class);
bolusId = fetchTaskRunner(new CancelBolusSilentlyTaskRunner(connector.getServiceConnector(),
ActiveBolusType.EXTENDED), Integer.class);
if (TreatmentsPlugin.getPlugin().isInHistoryExtendedBoluslInProgress()) {
ExtendedBolus exStop = new ExtendedBolus(System.currentTimeMillis());
exStop.source = Source.USER;
TreatmentsPlugin.getPlugin().addToHistoryExtendedBolus(exStop);
}
if (bolusId != null) connector.requestHistorySync(5000);
if (bolusId != null)
connector.requestHistorySync(5000);
connector.tryToGetPumpStatusAgain();
updateGui();
return new PumpEnactResult().success(true).enacted(bolusId != null);
@ -658,6 +722,7 @@ public class InsightPlugin extends PluginBase implements PumpInterface, Constrai
return fetchSingleMessage(message, BolusMessage.class).getBolusId();
}
@Override
public JSONObject getJSONStatus(Profile profile, String profileName) {
long now = System.currentTimeMillis();
@ -706,44 +771,53 @@ public class InsightPlugin extends PluginBase implements PumpInterface, Constrai
return pump;
}
@Override
public String deviceID() {
return "InsightPump";
}
@Override
public PumpDescription getPumpDescription() {
return pumpDescription;
}
@Override
public String shortStatus(boolean veryShort) {
String msg = gs(R.string.insightpump_shortname) + " Batt: " + batteryPercent + " Reserv: " + reservoirInUnits + " Basal: " + basalRate;
String msg = gs(R.string.insightpump_shortname) + " Batt: " + batteryPercent + " Reserv: " + reservoirInUnits
+ " Basal: " + basalRate;
if (LiveHistory.getStatus().length() > 0) {
msg += LiveHistory.getStatus();
}
return msg;
}
private void processStatusResult() {
if (statusResult != null) {
batteryPercent = statusResult.battery;
reservoirInUnits = (int) statusResult.cartridge;
reservoirInUnits = (int)statusResult.cartridge;
basalRate = statusResult.baseBasalRate;
profileBlocks = statusResult.basalProfile;
initialized = true; // basic communication test
}
}
private String gs(int id) {
return MainApp.gs(id);
}
private boolean isPumpRunning() {
if (statusResult == null) return true; // assume running if we have no information
if (statusResult == null)
return true; // assume running if we have no information
return statusResult.pumpStatus == PumpStatus.STARTED;
}
List<StatusItem> getStatusItems(boolean refresh) {
final List<StatusItem> l = new ArrayList<>();
@ -760,7 +834,8 @@ public class InsightPlugin extends PluginBase implements PumpInterface, Constrai
if (pumpRunning) {
l.add(new StatusItem(gs(R.string.pump_basebasalrate_label), getBaseBasalRateString() + "U"));
} else {
l.add(new StatusItem(gs(R.string.combo_warning), gs(R.string.pump_stopped_uppercase), StatusItem.Highlight.CRITICAL));
l.add(new StatusItem(gs(R.string.combo_warning), gs(R.string.pump_stopped_uppercase),
StatusItem.Highlight.CRITICAL));
}
}
@ -768,17 +843,17 @@ public class InsightPlugin extends PluginBase implements PumpInterface, Constrai
final long offset_minutes = offset_ms / 60000;
if (statusResult != null) {
l.add(new StatusItem(gs(R.string.status_updated), Helpers.niceTimeScalar(Helpers.msSince(statusResultTime)) + " " + gs(R.string.ago)));
l.add(new StatusItem(gs(R.string.pump_battery_label), batteryPercent + "%", batteryPercent < 100 ?
(batteryPercent < 90 ?
(batteryPercent < 70 ?
(StatusItem.Highlight.BAD) : StatusItem.Highlight.NOTICE) : StatusItem.Highlight.NORMAL) : StatusItem.Highlight.GOOD));
l.add(new StatusItem(gs(R.string.status_updated), Helpers.niceTimeScalar(Helpers.msSince(statusResultTime))
+ " " + gs(R.string.ago)));
l.add(new StatusItem(gs(R.string.pump_battery_label), batteryPercent + "%",
batteryPercent < 100 ? (batteryPercent < 90 ? (batteryPercent < 70 ? (StatusItem.Highlight.BAD)
: StatusItem.Highlight.NOTICE) : StatusItem.Highlight.NORMAL) : StatusItem.Highlight.GOOD));
l.add(new StatusItem(gs(R.string.pump_reservoir_label), reservoirInUnits + "U"));
try {
if (statusResult.tbrAmount != 100) {
l.add(new StatusItem(gs(R.string.insight_active_tbr), statusResult.tbrAmount + "% " + gs(R.string.with) + " "
+ Helpers.qs(statusResult.tbrLeftoverDuration - offset_minutes, 0)
+ " " + gs(R.string.insight_min_left), StatusItem.Highlight.NOTICE));
l.add(new StatusItem(gs(R.string.insight_active_tbr), statusResult.tbrAmount + "% "
+ gs(R.string.with) + " " + Helpers.qs(statusResult.tbrLeftoverDuration - offset_minutes, 0)
+ " " + gs(R.string.insight_min_left), StatusItem.Highlight.NOTICE));
}
} catch (NullPointerException e) {
// currentTBRMessage may be null
@ -788,7 +863,8 @@ public class InsightPlugin extends PluginBase implements PumpInterface, Constrai
if (TreatmentsPlugin.getPlugin().isTempBasalInProgress()) {
try {
l.add(new StatusItem(gs(R.string.pump_tempbasal_label), TreatmentsPlugin.getPlugin().getTempBasalFromHistory(System.currentTimeMillis()).toStringFull()));
l.add(new StatusItem(gs(R.string.pump_tempbasal_label), TreatmentsPlugin.getPlugin()
.getTempBasalFromHistory(System.currentTimeMillis()).toStringFull()));
} catch (NullPointerException e) {
//
}
@ -807,7 +883,8 @@ public class InsightPlugin extends PluginBase implements PumpInterface, Constrai
if (TreatmentsPlugin.getPlugin().isInHistoryExtendedBoluslInProgress()) {
try {
l.add(new StatusItem(gs(R.string.virtualpump_extendedbolus_label), TreatmentsPlugin.getPlugin().getExtendedBolusFromHistory(System.currentTimeMillis()).toString()));
l.add(new StatusItem(gs(R.string.virtualpump_extendedbolus_label), TreatmentsPlugin.getPlugin()
.getExtendedBolusFromHistory(System.currentTimeMillis()).toString()));
} catch (NullPointerException e) {
//
}
@ -833,15 +910,18 @@ public class InsightPlugin extends PluginBase implements PumpInterface, Constrai
connector.tryToGetPumpStatusAgain();
}
connector.requestHistorySync();
if (refresh) scheduleGUIUpdate();
if (refresh)
scheduleGUIUpdate();
return l;
}
private synchronized void scheduleGUIUpdate() {
if (!update_pending && connector.uiFresh()) {
update_pending = true;
Helpers.runOnUiThreadDelayed(new Runnable() {
@Override
public void run() {
updateGui();
@ -850,20 +930,41 @@ public class InsightPlugin extends PluginBase implements PumpInterface, Constrai
}
}
private void statusActiveBolus(ActiveBolus activeBolus, long offset_mins, List<StatusItem> l) {
if (activeBolus == null) return;
if (activeBolus == null)
return;
switch (activeBolus.getBolusType()) {
case STANDARD:
l.add(new StatusItem(activeBolus.getBolusType() + " " + gs(R.string.bolus), activeBolus.getInitialAmount() + "U", StatusItem.Highlight.NOTICE));
l.add(new StatusItem(activeBolus.getBolusType() + " " + gs(R.string.bolus), activeBolus
.getInitialAmount() + "U", StatusItem.Highlight.NOTICE));
break;
case EXTENDED:
l.add(new StatusItem(activeBolus.getBolusType() + " " + gs(R.string.bolus), activeBolus.getInitialAmount() + "U " + gs(R.string.insight_total_with) + " "
+ activeBolus.getLeftoverAmount() + "U " + gs(R.string.insight_remaining_over) + " " + (activeBolus.getDuration() - offset_mins) + " " + gs(R.string.insight_min), StatusItem.Highlight.NOTICE));
l.add(new StatusItem(activeBolus.getBolusType() + " " + gs(R.string.bolus), activeBolus
.getInitialAmount()
+ "U "
+ gs(R.string.insight_total_with)
+ " "
+ activeBolus.getLeftoverAmount()
+ "U "
+ gs(R.string.insight_remaining_over)
+ " "
+ (activeBolus.getDuration() - offset_mins) + " " + gs(R.string.insight_min),
StatusItem.Highlight.NOTICE));
break;
case MULTIWAVE:
l.add(new StatusItem(activeBolus.getBolusType() + " " + gs(R.string.bolus), activeBolus.getInitialAmount() + "U " + gs(R.string.insight_upfront_with) + " "
+ activeBolus.getLeftoverAmount() + "U " + gs(R.string.insight_remaining_over) + " " + (activeBolus.getDuration() - offset_mins) + " " + gs(R.string.insight_min), StatusItem.Highlight.NOTICE));
l.add(new StatusItem(activeBolus.getBolusType() + " " + gs(R.string.bolus), activeBolus
.getInitialAmount()
+ "U "
+ gs(R.string.insight_upfront_with)
+ " "
+ activeBolus.getLeftoverAmount()
+ "U "
+ gs(R.string.insight_remaining_over)
+ " "
+ (activeBolus.getDuration() - offset_mins) + " " + gs(R.string.insight_min),
StatusItem.Highlight.NOTICE));
break;
default:
@ -871,32 +972,40 @@ public class InsightPlugin extends PluginBase implements PumpInterface, Constrai
}
}
private void fetchTaskRunner(TaskRunner taskRunner) throws Exception {
fetchTaskRunner(taskRunner, Object.class);
}
private void fetchSingleMessage(AppLayerMessage message) throws Exception {
fetchSingleMessage(message, AppLayerMessage.class);
}
private <T> T fetchTaskRunner(TaskRunner taskRunner, Class<T> resultType) throws Exception {
try {
T result = (T) taskRunner.fetchAndWaitUsingLatch(BUSY_WAIT_TIME);
T result = (T)taskRunner.fetchAndWaitUsingLatch(BUSY_WAIT_TIME);
lastDataTime = System.currentTimeMillis();
return result;
} catch (Exception e) {
log.error("Error while fetching " + taskRunner.getClass().getSimpleName() + ": " + e.getClass().getSimpleName());
log.error("Error while fetching " + taskRunner.getClass().getSimpleName() + ": "
+ e.getClass().getSimpleName());
throw e;
}
}
private <T extends AppLayerMessage> T fetchSingleMessage(AppLayerMessage message, Class<T> resultType) throws Exception {
private <T extends AppLayerMessage> T fetchSingleMessage(AppLayerMessage message, Class<T> resultType)
throws Exception {
try {
T result = (T) new SingleMessageTaskRunner(connector.getServiceConnector(), message).fetchAndWaitUsingLatch(BUSY_WAIT_TIME);
T result = (T)new SingleMessageTaskRunner(connector.getServiceConnector(), message)
.fetchAndWaitUsingLatch(BUSY_WAIT_TIME);
lastDataTime = System.currentTimeMillis();
return result;
} catch (Exception e) {
log.error("Error while fetching " + message.getClass().getSimpleName() + ": " + e.getClass().getSimpleName());
log.error("Error while fetching " + message.getClass().getSimpleName() + ": "
+ e.getClass().getSimpleName());
throw e;
}
}
@ -906,30 +1015,54 @@ public class InsightPlugin extends PluginBase implements PumpInterface, Constrai
return new PumpEnactResult().success(false).enacted(false);
}
// Constraints
@Override
public Constraint<Integer> applyBasalPercentConstraints(Constraint<Integer> percentRate, Profile profile) {
percentRate.setIfGreater(0, String.format(MainApp.gs(R.string.limitingpercentrate), 0, MainApp.gs(R.string.itmustbepositivevalue)), this);
percentRate.setIfSmaller(getPumpDescription().maxTempPercent, String.format(MainApp.gs(R.string.limitingpercentrate), getPumpDescription().maxTempPercent, MainApp.gs(R.string.pumplimit)), this);
percentRate.setIfGreater(0,
String.format(MainApp.gs(R.string.limitingpercentrate), 0, MainApp.gs(R.string.itmustbepositivevalue)),
this);
percentRate.setIfSmaller(
getPumpDescription().maxTempPercent,
String.format(MainApp.gs(R.string.limitingpercentrate), getPumpDescription().maxTempPercent,
MainApp.gs(R.string.pumplimit)), this);
return percentRate;
}
@Override
public Constraint<Double> applyBolusConstraints(Constraint<Double> insulin) {
if (statusResult != null) {
insulin.setIfSmaller(statusResult.maximumBolusAmount, String.format(MainApp.gs(R.string.limitingbolus), statusResult.maximumBolusAmount, MainApp.gs(R.string.pumplimit)), this);
insulin.setIfSmaller(
statusResult.maximumBolusAmount,
String.format(MainApp.gs(R.string.limitingbolus), statusResult.maximumBolusAmount,
MainApp.gs(R.string.pumplimit)), this);
if (insulin.value() < statusResult.minimumBolusAmount) {
//TODO: Add function to Constraints or use different approach
// TODO: Add function to Constraints or use different approach
// This only works if the interface of the InsightPlugin is called last.
// If not, another contraint could theoretically set the value between 0 and minimumBolusAmount
insulin.set(0d, String.format(MainApp.gs(R.string.limitingbolus), statusResult.minimumBolusAmount, MainApp.gs(R.string.pumplimit)), this);
insulin.set(
0d,
String.format(MainApp.gs(R.string.limitingbolus), statusResult.minimumBolusAmount,
MainApp.gs(R.string.pumplimit)), this);
}
}
return insulin;
}
@Override
public List<CustomAction> getCustomActions() {
return null;
}
@Override
public PumpEnactResult executeCustomAction(CustomActionType customActionType) {
return null;
}
}

View file

@ -1,5 +1,7 @@
package info.nightscout.androidaps.plugins.PumpMDI;
import java.util.List;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
@ -17,6 +19,8 @@ import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.interfaces.PumpDescription;
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.Actions.defs.CustomAction;
import info.nightscout.androidaps.plugins.Actions.defs.CustomActionType;
import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin;
import info.nightscout.utils.DateUtil;
@ -24,10 +28,12 @@ import info.nightscout.utils.DateUtil;
* Created by mike on 05.08.2016.
*/
public class MDIPlugin extends PluginBase implements PumpInterface {
private static Logger log = LoggerFactory.getLogger(MDIPlugin.class);
private static MDIPlugin plugin = null;
public static MDIPlugin getPlugin() {
if (plugin == null)
plugin = new MDIPlugin();
@ -36,12 +42,10 @@ public class MDIPlugin extends PluginBase implements PumpInterface {
private PumpDescription pumpDescription = new PumpDescription();
private MDIPlugin() {
super(new PluginDescription()
.mainType(PluginType.PUMP)
.pluginName(R.string.mdi)
.description(R.string.description_pump_mdi)
);
super(new PluginDescription().mainType(PluginType.PUMP).pluginName(R.string.mdi)
.description(R.string.description_pump_mdi));
pumpDescription.isBolusCapable = true;
pumpDescription.bolusStep = 0.5d;
@ -51,68 +55,82 @@ public class MDIPlugin extends PluginBase implements PumpInterface {
pumpDescription.isRefillingCapable = false;
}
@Override
public boolean isFakingTempsByExtendedBoluses() {
return false;
}
@Override
public PumpEnactResult loadTDDs() {
//no result, could read DB in the future?
// no result, could read DB in the future?
PumpEnactResult result = new PumpEnactResult();
return result;
}
@Override
public boolean isInitialized() {
return true;
}
@Override
public boolean isSuspended() {
return false;
}
@Override
public boolean isBusy() {
return false;
}
@Override
public boolean isConnected() {
return true;
}
@Override
public boolean isConnecting() {
return false;
}
@Override
public boolean isHandshakeInProgress() {
return false;
}
@Override
public void finishHandshaking() {
}
@Override
public void connect(String reason) {
}
@Override
public void disconnect(String reason) {
}
@Override
public void stopConnecting() {
}
@Override
public void getPumpStatus() {
}
@Override
public PumpEnactResult setNewBasalProfile(Profile profile) {
// Do nothing here. we are using ConfigBuilderPlugin.getPlugin().getActiveProfile().getProfile();
@ -121,21 +139,25 @@ public class MDIPlugin extends PluginBase implements PumpInterface {
return result;
}
@Override
public boolean isThisProfileSet(Profile profile) {
return false;
}
@Override
public long lastDataTime() {
return System.currentTimeMillis();
}
@Override
public double getBaseBasalRate() {
return 0d;
}
@Override
public PumpEnactResult deliverTreatment(DetailedBolusInfo detailedBolusInfo) {
PumpEnactResult result = new PumpEnactResult();
@ -147,12 +169,15 @@ public class MDIPlugin extends PluginBase implements PumpInterface {
return result;
}
@Override
public void stopBolusDelivering() {
}
@Override
public PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes, Profile profile, boolean enforceNew) {
public PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes, Profile profile,
boolean enforceNew) {
PumpEnactResult result = new PumpEnactResult();
result.success = false;
result.comment = MainApp.gs(R.string.pumperror);
@ -161,8 +186,10 @@ public class MDIPlugin extends PluginBase implements PumpInterface {
return result;
}
@Override
public PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes, Profile profile, boolean enforceNew) {
public PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes, Profile profile,
boolean enforceNew) {
PumpEnactResult result = new PumpEnactResult();
result.success = false;
result.comment = MainApp.gs(R.string.pumperror);
@ -171,6 +198,7 @@ public class MDIPlugin extends PluginBase implements PumpInterface {
return result;
}
@Override
public PumpEnactResult setExtendedBolus(Double insulin, Integer durationInMinutes) {
PumpEnactResult result = new PumpEnactResult();
@ -181,6 +209,7 @@ public class MDIPlugin extends PluginBase implements PumpInterface {
return result;
}
@Override
public PumpEnactResult cancelTempBasal(boolean force) {
PumpEnactResult result = new PumpEnactResult();
@ -191,6 +220,7 @@ public class MDIPlugin extends PluginBase implements PumpInterface {
return result;
}
@Override
public PumpEnactResult cancelExtendedBolus() {
PumpEnactResult result = new PumpEnactResult();
@ -201,6 +231,7 @@ public class MDIPlugin extends PluginBase implements PumpInterface {
return result;
}
@Override
public JSONObject getJSONStatus(Profile profile, String profileName) {
long now = System.currentTimeMillis();
@ -224,19 +255,33 @@ public class MDIPlugin extends PluginBase implements PumpInterface {
return pump;
}
@Override
public String deviceID() {
return "MDI";
}
@Override
public PumpDescription getPumpDescription() {
return pumpDescription;
}
@Override
public String shortStatus(boolean veryShort) {
return deviceID();
}
@Override
public List<CustomAction> getCustomActions() {
return null;
}
@Override
public PumpEnactResult executeCustomAction(CustomActionType customActionType) {
return null;
}
}

View file

@ -214,7 +214,7 @@ public class MedtronicFragment extends SubscriberFragment {
}
private void setDeviceStatus(MedtronicPumpStatus pumpStatus) {
private synchronized void setDeviceStatus(MedtronicPumpStatus pumpStatus) {
pumpStatus.rileyLinkServiceState = (RileyLinkServiceState)checkStatusSet(pumpStatus.rileyLinkServiceState,
RileyLinkUtil.getServiceState());
@ -270,8 +270,10 @@ public class MedtronicFragment extends SubscriberFragment {
case Active: {
MedtronicCommandType cmd = MedtronicUtil.getCurrentCommand();
LOG.debug("Command: " + cmd);
if (cmd == null)
pumpStatusIconView.setText(" " + pumpStatus.pumpDeviceState.name());
pumpStatusIconView.setText(" " + MainApp.gs(pumpStatus.pumpDeviceState.getResourceId()));
else
pumpStatusIconView.setText(" " + cmd.name());

View file

@ -1,8 +1,12 @@
package info.nightscout.androidaps.plugins.PumpMedtronic;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.LocalDateTime;
@ -16,6 +20,8 @@ import android.os.SystemClock;
import android.support.annotation.NonNull;
import com.crashlytics.android.answers.CustomEvent;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import info.nightscout.androidaps.BuildConfig;
import info.nightscout.androidaps.MainApp;
@ -24,12 +30,14 @@ import info.nightscout.androidaps.data.DetailedBolusInfo;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.data.PumpEnactResult;
import info.nightscout.androidaps.db.Source;
import info.nightscout.androidaps.db.TDD;
import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.events.EventRefreshOverview;
import info.nightscout.androidaps.interfaces.PluginDescription;
import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.interfaces.PumpDescription;
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.plugins.Actions.defs.CustomAction;
import info.nightscout.androidaps.plugins.Actions.defs.CustomActionType;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.PumpCommon.PumpPluginAbstract;
import info.nightscout.androidaps.plugins.PumpCommon.defs.PumpDriverState;
@ -49,6 +57,7 @@ import info.nightscout.androidaps.plugins.PumpMedtronic.data.dto.BasalProfile;
import info.nightscout.androidaps.plugins.PumpMedtronic.data.dto.BasalProfileEntry;
import info.nightscout.androidaps.plugins.PumpMedtronic.data.dto.TempBasalPair;
import info.nightscout.androidaps.plugins.PumpMedtronic.defs.MedtronicCommandType;
import info.nightscout.androidaps.plugins.PumpMedtronic.defs.MedtronicCustomActionType;
import info.nightscout.androidaps.plugins.PumpMedtronic.defs.MedtronicNotificationType;
import info.nightscout.androidaps.plugins.PumpMedtronic.defs.MedtronicStatusRefreshType;
import info.nightscout.androidaps.plugins.PumpMedtronic.driver.MedtronicPumpStatus;
@ -76,10 +85,16 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
private boolean firstRun = true;
private boolean isRefresh = false;
private boolean isBasalProfileInvalid = false;
private boolean basalProfileChanged = false;
private Map<MedtronicStatusRefreshType, Long> statusRefreshMap = new HashMap<>();
private boolean isInitialized = false;
private MedtronicHistoryData medtronicHistoryData;
private MedtronicCommunicationManager medtronicCommunicationManager;
private PumpHistoryEntry lastPumpHistoryEntry;
public static Gson gsonInstance = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
public static Gson gsonInstancePretty = new GsonBuilder().excludeFieldsWithoutExposeAnnotation()
.setPrettyPrinting().create();
private MedtronicPumpPlugin() {
@ -94,7 +109,7 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
);
// TODO remove this later
displayConnectionMessages = true;
displayConnectionMessages = false;
medtronicHistoryData = new MedtronicHistoryData();
// medtronicCommunicationManager = MedtronicCommunicationManager.getInstance();
@ -159,24 +174,9 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
this.pumpStatus = pumpStatusLocal;
// this is only thing that can change, by being configured
pumpDescription.maxTempAbsolute = (pumpStatusLocal.maxBasal != null) ? pumpStatusLocal.maxBasal : 35.0d;
// needs to be changed in configuration, after all functionalities are done
pumpDescription.isBolusCapable = true; // WIP
pumpDescription.isTempBasalCapable = true; // WIP
pumpDescription.isExtendedBolusCapable = false;
pumpDescription.isSetBasalProfileCapable = true;
// unchangable
pumpDescription.tempBasalStyle = PumpDescription.PERCENT;
pumpDescription.tempDurationStep15mAllowed = false;
pumpDescription.tempDurationStep30mAllowed = true;
pumpDescription.isRefillingCapable = true;
pumpDescription.storesCarbInfo = false;
pumpDescription.is30minBasalRatesCapable = true;
pumpDescription.supportsTDDs = true;
pumpDescription.needsManualTDDLoad = false;
// set first Medtronic Pump Start
if (!SP.contains(MedtronicConst.Statistics.FirstPumpStart)) {
SP.putLong(MedtronicConst.Statistics.FirstPumpStart, System.currentTimeMillis());
@ -194,7 +194,7 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
SystemClock.sleep(60000);
if (doWeHaveAnyStatusNeededRefereshing()) {
ConfigBuilderPlugin.getPlugin().getCommandQueue().readStatus("Manual Status Refresh", null);
ConfigBuilderPlugin.getPlugin().getCommandQueue().readStatus("Scheduled Status Refresh", null);
}
} while (serviceRunning);
@ -235,13 +235,12 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
}
@Override
public boolean isSuspended() {
// TODO remove
LOG.debug("MedtronicPumpPlugin::isSuspended");
return isServiceSet() && medtronicHistoryData.isSuspended();
}
// @Override
// public boolean isSuspended() {
// // TO DO remove
// LOG.debug("MedtronicPumpPlugin::isSuspended");
// return isServiceSet() && medtronicHistoryData.is();
// }
@Override
public boolean isBusy() {
@ -316,15 +315,13 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
MedtronicUtil.sendNotification(MedtronicNotificationType.PumpUnreachable);
return;
// new PumpEnactResult() //
// .success(false) //
// .enacted(false) //
// .comment(MainApp.gs(R.string.medtronic_pump_status_pump_unreachable));
}
MedtronicUtil.dismissNotification(MedtronicNotificationType.PumpUnreachable);
Set<MedtronicStatusRefreshType> refreshTypesNeededToReschedule = new HashSet<>();
// execute
for (Map.Entry<MedtronicStatusRefreshType, Long> refreshType : statusRefreshMap.entrySet()) {
if (refreshType.getValue() > 0 && System.currentTimeMillis() > refreshType.getValue()) {
@ -339,7 +336,7 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
case BatteryStatus:
case RemainingInsulin: {
medtronicUIComm.executeCommand(refreshType.getKey().getCommandType());
scheduleNextRefresh(refreshType.getKey());
refreshTypesNeededToReschedule.add(refreshType.getKey());
resetTime = true;
}
break;
@ -347,14 +344,17 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
case Configuration: {
medtronicUIComm.executeCommand(refreshType.getKey().getCommandType());
resetTime = true;
medtronicHistoryData.resetRelevantConfigurationChanged();
}
break;
}
}
}
// reschedule
for (MedtronicStatusRefreshType refreshType : refreshTypesNeededToReschedule) {
scheduleNextRefresh(refreshType);
}
if (resetTime)
pumpStatusLocal.setLastCommunicationToNow();
@ -381,7 +381,7 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
private void initializePump(boolean realInit) {
LOG.error("initializePump - start");
LOG.info(getLogPrefix() + "initializePump - start");
if (medtronicCommunicationManager == null) {
medtronicCommunicationManager = MedtronicCommunicationManager.getInstance();
@ -394,7 +394,7 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
if (isRefresh) {
if (isPumpNotReachable()) {
LOG.error("initializePump::Pump unreachable.");
LOG.error(getLogPrefix() + "initializePump::Pump unreachable.");
MedtronicUtil.sendNotification(MedtronicNotificationType.PumpUnreachable);
setRefreshButtonEnabled(true);
@ -410,13 +410,13 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
medtronicUIComm.executeCommand(MedtronicCommandType.PumpModel);
} else {
if (pumpStatusLocal.medtronicDeviceType != MedtronicUtil.getMedtronicPumpModel()) {
LOG.warn("Configured pump is not the same as one detected.");
LOG.warn(getLogPrefix() + "Configured pump is not the same as one detected.");
MedtronicUtil.sendNotification(MedtronicNotificationType.PumpTypeNotSame);
}
}
// TODO this call might need to do deeper call (several pages)
// pump history handling - special, updates every 5 minutes ???
this.pumpState = PumpDriverState.Connected;
readPumpHistory();
// TODO rewrite reading of data to be done in background or different thread perhaps ??
@ -430,7 +430,7 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
scheduleNextRefresh(MedtronicStatusRefreshType.BatteryStatus, 20);
// configuration (once and then if history shows config changes)
medtronicUIComm.executeCommand(MedtronicCommandType.getSettings(MedtronicUtil.getMedtronicPumpModel()));
// medtronicUIComm.executeCommand(MedtronicCommandType.getSettings(MedtronicUtil.getMedtronicPumpModel()));
// time (1h)
medtronicUIComm.executeCommand(MedtronicCommandType.RealTimeClock);
@ -444,8 +444,8 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
if (errorCount >= 5) {
LOG.error("Number of error counts was 5 or more. Starting tunning.");
setRefreshButtonEnabled(true);
ServiceTaskExecutor.startTask(new WakeAndTuneTask());
setRefreshButtonEnabled(true); // FIXME
return;
}
@ -462,6 +462,7 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
.putCustomAttribute("version", BuildConfig.VERSION));
isInitialized = true;
// this.pumpState = PumpDriverState.Initialized;
this.firstRun = false;
}
@ -474,7 +475,7 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
return true;
}
if (!medtronicHistoryData.hasBasalProfileChanged() && getMDTPumpStatus().basalsByHour != null) {
if (!basalProfileChanged && getMDTPumpStatus().basalsByHour != null) {
return (!isBasalProfileInvalid);
}
@ -484,11 +485,7 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
MedtronicUtil.sendNotification(MedtronicNotificationType.PumpUnreachable);
setRefreshButtonEnabled(true);
return false;
// new PumpEnactResult() //
// .success(false) //
// .enacted(false) //
// .comment(MainApp.gs(R.string.medtronic_pump_status_pump_unreachable));
return true; // we don't won't setting profile if pump unreachable
}
MedtronicUtil.dismissNotification(MedtronicNotificationType.PumpUnreachable);
@ -506,7 +503,7 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
int index = 0;
if (basalsByHour == null)
return true;
return true; // we don't want to set profile again, unless we are sure
for (Profile.BasalValue basalValue : profile.getBasalValues()) {
@ -527,6 +524,7 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
if (!invalid) {
LOG.debug("Basal profile is same as AAPS one.");
basalProfileChanged = false;
} else {
LOG.debug("Basal profile on Pump is different than the AAPS one.");
}
@ -538,9 +536,6 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
isBasalProfileInvalid = invalid;
if (!invalid)
medtronicHistoryData.resetBasalProfileChanged();
setRefreshButtonEnabled(true);
return (!invalid);
@ -774,18 +769,18 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
getMDTPumpStatus();
LOG.info("MedtronicPumpPlugin::setTempBasalAbsolute: rate: {}, duration={}", absoluteRate, durationInMinutes);
LOG.info(getLogPrefix() + "setTempBasalAbsolute: rate: {}, duration={}", absoluteRate, durationInMinutes);
// read current TBR
TempBasalPair tbrCurrent = readTBR();
if (tbrCurrent == null) {
LOG.warn("MedtronicPumpPlugin::setTempBasalAbsolute - Could not read current TBR, canceling operation.");
setRefreshButtonEnabled(true);
LOG.warn(getLogPrefix() + "setTempBasalAbsolute - Could not read current TBR, canceling operation.");
finishAction("TBR");
return new PumpEnactResult().success(false).enacted(false)
.comment(MainApp.gs(R.string.medtronic_cmd_cant_read_tbr));
} else {
LOG.info("MedtronicPumpPlugin::setTempBasalAbsolute: Current Basal: duration: {} min, rate={}",
LOG.info(getLogPrefix() + "setTempBasalAbsolute: Current Basal: duration: {} min, rate={}",
tbrCurrent.getDurationMinutes(), tbrCurrent.getInsulinRate());
}
@ -800,8 +795,8 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
}
if (sameRate) {
LOG.info("MedtronicPumpPlugin::setTempBasalAbsolute - No enforceNew and same rate. Exiting.");
setRefreshButtonEnabled(true);
LOG.info(getLogPrefix() + "setTempBasalAbsolute - No enforceNew and same rate. Exiting.");
finishAction("TBR");
return new PumpEnactResult().success(true).enacted(false);
}
}
@ -810,7 +805,7 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
// if TBR is running we will cancel it.
if (tbrCurrent.getInsulinRate() != 0.0f && tbrCurrent.getDurationMinutes() > 0) {
LOG.info("MedtronicPumpPlugin::setTempBasalAbsolute - TBR running - so canceling it.");
LOG.info(getLogPrefix() + "setTempBasalAbsolute - TBR running - so canceling it.");
// CANCEL
@ -819,11 +814,11 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
Boolean response = (Boolean)responseTask2.returnData;
if (response) {
LOG.info("MedtronicPumpPlugin::setTempBasalAbsolute - Current TBR cancelled.");
LOG.info(getLogPrefix() + "setTempBasalAbsolute - Current TBR cancelled.");
} else {
LOG.error("MedtronicPumpPlugin::setTempBasalAbsolute - Cancel TBR failed.");
LOG.error(getLogPrefix() + "setTempBasalAbsolute - Cancel TBR failed.");
setRefreshButtonEnabled(true);
finishAction("TBR");
return new PumpEnactResult().success(false).enacted(false)
.comment(MainApp.gs(R.string.medtronic_cmd_cant_cancel_tbr));
@ -836,7 +831,7 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
Boolean response = (Boolean)responseTask.returnData;
LOG.info("MedtronicPumpPlugin::setTempBasalAbsolute - setTBR. Response: " + response);
LOG.info(getLogPrefix() + "setTempBasalAbsolute - setTBR. Response: " + response);
if (response) {
// FIXME put this into UIPostProcessor
@ -855,22 +850,30 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
incrementStatistics(MedtronicConst.Statistics.TBRsSet);
}
MainApp.bus().post(new EventRefreshOverview("TBR"));
triggerUIChange();
finishAction("TBR");
setRefreshButtonEnabled(true);
return new PumpEnactResult().success(response).enacted(response);
}
// Gson gson = new Gson();
PumpHistoryEntry lastPumpHistoryEntry;
private void finishAction(String overviewKey) {
if (overviewKey != null)
MainApp.bus().post(new EventRefreshOverview(overviewKey));
triggerUIChange();
setRefreshButtonEnabled(true);
}
private void readPumpHistory() {
LOG.error("MedtronicPumpPlugin::readPumpHistory NOT IMPLEMENTED.");
// readPumpHistoryLogic();
LOG.error(getLogPrefix() + "readPumpHistory WIP.");
readPumpHistoryLogic();
scheduleNextRefresh(MedtronicStatusRefreshType.PumpHistory);
@ -878,7 +881,70 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
scheduleNextRefresh(MedtronicStatusRefreshType.Configuration, -1);
}
// FIXME set last read
if (medtronicHistoryData.hasPumpTimeChanged()) {
scheduleNextRefresh(MedtronicStatusRefreshType.PumpTime, -1);
}
if (medtronicHistoryData.hasBasalProfileChanged()) {
this.basalProfileChanged = true;
}
PumpDriverState previousState = this.pumpState;
if (medtronicHistoryData.isPumpSuspended(this.pumpState == PumpDriverState.Suspended)) {
scheduleNextRefresh(MedtronicStatusRefreshType.PumpTime, -1);
this.pumpState = PumpDriverState.Suspended;
LOG.debug(getLogPrefix() + "isPumpSuspended: true");
} else {
if (previousState == PumpDriverState.Suspended) {
this.pumpState = PumpDriverState.Ready;
}
LOG.debug(getLogPrefix() + "isPumpSuspended: false");
}
List<PumpHistoryEntry> tdds = medtronicHistoryData.getTDDs();
if (tdds.size() > 0) {
processTDDs(tdds);
}
List<PumpHistoryEntry> tdds2 = medtronicHistoryData.getTDDs2();
LOG.debug("TDDs2: {}", gsonInstancePretty.toJson(tdds2));
List<PumpHistoryEntry> treatments = medtronicHistoryData.getTreatments();
if (treatments.size() > 0) {
processTreatments(treatments);
}
this.medtronicHistoryData.finalizeNewHistoryRecords();
}
private void processTreatments(List<PumpHistoryEntry> treatments) {
// FIXME bolus and tbr
LOG.error(getLogPrefix() + "Treatments found: {}. Not processed.\n", treatments.size());
MedtronicHistoryData.showLogs(null, gsonInstancePretty.toJson(treatments));
}
private void processTDDs(List<PumpHistoryEntry> tdds) {
LOG.error(getLogPrefix() + "TDDs found: {}. Not processed.\n{}", tdds.size(), gsonInstancePretty.toJson(tdds));
// FIXME tdd
List<TDD> tdDsForLastXDays = MainApp.getDbHelper().getTDDs();
for (TDD tdDsForLastXDay : tdDsForLastXDays) {
LOG.debug("TDD: " + tdDsForLastXDay);
}
}
@ -886,23 +952,26 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
LocalDateTime targetDate = null;
// TODO read History
// if (lastPumpHistoryEntry == null) {
// lastPumpHistoryEntryTime = SP.getLong(MedtronicConst.Statistics.LastPumpHistoryEntry, null);
// }
if (lastPumpHistoryEntry == null) {
Long lastPumpHistoryEntryTime = SP.getLong(MedtronicConst.Statistics.LastPumpHistoryEntry, null);
LOG.debug(getLogPrefix() + "readPumpHistoryLogic(): lastPumpHistoryEntry: null");
Long lastPumpHistoryEntryTime = SP.getLong(MedtronicConst.Statistics.LastPumpHistoryEntry, 0L);
LocalDateTime timeMinus36h = new LocalDateTime();
timeMinus36h = timeMinus36h.minusHours(36);
medtronicHistoryData.setIsInInit(true);
if (lastPumpHistoryEntryTime == null) {
if (lastPumpHistoryEntryTime == 0L) {
LOG.debug(getLogPrefix() + "readPumpHistoryLogic(): lastPumpHistoryEntryTime: 0L - targetDate: "
+ targetDate);
targetDate = timeMinus36h;
} else {
LocalDateTime lastHistoryRecordTime = DateTimeUtil.toLocalDateTime(lastPumpHistoryEntryTime);
LOG.debug(getLogPrefix() + "readPumpHistoryLogic(): lastPumpHistoryEntryTime: {} - targetDate: {}",
lastHistoryRecordTime, targetDate);
medtronicHistoryData.setLastHistoryRecordTime(DateTimeUtil.toLocalDateTime(lastPumpHistoryEntryTime));
lastHistoryRecordTime = lastHistoryRecordTime.minusHours(12); // we get last 12 hours of history to
@ -914,15 +983,25 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
}
targetDate = (timeMinus36h.isAfter(lastHistoryRecordTime) ? timeMinus36h : lastHistoryRecordTime);
LOG.debug(getLogPrefix() + "readPumpHistoryLogic(): targetDate: " + targetDate);
}
} else {
LOG.debug(getLogPrefix() + "readPumpHistoryLogic(): lastPumpHistoryEntry: not null - {}",
gsonInstancePretty.toJson(lastPumpHistoryEntry));
medtronicHistoryData.setIsInInit(false);
medtronicHistoryData.setLastHistoryRecordTime(null);
}
// FIXME read history
MedtronicUITask responseTask2 = medtronicUIComm.executeCommand(MedtronicCommandType.GetHistoryData,
lastPumpHistoryEntry, targetDate);
PumpHistoryResult historyResult = new PumpHistoryResult(null, null);
PumpHistoryResult historyResult = (PumpHistoryResult)responseTask2.returnData;
PumpHistoryEntry latestEntry = historyResult.getLatestEntry();
LOG.debug(getLogPrefix() + "Last entry: " + latestEntry);
if (latestEntry == null) // no new history to read
return;
@ -930,6 +1009,9 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
SP.putLong(MedtronicConst.Statistics.LastPumpHistoryEntry,
DateTimeUtil.toATechDate(latestEntry.getLocalDateTime()));
this.medtronicHistoryData.addNewHistory(historyResult);
this.medtronicHistoryData.filterNewEntries();
// determine if first run, if yes detrmine how much of update do we need
// first run:
// get last hiostory entry, if not there download 1.5 days of data
@ -963,7 +1045,7 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
case RemainingInsulin: {
Double remaining = pumpStatusLocal.reservoirRemainingUnits;
int min = 0;
int min;
if (remaining > 50)
min = 4 * 60;
else if (remaining > 20)
@ -975,6 +1057,7 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
}
break;
case PumpTime:
case Configuration:
case PumpHistory: {
statusRefreshMap.put(refreshType, getTimeInFutureFromMinutes(refreshType.getRefreshTime()
@ -1016,7 +1099,7 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
@Override
public PumpEnactResult cancelTempBasal(boolean enforceNew) {
LOG.info("MedtronicPumpPlugin::cancelTempBasal - started");
LOG.info(getLogPrefix() + "cancelTempBasal - started");
if (isPumpNotReachable()) {
@ -1035,13 +1118,13 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
if (tbrCurrent != null) {
if (tbrCurrent.getInsulinRate() == 0.0f && tbrCurrent.getDurationMinutes() == 0) {
LOG.info("MedtronicPumpPlugin::cancelTempBasal - TBR already canceled.");
setRefreshButtonEnabled(true);
LOG.info(getLogPrefix() + "cancelTempBasal - TBR already canceled.");
finishAction("TBR");
return new PumpEnactResult().success(true).enacted(false);
}
} else {
LOG.warn("MedtronicPumpPlugin::cancelTempBasal - Could not read currect TBR, canceling operation.");
setRefreshButtonEnabled(true);
LOG.warn(getLogPrefix() + "cancelTempBasal - Could not read currect TBR, canceling operation.");
finishAction("TBR");
return new PumpEnactResult().success(false).enacted(false)
.comment(MainApp.gs(R.string.medtronic_cmd_cant_read_tbr));
}
@ -1051,13 +1134,13 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
Boolean response = (Boolean)responseTask2.returnData;
if (response) {
LOG.info("MedtronicPumpPlugin::cancelTempBasal - Cancel TBR successful.");
LOG.info(getLogPrefix() + "cancelTempBasal - Cancel TBR successful.");
} else {
LOG.info("MedtronicPumpPlugin::cancelTempBasal - Cancel TBR failed.");
LOG.info(getLogPrefix() + "cancelTempBasal - Cancel TBR failed.");
}
setRefreshButtonEnabled(true);
finishAction("TBR");
return new PumpEnactResult().success(response).enacted(response);
}
@ -1109,12 +1192,12 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
MedtronicPumpStatus pumpStatus = getMDTPumpStatus();
if (pumpStatusLocal.maxBasal == null)
if (pumpStatus.maxBasal == null)
return null;
for (BasalProfileEntry profileEntry : basalProfile.getEntries()) {
if (profileEntry.rate > pumpStatusLocal.maxBasal) {
if (profileEntry.rate > pumpStatus.maxBasal) {
stringBuilder.append(profileEntry.startTime.toString("HH:mm") + "=" + profileEntry.rate);
@ -1176,40 +1259,72 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
}
// we don't loadTDD. TDD is read from Pump History
@Override
public PumpEnactResult loadTDDs() {
return OPERATION_NOT_SUPPORTED;
}
// // we don't loadTDD. TDD is read from Pump History
// @Override
// public PumpEnactResult loadTDDs() {
// return OPERATION_NOT_SUPPORTED;
// }
// public void connect(String reason) {
// // we don't use this.
// // we connect to RileyLink on startup and keep connection opened, then connection to pump
// // is established when needed.
//
// // TODO remove
// LOG.debug("MedtronicPumpPlugin::connect (reason: {})", reason);
// }
public void connect(String reason) {
// we don't use this.
// we connect to RileyLink on startup and keep connection opened, then connection to pump
// is established when needed.
// TODO remove
LOG.debug("MedtronicPumpPlugin::connect (reason: {})", reason);
}
public void disconnect(String reason) {
// see comment in connect
// TODO remove
LOG.debug("MedtronicPumpPlugin::disconnect (reason: {})", reason);
}
public void stopConnecting() {
// see comment in connect
// TODO remove
LOG.debug("MedtronicPumpPlugin::stopConnecting");
}
// public void disconnect(String reason) {
// // see comment in connect
// // TO DO remove
// LOG.debug("MedtronicPumpPlugin::disconnect (reason: {})", reason);
// }
// public void stopConnecting() {
// // see comment in connect
// // TO DO remove
// LOG.debug("MedtronicPumpPlugin::stopConnecting");
// }
@Override
public void stopBolusDelivering() {
// Medtronic doesn't have Bolus cancel, so we fake it.
}
List<CustomAction> customActions = null;
@Override
public List<CustomAction> getCustomActions() {
if (customActions == null) {
this.customActions = new ArrayList<>();
CustomAction ca = new CustomAction(R.string.medtronic_custom_action_wake_and_tune,
MedtronicCustomActionType.WakeUpAndTune);
this.customActions.add(ca);
}
return this.customActions;
}
@Override
public PumpEnactResult executeCustomAction(CustomActionType customActionType) {
MedtronicCustomActionType mcat = (MedtronicCustomActionType)customActionType;
switch (mcat) {
case WakeUpAndTune:
ServiceTaskExecutor.startTask(new WakeAndTuneTask());
break;
default:
break;
}
return null;
}
}

View file

@ -1,15 +1,14 @@
package info.nightscout.androidaps.plugins.PumpMedtronic.comm;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.joda.time.Instant;
import org.joda.time.LocalDateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import android.content.Context;
import android.os.SystemClock;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.RileyLinkCommunicationManager;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.RileyLinkConst;
@ -19,11 +18,11 @@ import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.data.RLMes
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.data.RadioPacket;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.data.RadioResponse;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.defs.RLMessageType;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.defs.RileyLinkTargetFrequency;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.service.tasks.ServiceTaskExecutor;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.service.tasks.WakeAndTuneTask;
import info.nightscout.androidaps.plugins.PumpCommon.utils.ByteUtil;
import info.nightscout.androidaps.plugins.PumpCommon.utils.HexDump;
import info.nightscout.androidaps.plugins.PumpMedtronic.comm.data.Page;
import info.nightscout.androidaps.plugins.PumpMedtronic.comm.data.history_old.Record;
import info.nightscout.androidaps.plugins.PumpMedtronic.comm.history.RawHistoryPage;
import info.nightscout.androidaps.plugins.PumpMedtronic.comm.history.pump.MedtronicPumpHistoryDecoder;
import info.nightscout.androidaps.plugins.PumpMedtronic.comm.history.pump.PumpHistoryEntry;
@ -65,15 +64,17 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager
private MedtronicPumpHistoryDecoder pumpHistoryDecoder;
private boolean doWakeUpBeforeCommand = true;
private boolean firstConnection = true;
private boolean medtronicHistoryTesting = false; // TODO remove when not needed
public MedtronicCommunicationManager(Context context, RFSpy rfspy, RileyLinkTargetFrequency targetFrequency) {
super(context, rfspy, targetFrequency);
public MedtronicCommunicationManager(Context context, RFSpy rfspy) {
super(context, rfspy);
medtronicCommunicationManager = this;
this.medtronicConverter = new MedtronicConverter();
this.pumpHistoryDecoder = new MedtronicPumpHistoryDecoder();
MedtronicUtil.getPumpStatus().previousConnection = SP.getLong(
RileyLinkConst.Prefs.LastGoodDeviceCommunicationTime, 0L);
}
@ -100,13 +101,18 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager
}
public boolean isDeviceReachable() {
return isDeviceReachable(false);
}
/**
* We do actual wakeUp and compare PumpModel with currently selected one. If returned model is not Unknown,
* pump is reachable.
*
* @return
*/
public boolean isDeviceReachable() {
public boolean isDeviceReachable(boolean canPreventTuneUp) {
PumpDeviceState state = MedtronicUtil.getPumpDeviceState();
@ -135,8 +141,6 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager
rfSpyResponse.wasTimeout());
} else {
// rememberLastGoodDeviceCommunicationTime();
// radioResponse.rssi;
Object dataResponse = medtronicConverter.convertResponse(MedtronicCommandType.PumpModel,
pumpResponse.getRawContent());
@ -175,11 +179,16 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager
LOG.warn("isDeviceReachable. Unknown response: " + ByteUtil.shortHexString(rfSpyResponse.getRaw()));
}
SystemClock.sleep(1000);
}
if (state != PumpDeviceState.PumpUnreachable)
MedtronicUtil.setPumpDeviceState(PumpDeviceState.PumpUnreachable);
if (!canPreventTuneUp)
ServiceTaskExecutor.startTask(new WakeAndTuneTask());
return false;
}
@ -188,7 +197,7 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager
@Override
public boolean tryToConnectToDevice() {
return isDeviceReachable();
return isDeviceReachable(true);
// wakeUp(true);
//
@ -378,6 +387,10 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager
if (doWakeUpBeforeCommand)
wakeUp(receiverDeviceAwakeForMinutes, false);
LOG.debug("Current command: " + MedtronicUtil.getCurrentCommand());
MedtronicUtil.setPumpDeviceState(PumpDeviceState.Active);
for (int pageNumber = 0; pageNumber < 16; pageNumber++) {
RawHistoryPage rawHistoryPage = new RawHistoryPage();
@ -454,6 +467,8 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager
LOG.error("getPumpHistory: checksum is wrong");
}
// TODO handle error states
rawHistoryPage.dumpToDebug();
List<PumpHistoryEntry> medtronicHistoryEntries = pumpHistoryDecoder.processPageAndCreateRecords(
@ -467,11 +482,15 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager
LOG.debug("getPumpHistory: Search status: Search finished: {}", pumpTotalResult.isSearchFinished());
if (pumpTotalResult.isSearchFinished()) {
MedtronicUtil.setPumpDeviceState(PumpDeviceState.Sleeping);
return pumpTotalResult;
}
}
MedtronicUtil.setPumpDeviceState(PumpDeviceState.Sleeping);
return pumpTotalResult;
}
@ -558,31 +577,29 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager
}
public ArrayList<Page> getAllHistoryPages() {
ArrayList<Page> pages = new ArrayList<>();
for (int pageNum = 0; pageNum < 16; pageNum++) {
pages.add(getPumpHistoryPage(pageNum));
}
return pages;
}
public ArrayList<Page> getHistoryEventsSinceDate(Instant when) {
ArrayList<Page> pages = new ArrayList<>();
for (int pageNum = 0; pageNum < 16; pageNum++) {
pages.add(getPumpHistoryPage(pageNum));
for (Page page : pages) {
for (Record r : page.mRecordList) {
LocalDateTime timestamp = r.getTimestamp().getLocalDateTime();
LOG.info("Found record: (" + r.getClass().getSimpleName() + ") " + timestamp.toString());
}
}
}
return pages;
}
// public ArrayList<Page> getAllHistoryPages() {
// ArrayList<Page> pages = new ArrayList<>();
//
// for (int pageNum = 0; pageNum < 16; pageNum++) {
// pages.add(getPumpHistoryPage(pageNum));
// }
//
// return pages;
// }
// public ArrayList<Page> getHistoryEventsSinceDate(Instant when) {
// ArrayList<Page> pages = new ArrayList<>();
// for (int pageNum = 0; pageNum < 16; pageNum++) {
// pages.add(getPumpHistoryPage(pageNum));
// for (Page page : pages) {
// for (Record r : page.mRecordList) {
// LocalDateTime timestamp = r.getTimestamp().getLocalDateTime();
// LOG.info("Found record: (" + r.getClass().getSimpleName() + ") " + timestamp.toString());
// }
// }
// }
// return pages;
// }
public String getErrorResponse() {
return this.errorMessage;

View file

@ -5,7 +5,12 @@ import java.util.List;
import java.util.Map;
import org.joda.time.LocalDateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import com.google.gson.annotations.Expose;
import info.nightscout.androidaps.plugins.PumpCommon.utils.DateTimeUtil;
import info.nightscout.androidaps.plugins.PumpCommon.utils.HexDump;
import info.nightscout.androidaps.plugins.PumpCommon.utils.StringUtil;
@ -34,6 +39,8 @@ public abstract class MedtronicHistoryEntry implements MedtronicHistoryEntryInte
protected List<Byte> rawData;
protected static DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern("dd.MM.yyyy HH:mm:ss");
protected int[] sizes = new int[3];
protected byte[] head;
@ -41,8 +48,14 @@ public abstract class MedtronicHistoryEntry implements MedtronicHistoryEntryInte
protected byte[] body;
protected LocalDateTime dateTime;
// protected PumpTimeStampedRecord historyEntryDetails;
@Expose
public String DT;
@Expose
public long atechDateTime;
@Expose
protected Map<String, Object> decodedData;
@ -231,6 +244,13 @@ public abstract class MedtronicHistoryEntry implements MedtronicHistoryEntryInte
public void setLocalDateTime(LocalDateTime atdate) {
this.dateTime = atdate;
// this.DT = atdate.toString(dateTimeFormatter);
}
public void setAtechDateTime(long dt) {
this.atechDateTime = dt;
this.DT = DateTimeUtil.toString(this.atechDateTime);
}

View file

@ -5,8 +5,6 @@ import java.util.Arrays;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import android.util.Log;
import info.nightscout.androidaps.plugins.PumpCommon.utils.ByteUtil;
import info.nightscout.androidaps.plugins.PumpCommon.utils.CRC;
import info.nightscout.androidaps.plugins.PumpMedtronic.util.MedtronicUtil;
@ -16,9 +14,9 @@ import info.nightscout.androidaps.plugins.PumpMedtronic.util.MedtronicUtil;
*/
public class RawHistoryPage {
private static final String TAG = "RawHistoryPage";
private static final Logger LOG = LoggerFactory.getLogger(RawHistoryPage.class);
byte[] data = new byte[0];
private byte[] data = new byte[0];
public RawHistoryPage() {
@ -69,14 +67,21 @@ public class RawHistoryPage {
public void dumpToDebug() {
int linesize = 80;
int offset = 0;
StringBuffer sb = new StringBuffer();
while (offset < data.length) {
int bytesToLog = linesize;
if (offset + linesize > data.length) {
bytesToLog = data.length - offset;
}
Log.d(TAG, ByteUtil.shortHexString(ByteUtil.substring(data, offset, bytesToLog)));
sb.append(ByteUtil.shortHexString(ByteUtil.substring(data, offset, bytesToLog)) + " ");
// sb.append("\n");
offset += linesize;
}
LOG.debug("History Page Data:\n{}", sb.toString());
}
}

View file

@ -110,12 +110,6 @@ public class MedtronicCGMSHistoryDecoder extends MedtronicHistoryDecoder {
}
// @Override
// public List<? extends MedtronicHistoryEntry> processPageAndCreateRecords(RawHistoryPage page) throws Exception {
// List<Byte> dataClear = checkPage(page, false);
// return createRecords(dataClear);
// }
protected <E extends MedtronicHistoryEntry> List<E> createRecords(List<Byte> dataClearInput, Class<E> clazz) {
// List<MinimedHistoryEntry> listRecords = new
// ArrayList<MinimedHistoryEntry>();

View file

@ -9,16 +9,17 @@ import org.joda.time.LocalDateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import android.util.Log;
import info.nightscout.androidaps.plugins.PumpCommon.utils.ByteUtil;
import info.nightscout.androidaps.plugins.PumpCommon.utils.DateTimeUtil;
import info.nightscout.androidaps.plugins.PumpCommon.utils.HexDump;
import info.nightscout.androidaps.plugins.PumpCommon.utils.StringUtil;
import info.nightscout.androidaps.plugins.PumpMedtronic.comm.history.MedtronicHistoryDecoder;
import info.nightscout.androidaps.plugins.PumpMedtronic.comm.history.MedtronicHistoryEntry;
import info.nightscout.androidaps.plugins.PumpMedtronic.comm.history.RecordDecodeStatus;
import info.nightscout.androidaps.plugins.PumpMedtronic.data.dto.BasalProfile;
import info.nightscout.androidaps.plugins.PumpMedtronic.data.dto.BolusDTO;
import info.nightscout.androidaps.plugins.PumpMedtronic.data.dto.BolusWizardDTO;
import info.nightscout.androidaps.plugins.PumpMedtronic.data.dto.DailyTotalsDTO;
import info.nightscout.androidaps.plugins.PumpMedtronic.data.dto.TempBasalPair;
import info.nightscout.androidaps.plugins.PumpMedtronic.defs.MedtronicDeviceType;
import info.nightscout.androidaps.plugins.PumpMedtronic.defs.PumpBolusType;
@ -48,7 +49,6 @@ import info.nightscout.androidaps.plugins.PumpMedtronic.util.MedtronicUtil;
public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder {
private static final Logger LOG = LoggerFactory.getLogger(MedtronicPumpHistoryDecoder.class);
private static final String TAG = "MdtPump";
// PumpValuesWriter pumpValuesWriter = null;
@ -61,22 +61,10 @@ public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder {
public MedtronicPumpHistoryDecoder() {
super();
}
// public List<? extends MedtronicHistoryEntry> processPageAndCreateRecords(RawHistoryPage page) {
// List<Byte> dataClear = checkPage(page, false);
// return createRecords(dataClear);
// }
// public <E extends MedtronicHistoryEntry> List<E> processPageAndCreateRecords(RawHistoryPage rawHistoryPage,
// boolean partial, Class<E> clazz) {
//
// return null;
// }
public <E extends MedtronicHistoryEntry> List<E> createRecords(List<Byte> dataClear, Class<E> clazz) {
protected <E extends MedtronicHistoryEntry> List<E> createRecords(List<Byte> dataClear, Class<E> clazz) {
prepareStatistics();
int counter = 0;
@ -89,8 +77,8 @@ public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder {
int elementStart = 0;
if (dataClear.size() == 0) {
Log.e(TAG, "Empty page.");
// return;
LOG.error("Empty page.");
return outList;
}
do {
@ -107,7 +95,7 @@ public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder {
continue;
} else {
if (skipped != null) {
Log.v(TAG, " ... Skipped " + skipped);
LOG.debug(" ... Skipped " + skipped);
skipped = null;
}
}
@ -148,7 +136,7 @@ public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder {
listRawData.add(dataClear.get(counter));
counter++;
} catch (Exception ex) {
Log.e(TAG, "OpCode: " + HexDump.getCorrectHexValue((byte)opCode) + ", Invalid package: "
LOG.error("OpCode: " + HexDump.getCorrectHexValue((byte)opCode) + ", Invalid package: "
+ HexDump.toHexStringDisplayable(listRawData));
// throw ex;
incompletePacket = true;
@ -189,38 +177,16 @@ public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder {
RecordDecodeStatus decoded = decodeRecord(pe);
// if (pe.getEntryType() ==
// PumpHistoryEntryType.UnknownBasePacket)
// {
// decoded = RecordDecodeStatus.Unknown;
// }
// else
// {
// decoded = decodeRecord(pe);
// }
// System.out.println("Found entry: " + entryType.name() +
// " ["
// + bitUtils.getDebugByteListHex(listRawData) + "] ");
// FIXME
// if (!decoded)
// System.out.println("#" + record + " " + pe);
// if (decoded)
// LOG.info("#" + record + " " + pe);
// else
// LOG.warn("#" + record + " BAD: " + pe);
if ((decoded == RecordDecodeStatus.OK) || (decoded == RecordDecodeStatus.Ignored)) {
LOG.info("#" + record + " " + decoded.getDescription() + " " + pe);
Log.i(TAG, "#" + record + " " + decoded.getDescription() + " -- " + pe);
} else {
if (decoded == RecordDecodeStatus.WIP) {
LOG.warn("#" + record + " " + decoded.getDescription() + " " + pe);
Log.w(TAG, "#" + record + " " + decoded.getDescription() + " -- " + pe);
}
// if ((decoded == RecordDecodeStatus.OK) || (decoded == RecordDecodeStatus.Ignored)) {
// LOG.info("#" + record + " " + decoded.getDescription() + " " + pe);
// } else {
// LOG.warn("#" + record + " " + decoded.getDescription() + " " + pe);
// }
addToStatistics(pe, decoded, null);
record++;
@ -231,11 +197,6 @@ public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder {
}
}
// System.out.println("Counter: " + counter);
// if (counter > 100)
// break;
} while (counter < dataClear.size());
return outList;
@ -276,31 +237,39 @@ public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder {
}
// LOG.debug("decodeRecord: type={}", entry.getEntryType());
decodeDateTime(entry);
// decodeDateTime(entry);
switch (entry.getEntryType()) {
// not implemented
case ChangeBasalProfile_NewProfile:
case ChangeBasalProfile_OldProfile:
case SelectBasalProfile:
case DailyTotals522:
// case IanA8:
case DailyTotals522:
case DailyTotals523:
case DailyTotals512:
return RecordDecodeStatus.NotSupported;
case DailyTotals515:
return decodeDailyTotals(entry); // Not supported at the moment
case SelectBasalProfile:
return RecordDecodeStatus.Ignored; // Not supported at the moment
// WORK IN PROGRESS
// POSSIBLY READY
case ChangeBasalProfile_OldProfile:
case ChangeBasalProfile_NewProfile:
return decodeBasalProfile(entry);
case BasalProfileStart:
return decodeBasalProfileStart(entry);
// AAPS Implementation - Not yet done
// AAPS Implementation - OK entries
case ChangeTempBasalType:
case ChangeMaxBolus:
case ChangeMaxBasal:
case ClearSettings:
case SaveSettings:
return RecordDecodeStatus.OK;
// AAPS events (Tbr, Bolus)
// AAPS alerts
@ -316,14 +285,11 @@ public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder {
case UnabsorbedInsulin:
case BGReceived: // Ian3F: CGMS
case SensorAlert: // Ian08 CGMS
case ChangeTempBasalType:
case ChangeTimeFormat:
case ChangeReservoirWarningTime:
case ChangeBolusReminderEnable:
case ChangeBolusReminderTime:
case ChangeChildBlockEnable:
case ChangeMaxBolus:
case ChangeMaxBasal:
case BolusWizardEnabled:
case ChangeBGReminderOffset:
case ChangeAlarmClockTime:
@ -334,7 +300,6 @@ public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder {
case DeleteBolusReminderTime:
case SetAutoOff:
case SelfTest:
case ClearSettings:
case JournalEntryInsulinMarker:
case JournalEntryOtherMarker:
case ChangeBolusWizardSetup:
@ -347,7 +312,6 @@ public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder {
case ChangeSensorRateOfChangeAlertSetup:
case ChangeBolusScrollStepSize:
case BolusWizardChange:
case SaveSettings:
case ChangeVariableBolus:
case ChangeAudioBolus:
case ChangeBGReminderEnable:
@ -357,9 +321,9 @@ public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder {
case ChangeCarbUnits:
case ChangeWatchdogEnable:
case ChangeOtherDeviceID:
case ChangeWatchdogMarriageProfile:
case DeleteOtherDeviceID:
case ChangeCaptureEventEnable:
// case ChangeWatchdogMarriageProfile:
// case DeleteOtherDeviceID:
// case ChangeCaptureEventEnable:
case EventUnknown_MM522_0x45:
case EventUnknown_MM522_0x46:
case EventUnknown_MM522_0x47:
@ -381,6 +345,7 @@ public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder {
case EventUnknown_MM512_0x94:
case EventUnknown_MM522_0xE8:
case EventUnknown_0x4d:
case EventUnknown_MM522_0x25:
// LOG.debug(" -- ignored Pump Entry: " + entry.getEntryType().name());
return RecordDecodeStatus.Ignored;
@ -395,11 +360,11 @@ public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder {
return RecordDecodeStatus.OK;
case TempBasalDuration:
decodeTempBasal(entry);
// decodeTempBasal(entry);
return RecordDecodeStatus.OK;
case TempBasalRate:
decodeTempBasal(entry);
// decodeTempBasal(entry);
return RecordDecodeStatus.OK;
case Bolus:
@ -434,8 +399,6 @@ public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder {
// this.writeData(PumpBaseType.Event, PumpEventType.CartridgeRewind, entry.getATechDate());
return RecordDecodeStatus.OK;
case EventUnknown_MM522_0x05:
break;
case NoDeliveryAlarm:
// this.writeData(PumpBaseType.Alarm, PumpAlarms.NoDelivery, entry.getATechDate());
return RecordDecodeStatus.OK;
@ -448,6 +411,12 @@ public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder {
decodePrime(entry);
return RecordDecodeStatus.OK;
case EventUnknown_MM522_0x05:
return RecordDecodeStatus.Ignored;
case TempBasalCombined:
return RecordDecodeStatus.Ignored;
case None:
case UnknownBasePacket:
return RecordDecodeStatus.Error;
@ -465,11 +434,68 @@ public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder {
}
return RecordDecodeStatus.Error;
// return RecordDecodeStatus.Error;
}
private RecordDecodeStatus decodeDailyTotals(PumpHistoryEntry entry) {
entry.addDecodedData("Raw Data", ByteUtil.getHex(entry.getRawData()));
LOG.debug("{} - {}", entry.getEntryType().name(), ByteUtil.getHex(entry.getRawData()));
LOG.debug("{}", entry);
// byte[] data = new byte[] {
// 0x6D, (byte)0xA2, (byte)0x92, 0x05, 0x0C, 0x00, (byte)0xE8, 0x00, 0x00, 0x00, 0x00, 0x03, 0x18, 0x02,
// (byte)0xD4, 0x5B, 0x00, 0x44, 0x09, 0x00, 0x00, 0x00, 0x44, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x44, 0x64, 0x01, 0x00, 0x00, 0x00, 0x01, 0x0C, 0x00, (byte)0xE8, 0x00, 0x00, 0x00 };
// basal 18.1, bolus 1.7 manual = 1.7
// bg avg, bg low hi, number Bgs,
// Sen Avg, Sen Lo/Hi, Sens Cal/Data = 0/0,
// Insulin=19.8, Basal, Bolus, Carbs,
// Bolus=1.7, Fodd, Corr, Manual=1.7,
// Num bOlus=1, food/corr, Food+corr, manual bolus=1
DailyTotalsDTO totals = new DailyTotalsDTO(entry.getEntryType(), entry.getBody());
// System.out.println("Totals:" + totals);
// if (entry.getEntryType() == PumpHistoryEntryType.DailyTotals522) {
//
// // Daily
//
// byte body[] = entry.getBody();
// System.out.println("Totoals 522");
//
// for (int i = 0; i < body.length - 1; i++) {
//
// int j = ByteUtil.toInt(body[i], body[i + 1]);
//
// System.out.println(String.format(
// "index: %d, number=%d, del/40=%.3f, del/10=%.3f, singular=%d, sing_hex=%s", i, j, j / 40.0d,
// j / 10.0d, body[i], ByteUtil.getHex(body[i])));
//
// }
//
// }
return RecordDecodeStatus.WIP;
}
private RecordDecodeStatus decodeBasalProfile(PumpHistoryEntry entry) {
BasalProfile basalProfile = new BasalProfile(entry.getBody());
entry.addDecodedData("Object", basalProfile);
return RecordDecodeStatus.OK;
}
// private void decodeCalBGForPH(PumpHistoryEntry entry) {
// int high = (entry.getDatetime()[4] & 0x80) >> 7;
// int bg = bitUtils.toInt(high, getUnsignedInt(entry.getHead()[0]));
@ -571,7 +597,7 @@ public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder {
} else {
dto.bloodGlucose = (((body[1] & 0x0F) << 8) | entry.getHead()[0]);
dto.carbs = (int)body[0];
dto.carbRatio = new Float(body[2]);
dto.carbRatio = Float.valueOf(body[2]);
dto.insulinSensitivity = new Float(body[3]);
dto.bgTargetLow = (int)body[4];
dto.bgTargetHigh = (int)body[12];
@ -643,9 +669,9 @@ public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder {
bolus.setInsulinOnBoard(bitUtils.toInt(data[4], data[5]) / 40.0f);
bolus.setDuration(data[6] * 30);
} else {
bolus.setRequestedAmount(data[0] / 40.0f);
bolus.setDeliveredAmount(data[1] / 10.0f);
bolus.setDuration(data[2] * 30);
bolus.setRequestedAmount(ByteUtil.asUINT8(data[0]) / 40.0f);
bolus.setDeliveredAmount(ByteUtil.asUINT8(data[1]) / 10.0f);
bolus.setDuration(ByteUtil.asUINT8(data[2]) * 30);
}
bolus.setBolusType((bolus.getDuration() != null && (bolus.getDuration() > 0)) ? PumpBolusType.Extended
@ -682,6 +708,14 @@ public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder {
return;
}
decodeTempBasal(this.tbrPreviousRecord, entry);
tbrPreviousRecord = null;
}
public static void decodeTempBasal(PumpHistoryEntry tbrPreviousRecord, PumpHistoryEntry entry) {
PumpHistoryEntry tbrRate = null, tbrDuration = null;
if (entry.getEntryType() == PumpHistoryEntryType.TempBasalRate) {
@ -696,18 +730,6 @@ public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder {
tbrRate = tbrPreviousRecord;
}
// LOG.debug("Rate: " + tbrRate.toString());
// LOG.debug("Durration: " + tbrDuration.toString());
// if ((asUINT8(data[7]) >> 3) == 0) {
// mIsPercent = false;
// tbrRate = (double) (asUINT8(tbrRate.getRawData().get(1)) / 40.0;
// } else {
// mIsPercent = true;
// basalRate = asUINT8(data[1]);
// }
// FIXME
TempBasalPair tbr = new TempBasalPair(tbrRate.getHead()[0], tbrDuration.getHead()[0], (ByteUtil.asUINT8(tbrRate
.getDatetime()[4]) >> 3) == 0);
@ -717,7 +739,12 @@ public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder {
entry.addDecodedData("Object", tbr);
tbrPreviousRecord = null;
entry.addDecodedData("Rate 1: ", tbrRate.getHead()[0] * 0.025);
entry.addDecodedData("Rate 2: ", ByteUtil.asUINT8(tbrRate.getHead()[0]) * 0.025d);
entry.addDecodedData("Rate 1.b: ", tbrRate.getHead()[0]);
entry.addDecodedData("Rate 2.b: ", ByteUtil.asUINT8(tbrRate.getHead()[0]));
entry.addDecodedData("Rate 3: ", (ByteUtil.asUINT8(tbrRate.getHead()[0])) / 40.0d);
}
@ -743,13 +770,16 @@ public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder {
LocalDateTime atdate = new LocalDateTime(year, month, dayOfMonth, hour, minutes, seconds);
entry.setLocalDateTime(atdate);
entry.setLocalDateTime(atdate); // TODO remove
entry.setAtechDateTime(DateTimeUtil.toATechDate(year, month, dayOfMonth, hour, minutes, seconds));
} else if (entry.getDateTimeLength() == 2) {
int low = ByteUtil.asUINT8(dt[0]) & 0x1F;
int mhigh = (ByteUtil.asUINT8(dt[0]) & 0xE0) >> 4;
int mlow = (ByteUtil.asUINT8(dt[1]) & 0x80) >> 7;
int month = mhigh + mlow;
int dayOfMonth = low + 1;
// int dayOfMonth = low + 1;
int dayOfMonth = dt[0] & 0x1F;
int year = 2000 + (ByteUtil.asUINT8(dt[1]) & 0x7F);
// LocalDate rval = new LocalDate(year, month, dayOfMonth);
@ -758,7 +788,21 @@ public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder {
// int month = (((dt[0] & 0xE0) >> 4) + ((dt[1] & 0x80) >> 7));
// int year = fix2DigitYear(dt[1] & 0x3F);
LocalDateTime atdate = new LocalDateTime(year, month, dayOfMonth, 0, 0);
LocalDateTime atdate = null;
LOG.debug("DT: {} {} {}", year, month, dayOfMonth);
if (dayOfMonth == 32) {
// FIXME remove
LOG.debug("Entry: {} = [{}] {}", entry.getEntryType().name(), ByteUtil.getHex(entry.getRawData()),
entry);
}
if (entry.getEntryType() == PumpHistoryEntryType.EndResultTotals) {
atdate = new LocalDateTime(year, month, dayOfMonth, 23, 59, 59);
} else {
atdate = new LocalDateTime(year, month, dayOfMonth, 0, 0);
}
entry.setLocalDateTime(atdate);
} else {

View file

@ -6,6 +6,8 @@ import org.joda.time.LocalDateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.annotations.Expose;
import info.nightscout.androidaps.plugins.PumpCommon.utils.HexDump;
import info.nightscout.androidaps.plugins.PumpCommon.utils.StringUtil;
import info.nightscout.androidaps.plugins.PumpMedtronic.comm.history.MedtronicHistoryEntry;
@ -35,9 +37,9 @@ public class PumpHistoryEntry extends MedtronicHistoryEntry {
private static Logger LOG = LoggerFactory.getLogger(PumpHistoryEntry.class);
@Expose
private PumpHistoryEntryType entryType;
private Integer opCode; // this is set only when we have unknown entry...
// private LocalDateTime timeOfEntry;
private int offset;
@ -77,15 +79,6 @@ public class PumpHistoryEntry extends MedtronicHistoryEntry {
}
// public PumpTimeStampedRecord getHistoryEntryDetails() {
// return historyEntryDetails;
// }
//
//
// public void setHistoryEntryDetails(PumpTimeStampedRecord historyEntryDetails) {
// this.historyEntryDetails = historyEntryDetails;
// }
public int getOffset() {
return offset;
}
@ -137,11 +130,16 @@ public class PumpHistoryEntry extends MedtronicHistoryEntry {
return this.dateTime.isAfter(dateTimeIn);
}
public boolean isAfter(long atechDateTime) {
return atechDateTime > this.atechDateTime;
}
public static class Comparator implements java.util.Comparator<PumpHistoryEntry> {
@Override
public int compare(PumpHistoryEntry o1, PumpHistoryEntry o2) {
return o2.dateTime.compareTo(o1.dateTime);
return (int)(o2.atechDateTime - o1.atechDateTime);
}
}
}

View file

@ -61,8 +61,8 @@ public enum PumpHistoryEntryType // implements CodeEnum
LowBattery(0x19, "LowBattery"), //
BatteryActivity(0x1a, "Battery Activity"), //
SetAutoOff(0x1b, "SetAutoOff"), //
PumpSuspend(0x1e, "PumpSuspend"), //
PumpResume(0x1f, "PumpResume"), //
PumpSuspend(0x1e, "Pump Suspend"), //
PumpResume(0x1f, "Pump Resume"), //
SelfTest(0x20, "SelfTest"), //
Rewind(0x21, "Rewind"), //
ClearSettings(0x22, "ClearSettings"), // 8?
@ -78,7 +78,7 @@ public enum PumpHistoryEntryType // implements CodeEnum
EventUnknown_MM512_0x2f(0x2f), //
ChangeBGReminderOffset(0x31), //
ChangeAlarmClockTime(0x32), //
TempBasalRate(0x33, "TempBasal", 2, 5, 1), //
TempBasalRate(0x33, "Temp Basal Rate", 2, 5, 1), //
LowReservoir(0x34), //
ChangeMeterId(0x36), //
@ -88,7 +88,7 @@ public enum PumpHistoryEntryType // implements CodeEnum
EventUnknown_MM512_0x3b(0x3b), //
ChangeParadigmLinkID(0x3c, 2, 5, 14), // V3 ? V6: 2,5,14
BGReceived(0x3f, "BGReceived", 2, 5, 3), // Ian3F
BGReceived(0x3f, "BG Received", 2, 5, 3), // Ian3F
JournalEntryMealMarker(0x40, 2, 5, 2), //
JournalEntryExerciseMarker(0x41, 2, 5, 1), // ?? JournalEntryExerciseMarkerPumpEvent
JournalEntryInsulinMarker(0x42, 2, 5, 1), // ?? InsulinMarkerEvent
@ -116,7 +116,7 @@ public enum PumpHistoryEntryType // implements CodeEnum
ChangeBolusScrollStepSize(0x57), //
// V4
// Andy58(0x58, "Unknown", 13, 5, 0), // TODO is this one really there ???
// Andy58(0x58, "Unknown", 13, 5, 0), // TO DO is this one really there ???
BolusWizardChange(0x5a, "BolusWizard", 2, 5, 117), // V2: 522+[B=143]
BolusWizardBolusEstimate(0x5b, "BolusWizardBolusEstimate", 2, 5, 13), // 15 // V2: 523+[B=15]
@ -125,7 +125,7 @@ public enum PumpHistoryEntryType // implements CodeEnum
ChangeVariableBolus(0x5e), //
ChangeAudioBolus(0x5f, "EasyBolusEnabled"), // V3 ?
ChangeBGReminderEnable(0x60), // questionable60
ChangeAlarmClockEnable((byte)0x61), //
ChangeAlarmClockEnable(0x61), //
ChangeTempBasalType((byte)0x62), // ChangeTempBasalTypePumpEvent
ChangeAlarmNotifyMode(0x63), //
ChangeTimeFormat(0x64), //
@ -134,10 +134,10 @@ public enum PumpHistoryEntryType // implements CodeEnum
ChangeBolusReminderTime((byte)0x67, 2, 5, 2), // 9
DeleteBolusReminderTime((byte)0x68, 2, 5, 2), // 9
BolusReminder(0x69, 2, 5, 0), // Ian69
DeleteAlarmClockTime(0x6a, "DeleteAlarmClockTime", 2, 5, 7), // 14
DeleteAlarmClockTime(0x6a, "Delete Alarm Clock Time", 2, 5, 7), // 14
DailyTotals512(0x6c, "Daily Totals 512", 0, 0, 36), //
DailyTotals522(0x6d, "Daily Totals 522", 1, 2, 41), // // hack1(0x6d, "hack1", 46, 5, 0),
DailyTotals515(0x6c, "Daily Totals 515", 0, 0, 36), //
DailyTotals522(0x6d, "Daily Totals 522", 1, 2, 41), // // hack1(0x6d, "hack1", 46, 5, 0), // 1,2,41
DailyTotals523(0x6e, "Daily Totals 523", 1, 2, 49), // 1102014-03-17T00:00:00
ChangeCarbUnits((byte)0x6f), //
@ -147,12 +147,12 @@ public enum PumpHistoryEntryType // implements CodeEnum
ChangeWatchdogEnable((byte)0x7c), //
ChangeOtherDeviceID((byte)0x7d, 2, 5, 30), //
ChangeWatchdogMarriageProfile((byte)0x81, 2, 5, 5), // 12
DeleteOtherDeviceID((byte)0x82, 2, 5, 5), //
ChangeCaptureEventEnable((byte)0x83), //
// ChangeWatchdogMarriageProfile(0x81, 2, 5, 5), // 12
// DeleteOtherDeviceID(0x82, 2, 5, 5), //
// ChangeCaptureEventEnable(0x83), //
EventUnknown_MM512_0x88((byte)0x88), //
EventUnknown_MM512_0x94((byte)0x94), //
EventUnknown_MM512_0x88(0x88), //
EventUnknown_MM512_0x94(0x94), //
// IanA8(0xA8, "xx", 10, 5, 0), //
// Andy90(0x90, "Unknown", 7, 5, 0),
@ -165,6 +165,12 @@ public enum PumpHistoryEntryType // implements CodeEnum
EventUnknown_MM522_0xE8(0xe8, 2, 5, 25), //
ReadOtherDevicesIDs(0xF0, ""), // ?
readCaptureEventEnabled(0xF1), // ?
changeCaptureEventEnable(0xF2), // ?
readOtherDevicesStatus(0xF3), // ?
TempBasalCombined(0xFE, "TempBasalCombined"), //
UnknownBasePacket(0xFF, "Unknown Base Packet");
// private PumpHistoryEntryType(String description, List<Integer> opCode,
@ -263,6 +269,37 @@ public enum PumpHistoryEntryType // implements CodeEnum
// }
//
public static boolean isAAPSRelevantEntry(PumpHistoryEntryType entryType) {
return (entryType == PumpHistoryEntryType.Bolus || // Treatments
entryType == PumpHistoryEntryType.TempBasalRate || //
entryType == PumpHistoryEntryType.TempBasalDuration || //
entryType == PumpHistoryEntryType.Prime || // Pump Status Change
entryType == PumpHistoryEntryType.PumpSuspend || //
entryType == PumpHistoryEntryType.PumpResume || //
entryType == PumpHistoryEntryType.Rewind || //
entryType == PumpHistoryEntryType.NoDeliveryAlarm || // no delivery
entryType == PumpHistoryEntryType.BasalProfileStart || //
entryType == PumpHistoryEntryType.ChangeTime || // Time Change
entryType == PumpHistoryEntryType.NewTimeSet || //
entryType == PumpHistoryEntryType.SelectBasalProfile || // Settings
entryType == PumpHistoryEntryType.ClearSettings || //
entryType == PumpHistoryEntryType.SaveSettings || //
entryType == PumpHistoryEntryType.ChangeMaxBolus || //
entryType == PumpHistoryEntryType.ChangeMaxBasal || //
entryType == PumpHistoryEntryType.ChangeTempBasalType || //
entryType == PumpHistoryEntryType.ChangeBasalProfile_NewProfile || // Basal profile
entryType == PumpHistoryEntryType.DailyTotals515 || // Daily Totals
entryType == PumpHistoryEntryType.DailyTotals522 || //
entryType == PumpHistoryEntryType.DailyTotals523 || //
entryType == PumpHistoryEntryType.EndResultTotals);
}
public static boolean isRelevantEntry() {
return true;
}

View file

@ -8,6 +8,8 @@ import org.joda.time.LocalDateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.plugins.PumpMedtronic.MedtronicPumpPlugin;
/**
* Created by andy on 9/23/18.
*/
@ -48,7 +50,7 @@ public class PumpHistoryResult {
public void addHistoryEntries(List<PumpHistoryEntry> entries) {
this.unprocessedEntries = entries;
LOG.debug("PumpHistoryResult. Unprocessed entries: {}", entries);
LOG.debug("PumpHistoryResult. Unprocessed entries: {}", MedtronicPumpPlugin.gsonInstance.toJson(entries));
processEntries();
}
@ -115,8 +117,15 @@ public class PumpHistoryResult {
public PumpHistoryEntry getLatestEntry() {
if (this.validEntries == null || this.validEntries.size() == 0)
return null;
else
else {
return this.validEntries.get(0);
// PumpHistoryEntry pumpHistoryEntry = this.validEntries.get(0);
//
// if (pumpHistoryEntry.getEntryType() == PumpHistoryEntryType.EndResultTotals)
// return pumpHistoryEntry;
// else
// return this.validEntries.get(1);
}
}

View file

@ -45,15 +45,15 @@ public class MedtronicUIPostprocessor {
switch (uiTask.commandType) {
case SetBasalProfileSTD: {
Boolean response = (Boolean) uiTask.returnData;
Boolean response = (Boolean)uiTask.returnData;
if (response) {
BasalProfile basalProfile = (BasalProfile) uiTask.getParameter(0);
BasalProfile basalProfile = (BasalProfile)uiTask.getParameter(0);
pumpStatus.basalsByHour = basalProfile.getProfilesByHour();
}
}
break;
break;
case GetBasalProfileSTD: {
BasalProfile basalProfile = (BasalProfile)uiTask.returnData;
@ -119,7 +119,7 @@ public class MedtronicUIPostprocessor {
// no postprocessing
default:
LOG.warn("Post-processing not implemented for {}.", uiTask.commandType.name());
LOG.trace("Post-processing not implemented for {}.", uiTask.commandType.name());
}
@ -135,15 +135,14 @@ public class MedtronicUIPostprocessor {
long currentTimeMillis = System.currentTimeMillis();
long diff = Math.abs(d1.getTime() - currentTimeMillis);
LOG.warn("Pump Time: " + ldt + ", DeviceTime=" + d1 + //
// ", epoch: " + d1.getTime() + ", current: " + currentTimeMillis + //
LOG.debug("Pump Time: " + ldt + ", DeviceTime=" + d1 + //
", diff: " + diff / 1000 + " s");
if (diff >= 10 * 60 * 1000) {
LOG.debug("Pump clock needs update, pump time: " + ldt + " (" + ldt + ")");
LOG.warn("Pump clock needs update, pump time: " + ldt + " (" + ldt + ")");
sendNotification(MedtronicNotificationType.PumpWrongTimeUrgent);
} else if (diff >= 4 * 60 * 1000) {
LOG.debug("Pump clock needs update, pump time: " + ldt + " (" + ldt + ")");
LOG.warn("Pump clock needs update, pump time: " + ldt + " (" + ldt + ")");
sendNotification(MedtronicNotificationType.PumpWrongTimeNormal);
}

View file

@ -1,10 +1,12 @@
package info.nightscout.androidaps.plugins.PumpMedtronic.comm.ui;
import org.joda.time.LocalDateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.plugins.PumpMedtronic.comm.MedtronicCommunicationManager;
import info.nightscout.androidaps.plugins.PumpMedtronic.comm.history.pump.PumpHistoryEntry;
import info.nightscout.androidaps.plugins.PumpMedtronic.data.dto.BasalProfile;
import info.nightscout.androidaps.plugins.PumpMedtronic.data.dto.TempBasalPair;
import info.nightscout.androidaps.plugins.PumpMedtronic.defs.MedtronicCommandType;
@ -125,6 +127,12 @@ public class MedtronicUITask {
}
break;
case GetHistoryData: {
returnData = communicationManager.getPumpHistory((PumpHistoryEntry)parameters[0],
(LocalDateTime)parameters[1]);
}
break;
default: {
LOG.warn("This commandType is not supported (yet) - {}.", commandType);
// invalid = true;

View file

@ -1,11 +1,25 @@
package info.nightscout.androidaps.plugins.PumpMedtronic.data;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.joda.time.LocalDateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Splitter;
import info.nightscout.androidaps.plugins.PumpCommon.utils.DateTimeUtil;
import info.nightscout.androidaps.plugins.PumpMedtronic.MedtronicPumpPlugin;
import info.nightscout.androidaps.plugins.PumpMedtronic.comm.history.pump.MedtronicPumpHistoryDecoder;
import info.nightscout.androidaps.plugins.PumpMedtronic.comm.history.pump.PumpHistoryEntry;
import info.nightscout.androidaps.plugins.PumpMedtronic.comm.history.pump.PumpHistoryEntryType;
import info.nightscout.androidaps.plugins.PumpMedtronic.comm.history.pump.PumpHistoryResult;
//import info.nightscout.androidaps.plugins.PumpMedtronic.MedtronicPumpPlugin;
/**
* Created by andy on 10/12/18.
@ -13,43 +27,263 @@ import info.nightscout.androidaps.plugins.PumpMedtronic.comm.history.pump.PumpHi
public class MedtronicHistoryData {
List<PumpHistoryEntry> history = null;
private boolean suspended = false;
private boolean relevantConfigurationChanged = false;
private boolean basalProfileChanged = true;
private static final Logger LOG = LoggerFactory.getLogger(MedtronicHistoryData.class);
private List<PumpHistoryEntry> allHistory = null;
private List<PumpHistoryEntry> newHistory = null;
private LocalDateTime lastHistoryRecordTime;
private boolean isInit = false;
private static final int OLD_HISTORY_SIZE = 50;
public MedtronicHistoryData() {
this.history = new ArrayList<>();
this.allHistory = new ArrayList<>();
}
// TODO
public boolean isSuspended() {
return suspended;
/**
* Add New History entries
*
* @param result PumpHistoryResult instance
*/
public void addNewHistory(PumpHistoryResult result) {
this.newHistory = result.getValidEntries();
showLogs("List of history (before filtering): ", MedtronicPumpPlugin.gsonInstance.toJson(this.newHistory));
}
public static void showLogs(String header, String data) {
if (header != null) {
LOG.debug(header);
}
for (final String token : Splitter.fixedLength(3500).split(data)) {
LOG.debug("{}", token);
}
}
public void filterNewEntries() {
List<PumpHistoryEntry> newHistory2 = new ArrayList<>();
List<PumpHistoryEntry> TBRs = new ArrayList<>();
LocalDateTime localDateTime = new LocalDateTime();
for (PumpHistoryEntry pumpHistoryEntry : newHistory) {
PumpHistoryEntryType type = pumpHistoryEntry.getEntryType();
if (PumpHistoryEntryType.isAAPSRelevantEntry(type)) {
if (type == PumpHistoryEntryType.TempBasalRate || type == PumpHistoryEntryType.TempBasalDuration) {
TBRs.add(pumpHistoryEntry);
} else {
if (type == PumpHistoryEntryType.EndResultTotals) {
if (!DateTimeUtil.isSameDay(localDateTime, pumpHistoryEntry.getLocalDateTime())) {
newHistory2.add(pumpHistoryEntry);
}
} else {
newHistory2.add(pumpHistoryEntry);
}
}
}
}
TBRs = processTBRs(TBRs);
newHistory2.addAll(TBRs);
this.newHistory = newHistory2;
sort(this.newHistory);
LOG.debug("New History entries found: {}", this.newHistory.size());
showLogs("List of history (after filtering): ", MedtronicPumpPlugin.gsonInstance.toJson(this.newHistory));
}
public void finalizeNewHistoryRecords() {
List<PumpHistoryEntry> filteredListByLastRecord = getFilteredListByLastRecord((PumpHistoryEntryType)null);
if (filteredListByLastRecord.size() == 0)
return;
List<PumpHistoryEntry> outList = new ArrayList<>();
if (allHistory.size() > OLD_HISTORY_SIZE) {
for (int i = 0; i < OLD_HISTORY_SIZE; i++) {
outList.add(allHistory.get(i));
}
}
outList.addAll(filteredListByLastRecord);
this.allHistory.clear();
this.allHistory.addAll(outList);
this.sort(this.allHistory);
}
// TODO implement logic here fror config changes
public boolean hasRelevantConfigurationChanged() {
return relevantConfigurationChanged;
return getStateFromFilteredList( //
PumpHistoryEntryType.SelectBasalProfile, //
PumpHistoryEntryType.ClearSettings, //
PumpHistoryEntryType.SaveSettings, //
PumpHistoryEntryType.ChangeMaxBolus, //
PumpHistoryEntryType.ChangeMaxBasal, //
PumpHistoryEntryType.ChangeTempBasalType);
}
public void resetRelevantConfigurationChanged() {
relevantConfigurationChanged = false;
// TODO This logic might not be working correctly
public boolean isPumpSuspended(Boolean wasPumpSuspended) {
if (wasPumpSuspended == null) { // suspension status not known
List<PumpHistoryEntry> items = getFilteredItems(PumpHistoryEntryType.Bolus, //
PumpHistoryEntryType.TempBasalCombined, //
PumpHistoryEntryType.Prime, //
PumpHistoryEntryType.PumpSuspend, //
PumpHistoryEntryType.PumpResume, //
PumpHistoryEntryType.Rewind, //
PumpHistoryEntryType.NoDeliveryAlarm, //
PumpHistoryEntryType.BasalProfileStart);
if (items.size() == 0)
return wasPumpSuspended == null ? false : wasPumpSuspended;
PumpHistoryEntry pumpHistoryEntry = items.get(0);
return !(pumpHistoryEntry.getEntryType() == PumpHistoryEntryType.TempBasalCombined || //
pumpHistoryEntry.getEntryType() == PumpHistoryEntryType.BasalProfileStart || //
pumpHistoryEntry.getEntryType() == PumpHistoryEntryType.Bolus || //
pumpHistoryEntry.getEntryType() == PumpHistoryEntryType.PumpResume);
} else {
List<PumpHistoryEntry> items = getFilteredItems(PumpHistoryEntryType.Bolus, //
PumpHistoryEntryType.TempBasalCombined, //
PumpHistoryEntryType.Prime, //
PumpHistoryEntryType.PumpSuspend, //
PumpHistoryEntryType.PumpResume, //
PumpHistoryEntryType.Rewind, //
PumpHistoryEntryType.NoDeliveryAlarm, //
PumpHistoryEntryType.BasalProfileStart);
if (wasPumpSuspended) {
if (items.size() == 0)
return wasPumpSuspended == null ? false : wasPumpSuspended;
PumpHistoryEntry pumpHistoryEntry = items.get(0);
if (pumpHistoryEntry.getEntryType() == PumpHistoryEntryType.TempBasalCombined || //
pumpHistoryEntry.getEntryType() == PumpHistoryEntryType.BasalProfileStart || //
pumpHistoryEntry.getEntryType() == PumpHistoryEntryType.Bolus || //
pumpHistoryEntry.getEntryType() == PumpHistoryEntryType.PumpResume)
return false;
else
return true;
} else {
PumpHistoryEntry pumpHistoryEntry = items.get(0);
if (pumpHistoryEntry.getEntryType() == PumpHistoryEntryType.NoDeliveryAlarm || //
pumpHistoryEntry.getEntryType() == PumpHistoryEntryType.PumpSuspend || //
pumpHistoryEntry.getEntryType() == PumpHistoryEntryType.Prime)
return true;
}
}
// FIXME
return false;
}
// TODO implement logic to see if Basalrates changed from last time
public List<PumpHistoryEntry> getTDDs() {
return getFilteredListByLastRecord(PumpHistoryEntryType.EndResultTotals);
}
// FIXME remove
public List<PumpHistoryEntry> getTDDs2() {
return getFilteredListByLastRecord(PumpHistoryEntryType.DailyTotals515, PumpHistoryEntryType.DailyTotals522,
PumpHistoryEntryType.DailyTotals523);
}
public List<PumpHistoryEntry> getTreatments() {
return getFilteredListByLastRecord( //
PumpHistoryEntryType.Bolus, //
PumpHistoryEntryType.TempBasalCombined);
}
/*
* entryType == PumpHistoryEntryType.Bolus || // Treatments
* entryType == PumpHistoryEntryType.TempBasalRate || //
* entryType == PumpHistoryEntryType.TempBasalDuration || //
*
* entryType == PumpHistoryEntryType.Prime || // Pump Status Change
* entryType == PumpHistoryEntryType.PumpSuspend || //
* entryType == PumpHistoryEntryType.PumpResume || //
* entryType == PumpHistoryEntryType.Rewind || //
* entryType == PumpHistoryEntryType.NoDeliveryAlarm || // no delivery
* entryType == PumpHistoryEntryType.BasalProfileStart || //
*
* entryType == PumpHistoryEntryType.ChangeTime || // Time Change
* entryType == PumpHistoryEntryType.NewTimeSet || //
*
* entryType == PumpHistoryEntryType.SelectBasalProfile || // Settings
* entryType == PumpHistoryEntryType.ClearSettings || //
* entryType == PumpHistoryEntryType.SaveSettings || //
* entryType == PumpHistoryEntryType.ChangeMaxBolus || //
* entryType == PumpHistoryEntryType.ChangeMaxBasal || //
* entryType == PumpHistoryEntryType.ChangeTempBasalType || //
*
* entryType == PumpHistoryEntryType.ChangeBasalProfile_NewProfile || // Basal profile
*
* entryType == PumpHistoryEntryType.DailyTotals512 || // Daily Totals
* entryType == PumpHistoryEntryType.DailyTotals522 || //
* entryType == PumpHistoryEntryType.DailyTotals523 || //
* entryType == PumpHistoryEntryType.EndResultTotals
*/
public boolean hasBasalProfileChanged() {
return basalProfileChanged;
return getStateFromFilteredList(PumpHistoryEntryType.ChangeBasalProfile_NewProfile);
}
public void resetBasalProfileChanged() {
basalProfileChanged = true; // FIXME when this works this should reset to false
public boolean hasPumpTimeChanged() {
return getStateFromFilteredList(PumpHistoryEntryType.NewTimeSet, //
PumpHistoryEntryType.ChangeTime);
}
@ -59,8 +293,103 @@ public class MedtronicHistoryData {
}
public LocalDateTime getLastHistoryRecordTime() {
public void setIsInInit(boolean init) {
this.isInit = init;
}
return lastHistoryRecordTime;
// HELPER METHODS
private void sort(List<PumpHistoryEntry> list) {
Collections.sort(list, new PumpHistoryEntry.Comparator());
}
private List<PumpHistoryEntry> processTBRs(List<PumpHistoryEntry> TBRs_Input) {
List<PumpHistoryEntry> TBRs = new ArrayList<>();
Map<String, PumpHistoryEntry> map = new HashMap<>();
for (PumpHistoryEntry pumpHistoryEntry : TBRs_Input) {
if (map.containsKey(pumpHistoryEntry.DT)) {
MedtronicPumpHistoryDecoder.decodeTempBasal(map.get(pumpHistoryEntry.DT), pumpHistoryEntry);
pumpHistoryEntry.setEntryType(PumpHistoryEntryType.TempBasalCombined);
TBRs.add(pumpHistoryEntry);
map.remove(pumpHistoryEntry.DT);
} else {
map.put(pumpHistoryEntry.DT, pumpHistoryEntry);
}
}
return TBRs;
}
private List<PumpHistoryEntry> getFilteredItems(PumpHistoryEntryType... entryTypes) {
return getFilteredItems(this.newHistory, entryTypes);
}
private List<PumpHistoryEntry> getFilteredListByLastRecord(PumpHistoryEntryType... entryTypes) {
if (this.lastHistoryRecordTime == null) {
return getFilteredItems(entryTypes);
} else {
return getFilteredItems(this.lastHistoryRecordTime, entryTypes);
}
}
private boolean getStateFromFilteredList(PumpHistoryEntryType... entryTypes) {
if (isInit) {
return false;
} else {
List<PumpHistoryEntry> filteredItems = getFilteredItems(entryTypes);
return filteredItems.size() > 0;
}
}
private List<PumpHistoryEntry> getFilteredItems(LocalDateTime dateTime, PumpHistoryEntryType... entryTypes) {
PumpHistoryResult phr = new PumpHistoryResult(null, dateTime);
return getFilteredItems(phr.getValidEntries(), entryTypes);
}
private List<PumpHistoryEntry> getFilteredItems(List<PumpHistoryEntry> inList, PumpHistoryEntryType... entryTypes) {
// LOG.debug("InList: " + inList.size());
List<PumpHistoryEntry> outList = new ArrayList<>();
if (inList != null && inList.size() > 0) {
for (PumpHistoryEntry pumpHistoryEntry : inList) {
if (entryTypes != null) {
for (PumpHistoryEntryType pumpHistoryEntryType : entryTypes) {
if (pumpHistoryEntry.getEntryType() == pumpHistoryEntryType) {
outList.add(pumpHistoryEntry);
break;
}
}
} else {
outList.add(pumpHistoryEntry);
}
}
}
// LOG.debug("OutList: " + outList.size());
return outList;
}
public List<PumpHistoryEntry> getNewHistoryEntries() {
return this.newHistory;
}
}

View file

@ -7,6 +7,8 @@ import org.joda.time.Instant;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.annotations.Expose;
import info.nightscout.androidaps.plugins.PumpCommon.defs.PumpType;
import info.nightscout.androidaps.plugins.PumpCommon.utils.ByteUtil;
import info.nightscout.androidaps.plugins.PumpCommon.utils.FabricUtil;
@ -18,23 +20,24 @@ import info.nightscout.androidaps.plugins.PumpMedtronic.util.MedtronicUtil;
* There are three basal profiles stored on the pump. (722 only?) They are all parsed the same, the user just has 3 to
* choose from: Standard, A, and B
* <p>
* The byte array seems to be 21 three byte entries long, plus a zero? If the profile is completely empty, it should
* have one entry: [0,0,0x3F] (?) The first entry of [0,0,0] marks the end of the used entries.
* The byte array is 48 times three byte entries long, plus a zero? If the profile is completely empty, it should have
* one entry: [0,0,0x3F]. The first entry of [0,0,0] marks the end of the used entries.
* <p>
* Each entry is assumed to span from the specified start time to the start time of the next entry, or to midnight if
* there are no more entries.
* <p>
* Individual entries are of the form [r,z,m] where r is the rate (in 0.025 U increments) z is zero (?) m is the start
* time-of-day for the basal rate period (in 30 minute increments?)
* time-of-day for the basal rate period (in 30 minute increments)
*/
public class BasalProfile {
public static final int MAX_RAW_DATA_SIZE = (48 * 3) + 1;
// private static final String TAG = "BasalProfile";
private static final Logger LOG = LoggerFactory.getLogger(BasalProfile.class);
public static final int MAX_RAW_DATA_SIZE = (48 * 3) + 1;
private static final boolean DEBUG_BASALPROFILE = false;
protected byte[] mRawData; // store as byte array to make transport (via parcel) easier
List<BasalProfileEntry> listEntries;
@Expose
private byte[] mRawData; // store as byte array to make transport (via parcel) easier
private List<BasalProfileEntry> listEntries;
public BasalProfile() {
@ -286,15 +289,6 @@ public class BasalProfile {
}
}
// StringBuilder sb = new StringBuilder();
//
// for (int i = 0; i < 24; i++) {
// sb.append("" + i + "=" + basalByHour[i]);
// sb.append("\n");
// }
//
// System.out.println("Basal Profile: \n" + sb.toString());
return basalByHour;
}

View file

@ -1,5 +1,7 @@
package info.nightscout.androidaps.plugins.PumpMedtronic.data.dto;
import com.google.gson.annotations.Expose;
import info.nightscout.androidaps.plugins.PumpMedtronic.defs.BatteryType;
/**
@ -8,6 +10,7 @@ import info.nightscout.androidaps.plugins.PumpMedtronic.defs.BatteryType;
public class BatteryStatusDTO {
@Expose
public BatteryStatusType batteryStatusType;
public double voltage;

View file

@ -1,5 +1,7 @@
package info.nightscout.androidaps.plugins.PumpMedtronic.data.dto;
import com.google.gson.annotations.Expose;
import info.nightscout.androidaps.plugins.PumpCommon.utils.StringUtil;
import info.nightscout.androidaps.plugins.PumpMedtronic.defs.PumpBolusType;
@ -26,10 +28,15 @@ import info.nightscout.androidaps.plugins.PumpMedtronic.defs.PumpBolusType;
public class BolusDTO extends PumpTimeStampedRecord {
@Expose
private Float requestedAmount;
@Expose
private Float deliveredAmount;
@Expose
private Float immediateAmount; // when Multiwave this is used
@Expose
private Integer duration;
@Expose
private PumpBolusType bolusType;
private Float insulinOnBoard;

View file

@ -0,0 +1,147 @@
package info.nightscout.androidaps.plugins.PumpMedtronic.data.dto;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.MoreObjects;
import info.nightscout.androidaps.plugins.PumpCommon.utils.ByteUtil;
import info.nightscout.androidaps.plugins.PumpMedtronic.comm.history.pump.PumpHistoryEntryType;
/**
* Created by andy on 11/3/18.
*/
public class DailyTotalsDTO {
private static final Logger LOG = LoggerFactory.getLogger(DailyTotalsDTO.class);
// bg avg, bg low hi, number Bgs,
// Sen Avg, Sen Lo/Hi, Sens Cal/Data = 0/0,
// Insulin=19.8[8,9], Basal[10,11], Bolus[13,14], Carbs,
// Bolus=1.7, Fodd, Corr, Manual=1.7,
// Num bOlus=1, food/corr, Food+corr, manual bolus=1
Double bgAvg;
Double bgLow;
Double bgHigh;
Integer bgCount;
Double sensorAvg;
Double sensorMin;
Double sensorMax;
Integer sensorCalcCount;
Integer sensorDataCount;
Double insulinTotal;
Double insulinBasal;
Double insulinBolus;
Double insulinCarbs;
Double bolusTotal;
Double bolusFood;
Double bolusCorrection;
Double bolusManual;
Integer bolusCount;
Integer bolusCountFoodOrCorr;
// Integer bolusCountCorr;
Integer bolusCountFoodAndCorr;
Integer bolusCountManual;
public DailyTotalsDTO(PumpHistoryEntryType entryType, byte[] data) {
switch (entryType) {
case DailyTotals515:
decodeData512(data);
break;
case DailyTotals522:
decodeData522(data);
break;
case DailyTotals523:
decodeData523(data);
break;
default:
break;
}
}
private void decodeData512(byte[] data) {
LOG.debug("Can't decode DailyTotals512: Body={}", ByteUtil.getHex(data));
}
// bg avg, bg low hi, number Bgs,
// Sen Avg, Sen Lo/Hi, Sens Cal/Data = 0/0,
// Insulin=19.8[8,9], Basal[10,11], Bolus[13,14], Carbs,
// Bolus=1.7[18,19], Fodd, Corr, Manual=1.7[27,28],
// Num bOlus=1, food/corr, Food+corr, manual bolus=1
private void decodeData522(byte[] data) {
// Double bgAvg;
// Double bgLow;
// Double bgHigh;
// Integer bgCount;
//
// Double sensorAvg;
// Double sensorMin;
// Double sensorMax;
// Integer sensorCalcCount;
// Integer sensorDataCount;
this.insulinTotal = ByteUtil.toInt(data[8], data[9]) / 40.0d;
this.insulinBasal = ByteUtil.toInt(data[10], data[11]) / 40.0d;
this.insulinBolus = ByteUtil.toInt(data[13], data[14]) / 40.0d;
// Double insulinCarbs;
this.bolusTotal = ByteUtil.toInt(data[17], data[18], data[19]) / 40.0d;
this.bolusFood = ByteUtil.toInt(data[21], data[22]) / 40.0d;
this.bolusCorrection = ByteUtil.toInt(data[23], data[24], data[25]) / 40.0d;
this.bolusManual = ByteUtil.toInt(data[26], data[27], data[28]) / 40.0d;
bolusCount = ByteUtil.asUINT8(data[30]);
bolusCountFoodOrCorr = ByteUtil.asUINT8(data[31]);
// Integer bolusCountCorr;
bolusCountFoodAndCorr = ByteUtil.asUINT8(data[32]);
bolusCountManual = ByteUtil.asUINT8(data[33]);
LOG.debug("{}", toString());
}
private void decodeData523(byte[] data) {
LOG.debug("Can't decode DailyTotals523: Body={}", ByteUtil.getHex(data));
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this) //
.add("bgAvg", bgAvg) //
.add("bgLow", bgLow) //
.add("bgHigh", bgHigh) //
.add("bgCount", bgCount) //
.add("sensorAvg", sensorAvg) //
.add("sensorMin", sensorMin) //
.add("sensorMax", sensorMax) //
.add("sensorCalcCount", sensorCalcCount) //
.add("sensorDataCount", sensorDataCount) //
.add("insulinTotal", insulinTotal) //
.add("insulinBasal", insulinBasal) //
.add("insulinBolus", insulinBolus) //
.add("insulinCarbs", insulinCarbs) //
.add("bolusTotal", bolusTotal) //
.add("bolusFood", bolusFood) //
.add("bolusCorrection", bolusCorrection) //
.add("bolusManual", bolusManual) //
.add("bolusCount", bolusCount) //
.add("bolusCountFoodOrCorr", bolusCountFoodOrCorr) //
.add("bolusCountFoodAndCorr", bolusCountFoodAndCorr) //
.add("bolusCountManual", bolusCountManual) //
.toString();
}
}

View file

@ -6,6 +6,9 @@ import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.annotations.Expose;
import info.nightscout.androidaps.plugins.PumpCommon.utils.ByteUtil;
import info.nightscout.androidaps.plugins.PumpMedtronic.util.MedtronicUtil;
/**
@ -17,8 +20,11 @@ public class TempBasalPair {
private static final Logger LOG = LoggerFactory.getLogger(TempBasalPair.class);
private double insulinRate = 0.0;
@Expose
private double insulinRate = 0.0d;
@Expose
private int durationMinutes = 0;
@Expose
private boolean isPercent = false;
@ -34,10 +40,12 @@ public class TempBasalPair {
* @param isPercent
*/
public TempBasalPair(byte rateByte, int startTimeByte, boolean isPercent) {
int rateInt = ByteUtil.asUINT8(rateByte);
if (isPercent)
this.insulinRate = rateByte;
else
this.insulinRate = rateByte * 0.025;
this.insulinRate = rateInt * 0.025;
this.durationMinutes = startTimeByte * 30;
this.isPercent = isPercent;
}

View file

@ -0,0 +1,19 @@
package info.nightscout.androidaps.plugins.PumpMedtronic.defs;
import info.nightscout.androidaps.plugins.Actions.defs.CustomActionType;
/**
* Created by andy on 11/3/18.
*/
public enum MedtronicCustomActionType implements CustomActionType {
WakeUpAndTune()
;
@Override
public String getKey() {
return this.name();
}
}

View file

@ -65,6 +65,8 @@ public class MedtronicPumpStatus extends PumpStatus {
private boolean isFrequencyUS = false;
private Map<String, PumpType> medtronicPumpMap = null;
private Map<String, MedtronicDeviceType> medtronicDeviceTypeMap = null;
private RileyLinkTargetFrequency targetFrequency;
private boolean targetFrequencyChanged = false;
public MedtronicPumpStatus(PumpDescription pumpDescription) {
@ -189,9 +191,15 @@ public class MedtronicPumpStatus extends PumpStatus {
this.pumpFrequency = pumpFrequency;
this.isFrequencyUS = pumpFrequency.equals(frequencies[0]);
RileyLinkUtil.setRileyLinkTargetFrequency(this.isFrequencyUS ? //
RileyLinkTargetFrequency newTargetFrequency = this.isFrequencyUS ? //
RileyLinkTargetFrequency.Medtronic_US
: RileyLinkTargetFrequency.Medtronic_WorldWide);
: RileyLinkTargetFrequency.Medtronic_WorldWide;
if (targetFrequency == newTargetFrequency) {
RileyLinkUtil.setRileyLinkTargetFrequency(newTargetFrequency);
targetFrequencyChanged = true;
}
}
}
@ -228,7 +236,9 @@ public class MedtronicPumpStatus extends PumpStatus {
// LOG.debug("MedtronicPumpStatus::startService");
if (serialChanged && !inPreInit && MedtronicUtil.getMedtronicService() != null) {
boolean ready = (!inPreInit && MedtronicUtil.getMedtronicService() != null);
if (serialChanged && ready) {
MedtronicUtil.getMedtronicService().setPumpIDString(this.serialNumber); // short operation
serialChanged = false;
}
@ -238,7 +248,13 @@ public class MedtronicPumpStatus extends PumpStatus {
rileyLinkAddressChanged = false;
}
return (rileyLinkAddressChanged == false && serialChanged == false);
if (targetFrequencyChanged && !inPreInit && MedtronicUtil.getMedtronicService() != null) {
RileyLinkUtil.setRileyLinkTargetFrequency(targetFrequency);
RileyLinkUtil.getRileyLinkCommunicationManager().refreshRileyLinkTargetFrequency();
targetFrequencyChanged = false;
}
return (!rileyLinkAddressChanged && !serialChanged && !targetFrequencyChanged);
}

View file

@ -92,9 +92,9 @@ public class RileyLinkMedtronicService extends RileyLinkService {
MainApp.gs(R.string.medtronic_pump_frequency_us)).equals(MainApp.gs(R.string.medtronic_pump_frequency_us));
if (hasUSFrequency)
this.rileyLinkTargetFrequency = RileyLinkTargetFrequency.Medtronic_US;
RileyLinkUtil.setRileyLinkTargetFrequency(RileyLinkTargetFrequency.Medtronic_US);
else
this.rileyLinkTargetFrequency = RileyLinkTargetFrequency.Medtronic_WorldWide;
RileyLinkUtil.setRileyLinkTargetFrequency(RileyLinkTargetFrequency.Medtronic_WorldWide);
}
@ -120,7 +120,7 @@ public class RileyLinkMedtronicService extends RileyLinkService {
RileyLinkUtil.setRileyLinkBLE(rileyLinkBLE);
// init rileyLinkCommunicationManager
medtronicCommunicationManager = new MedtronicCommunicationManager(context, rfspy, rileyLinkTargetFrequency);
medtronicCommunicationManager = new MedtronicCommunicationManager(context, rfspy);
}

View file

@ -219,24 +219,6 @@ public class MedtronicUtil extends RileyLinkUtil {
}
// @Deprecated
// public static void sendNotification(int resourceId, int notificationUrgencyType) {
// Notification notification = new Notification( //
// Notification.MEDTRONIC_PUMP_ALARM, //
// MainApp.gs(resourceId), //
// notificationUrgencyType);
// MainApp.bus().post(new EventNewNotification(notification));
// }
// @Deprecated
// public static void sendNotification(int resourceId, int notificationUrgencyType, Object... parameters) {
// Notification notification = new Notification( //
// Notification.MEDTRONIC_PUMP_ALARM, //
// MainApp.gs(resourceId, parameters), //
// notificationUrgencyType);
// MainApp.bus().post(new EventNewNotification(notification));
// }
public static byte[] buildCommandPayload(MessageType commandType, byte[] parameters) {
return buildCommandPayload(commandType.getValue(), parameters);
}
@ -463,6 +445,7 @@ public class MedtronicUtil extends RileyLinkUtil {
if (currentCommand != null)
historyRileyLink.add(new RLHistoryItem(currentCommand));
}

View file

@ -1,14 +1,16 @@
package info.nightscout.androidaps.plugins.PumpVirtual;
import android.os.SystemClock;
import com.squareup.otto.Subscribe;
import java.util.List;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import android.os.SystemClock;
import com.squareup.otto.Subscribe;
import info.nightscout.androidaps.BuildConfig;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.MainApp;
@ -26,6 +28,8 @@ import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.interfaces.PumpDescription;
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.Actions.defs.CustomAction;
import info.nightscout.androidaps.plugins.Actions.defs.CustomActionType;
import info.nightscout.androidaps.plugins.ConfigBuilder.ProfileFunctions;
import info.nightscout.androidaps.plugins.NSClientInternal.NSUpload;
import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
@ -41,6 +45,7 @@ import info.nightscout.utils.SP;
* Created by mike on 05.08.2016.
*/
public class VirtualPumpPlugin extends PluginBase implements PumpInterface {
private Logger log = LoggerFactory.getLogger(L.PUMP);
Integer batteryPercent = 50;
@ -51,16 +56,12 @@ public class VirtualPumpPlugin extends PluginBase implements PumpInterface {
private long lastDataTime = 0;
private PumpDescription pumpDescription = new PumpDescription();
public VirtualPumpPlugin() {
super(new PluginDescription()
.mainType(PluginType.PUMP)
.fragmentClass(VirtualPumpFragment.class.getName())
.pluginName(R.string.virtualpump)
.shortName(R.string.virtualpump_shortname)
.preferencesId(R.xml.pref_virtualpump)
.neverVisible(Config.NSCLIENT)
.description(R.string.description_pump_virtual)
);
super(new PluginDescription().mainType(PluginType.PUMP).fragmentClass(VirtualPumpFragment.class.getName())
.pluginName(R.string.virtualpump).shortName(R.string.virtualpump_shortname)
.preferencesId(R.xml.pref_virtualpump).neverVisible(Config.NSCLIENT)
.description(R.string.description_pump_virtual));
pumpDescription.isBolusCapable = true;
pumpDescription.bolusStep = 0.1d;
@ -80,7 +81,6 @@ public class VirtualPumpPlugin extends PluginBase implements PumpInterface {
pumpDescription.tempDurationStep30mAllowed = true;
pumpDescription.tempMaxDuration = 24 * 60;
pumpDescription.isSetBasalProfileCapable = true;
pumpDescription.basalStep = 0.01d;
pumpDescription.basalMinimumRate = 0.01d;
@ -91,6 +91,7 @@ public class VirtualPumpPlugin extends PluginBase implements PumpInterface {
pumpDescription.is30minBasalRatesCapable = true;
}
public static VirtualPumpPlugin getPlugin() {
if (plugin == null)
plugin = new VirtualPumpPlugin();
@ -98,19 +99,23 @@ public class VirtualPumpPlugin extends PluginBase implements PumpInterface {
return plugin;
}
private void loadFakingStatus() {
fromNSAreCommingFakedExtendedBoluses = SP.getBoolean(R.string.key_fromNSAreCommingFakedExtendedBoluses, false);
}
public boolean getFakingStatus() {
return fromNSAreCommingFakedExtendedBoluses;
}
public void setFakingStatus(boolean newStatus) {
fromNSAreCommingFakedExtendedBoluses = newStatus;
SP.putBoolean(R.string.key_fromNSAreCommingFakedExtendedBoluses, fromNSAreCommingFakedExtendedBoluses);
}
@Override
protected void onStart() {
super.onStart();
@ -118,62 +123,74 @@ public class VirtualPumpPlugin extends PluginBase implements PumpInterface {
refreshConfiguration();
}
@Override
protected void onStop() {
MainApp.bus().unregister(this);
}
@Subscribe
public void onStatusEvent(final EventPreferenceChange s) {
if (s.isChanged(R.string.key_virtualpump_type))
refreshConfiguration();
}
@Override
public boolean isFakingTempsByExtendedBoluses() {
return (Config.NSCLIENT) && fromNSAreCommingFakedExtendedBoluses;
}
@Override
public PumpEnactResult loadTDDs() {
//no result, could read DB in the future?
// no result, could read DB in the future?
return new PumpEnactResult();
}
@Override
public boolean isInitialized() {
return true;
}
@Override
public boolean isSuspended() {
return false;
}
@Override
public boolean isBusy() {
return false;
}
@Override
public boolean isConnected() {
return true;
}
@Override
public boolean isConnecting() {
return false;
}
@Override
public boolean isHandshakeInProgress() {
return false;
}
@Override
public void finishHandshaking() {
}
@Override
public void connect(String reason) {
if (!Config.NSCLIENT)
@ -181,40 +198,48 @@ public class VirtualPumpPlugin extends PluginBase implements PumpInterface {
lastDataTime = System.currentTimeMillis();
}
@Override
public void disconnect(String reason) {
}
@Override
public void stopConnecting() {
}
@Override
public void getPumpStatus() {
lastDataTime = System.currentTimeMillis();
}
@Override
public PumpEnactResult setNewBasalProfile(Profile profile) {
lastDataTime = System.currentTimeMillis();
// Do nothing here. we are using ConfigBuilderPlugin.getPlugin().getActiveProfile().getProfile();
PumpEnactResult result = new PumpEnactResult();
result.success = true;
Notification notification = new Notification(Notification.PROFILE_SET_OK, MainApp.gs(R.string.profile_set_ok), Notification.INFO, 60);
Notification notification = new Notification(Notification.PROFILE_SET_OK, MainApp.gs(R.string.profile_set_ok),
Notification.INFO, 60);
MainApp.bus().post(new EventNewNotification(notification));
return result;
}
@Override
public boolean isThisProfileSet(Profile profile) {
return true;
}
@Override
public long lastDataTime() {
return lastDataTime;
}
@Override
public double getBaseBasalRate() {
Profile profile = ProfileFunctions.getInstance().getProfile();
@ -241,7 +266,7 @@ public class VirtualPumpPlugin extends PluginBase implements PumpInterface {
SystemClock.sleep(200);
EventOverviewBolusProgress bolusingEvent = EventOverviewBolusProgress.getInstance();
bolusingEvent.status = String.format(MainApp.gs(R.string.bolusdelivering), delivering);
bolusingEvent.percent = Math.min((int) (delivering / detailedBolusInfo.insulin * 100), 100);
bolusingEvent.percent = Math.min((int)(delivering / detailedBolusInfo.insulin * 100), 100);
MainApp.bus().post(bolusingEvent);
delivering += 0.1d;
}
@ -252,25 +277,26 @@ public class VirtualPumpPlugin extends PluginBase implements PumpInterface {
MainApp.bus().post(bolusingEvent);
SystemClock.sleep(1000);
if (L.isEnabled(L.PUMPCOMM))
log.debug("Delivering treatment insulin: " + detailedBolusInfo.insulin + "U carbs: " + detailedBolusInfo.carbs + "g " + result);
log.debug("Delivering treatment insulin: " + detailedBolusInfo.insulin + "U carbs: "
+ detailedBolusInfo.carbs + "g " + result);
MainApp.bus().post(new EventVirtualPumpUpdateGui());
lastDataTime = System.currentTimeMillis();
TreatmentsPlugin.getPlugin().addToHistoryTreatment(detailedBolusInfo, false);
return result;
}
@Override
public void stopBolusDelivering() {
}
@Override
public PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes, Profile profile, boolean enforceNew) {
TemporaryBasal tempBasal = new TemporaryBasal()
.date(System.currentTimeMillis())
.absolute(absoluteRate)
.duration(durationInMinutes)
.source(Source.USER);
@Override
public PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes, Profile profile,
boolean enforceNew) {
TemporaryBasal tempBasal = new TemporaryBasal().date(System.currentTimeMillis()).absolute(absoluteRate)
.duration(durationInMinutes).source(Source.USER);
PumpEnactResult result = new PumpEnactResult();
result.success = true;
result.enacted = true;
@ -286,13 +312,12 @@ public class VirtualPumpPlugin extends PluginBase implements PumpInterface {
return result;
}
@Override
public PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes, Profile profile, boolean enforceNew) {
TemporaryBasal tempBasal = new TemporaryBasal()
.date(System.currentTimeMillis())
.percent(percent)
.duration(durationInMinutes)
.source(Source.USER);
public PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes, Profile profile,
boolean enforceNew) {
TemporaryBasal tempBasal = new TemporaryBasal().date(System.currentTimeMillis()).percent(percent)
.duration(durationInMinutes).source(Source.USER);
PumpEnactResult result = new PumpEnactResult();
result.success = true;
result.enacted = true;
@ -309,17 +334,15 @@ public class VirtualPumpPlugin extends PluginBase implements PumpInterface {
return result;
}
@Override
public PumpEnactResult setExtendedBolus(Double insulin, Integer durationInMinutes) {
PumpEnactResult result = cancelExtendedBolus();
if (!result.success)
return result;
ExtendedBolus extendedBolus = new ExtendedBolus()
.date(System.currentTimeMillis())
.insulin(insulin)
.durationInMinutes(durationInMinutes)
.source(Source.USER);
ExtendedBolus extendedBolus = new ExtendedBolus().date(System.currentTimeMillis()).insulin(insulin)
.durationInMinutes(durationInMinutes).source(Source.USER);
result.success = true;
result.enacted = true;
result.bolusDelivered = insulin;
@ -334,6 +357,7 @@ public class VirtualPumpPlugin extends PluginBase implements PumpInterface {
return result;
}
@Override
public PumpEnactResult cancelTempBasal(boolean force) {
PumpEnactResult result = new PumpEnactResult();
@ -344,7 +368,7 @@ public class VirtualPumpPlugin extends PluginBase implements PumpInterface {
result.enacted = true;
TemporaryBasal tempStop = new TemporaryBasal().date(System.currentTimeMillis()).source(Source.USER);
TreatmentsPlugin.getPlugin().addToHistoryTempBasal(tempStop);
//tempBasal = null;
// tempBasal = null;
if (L.isEnabled(L.PUMPCOMM))
log.debug("Canceling temp basal: " + result);
MainApp.bus().post(new EventVirtualPumpUpdateGui());
@ -353,6 +377,7 @@ public class VirtualPumpPlugin extends PluginBase implements PumpInterface {
return result;
}
@Override
public PumpEnactResult cancelExtendedBolus() {
PumpEnactResult result = new PumpEnactResult();
@ -372,6 +397,7 @@ public class VirtualPumpPlugin extends PluginBase implements PumpInterface {
return result;
}
@Override
public JSONObject getJSONStatus(Profile profile, String profileName) {
long now = System.currentTimeMillis();
@ -415,21 +441,25 @@ public class VirtualPumpPlugin extends PluginBase implements PumpInterface {
return pump;
}
@Override
public String deviceID() {
return "VirtualPump";
}
@Override
public PumpDescription getPumpDescription() {
return pumpDescription;
}
@Override
public String shortStatus(boolean veryShort) {
return "Virtual Pump";
}
public PumpType getPumpType() {
return pumpType;
}
@ -455,4 +485,15 @@ public class VirtualPumpPlugin extends PluginBase implements PumpInterface {
}
@Override
public List<CustomAction> getCustomActions() {
return null;
}
@Override
public PumpEnactResult executeCustomAction(CustomActionType customActionType) {
return null;
}
}

View file

@ -29,15 +29,15 @@ import info.nightscout.androidaps.events.EventNewBG;
import info.nightscout.androidaps.events.EventTempBasalChange;
import info.nightscout.androidaps.plugins.Common.SubscriberFragment;
import info.nightscout.androidaps.plugins.ConfigBuilder.ProfileFunctions;
import info.nightscout.androidaps.plugins.NSClientInternal.NSUpload;
import info.nightscout.androidaps.plugins.NSClientInternal.UploadQueue;
import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin;
import info.nightscout.utils.DateUtil;
import info.nightscout.utils.DecimalFormatter;
import info.nightscout.utils.FabricPrivacy;
import info.nightscout.androidaps.plugins.NSClientInternal.NSUpload;
public class TreatmentsTemporaryBasalsFragment extends SubscriberFragment {
RecyclerView recyclerView;
LinearLayoutManager llm;
@ -49,16 +49,20 @@ public class TreatmentsTemporaryBasalsFragment extends SubscriberFragment {
Intervals<TemporaryBasal> tempBasalList;
RecyclerViewAdapter(Intervals<TemporaryBasal> tempBasalList) {
this.tempBasalList = tempBasalList;
}
@Override
public TempBasalsViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.treatments_tempbasals_item, viewGroup, false);
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.treatments_tempbasals_item,
viewGroup, false);
return new TempBasalsViewHolder(v);
}
@Override
public void onBindViewHolder(TempBasalsViewHolder holder, int position) {
TemporaryBasal tempBasal = tempBasalList.getReversed(position);
@ -87,7 +91,8 @@ public class TreatmentsTemporaryBasalsFragment extends SubscriberFragment {
if (tempBasal.isAbsolute) {
Profile profile = ProfileFunctions.getInstance().getProfile(tempBasal.date);
if (profile != null) {
holder.absolute.setText(DecimalFormatter.to0Decimal(tempBasal.tempBasalConvertedToAbsolute(tempBasal.date, profile), " U/h"));
holder.absolute.setText(DecimalFormatter.to2Decimal(
tempBasal.tempBasalConvertedToAbsolute(tempBasal.date, profile), " U/h"));
holder.percent.setText("");
} else {
holder.absolute.setText(MainApp.gs(R.string.noprofile));
@ -115,17 +120,20 @@ public class TreatmentsTemporaryBasalsFragment extends SubscriberFragment {
holder.remove.setTag(tempBasal);
}
@Override
public int getItemCount() {
return tempBasalList.size();
}
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
}
public class TempBasalsViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
CardView cv;
TextView date;
TextView duration;
@ -140,33 +148,36 @@ public class TreatmentsTemporaryBasalsFragment extends SubscriberFragment {
TextView ph;
TextView ns;
TempBasalsViewHolder(View itemView) {
super(itemView);
cv = (CardView) itemView.findViewById(R.id.tempbasals_cardview);
date = (TextView) itemView.findViewById(R.id.tempbasals_date);
duration = (TextView) itemView.findViewById(R.id.tempbasals_duration);
absolute = (TextView) itemView.findViewById(R.id.tempbasals_absolute);
percent = (TextView) itemView.findViewById(R.id.tempbasals_percent);
realDuration = (TextView) itemView.findViewById(R.id.tempbasals_realduration);
netRatio = (TextView) itemView.findViewById(R.id.tempbasals_netratio);
netInsulin = (TextView) itemView.findViewById(R.id.tempbasals_netinsulin);
iob = (TextView) itemView.findViewById(R.id.tempbasals_iob);
extendedFlag = (TextView) itemView.findViewById(R.id.tempbasals_extendedflag);
ph = (TextView) itemView.findViewById(R.id.pump_sign);
ns = (TextView) itemView.findViewById(R.id.ns_sign);
remove = (TextView) itemView.findViewById(R.id.tempbasals_remove);
cv = (CardView)itemView.findViewById(R.id.tempbasals_cardview);
date = (TextView)itemView.findViewById(R.id.tempbasals_date);
duration = (TextView)itemView.findViewById(R.id.tempbasals_duration);
absolute = (TextView)itemView.findViewById(R.id.tempbasals_absolute);
percent = (TextView)itemView.findViewById(R.id.tempbasals_percent);
realDuration = (TextView)itemView.findViewById(R.id.tempbasals_realduration);
netRatio = (TextView)itemView.findViewById(R.id.tempbasals_netratio);
netInsulin = (TextView)itemView.findViewById(R.id.tempbasals_netinsulin);
iob = (TextView)itemView.findViewById(R.id.tempbasals_iob);
extendedFlag = (TextView)itemView.findViewById(R.id.tempbasals_extendedflag);
ph = (TextView)itemView.findViewById(R.id.pump_sign);
ns = (TextView)itemView.findViewById(R.id.ns_sign);
remove = (TextView)itemView.findViewById(R.id.tempbasals_remove);
remove.setOnClickListener(this);
remove.setPaintFlags(remove.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);
}
@Override
public void onClick(View v) {
final TemporaryBasal tempBasal = (TemporaryBasal) v.getTag();
final TemporaryBasal tempBasal = (TemporaryBasal)v.getTag();
switch (v.getId()) {
case R.id.tempbasals_remove:
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle(MainApp.gs(R.string.confirmation));
builder.setMessage(MainApp.gs(R.string.removerecord) + "\n" + DateUtil.dateAndTimeString(tempBasal.date));
builder.setMessage(MainApp.gs(R.string.removerecord) + "\n"
+ DateUtil.dateAndTimeString(tempBasal.date));
builder.setPositiveButton(MainApp.gs(R.string.ok), (dialog, id) -> {
final String _id = tempBasal._id;
if (NSUpload.isIdValid(_id)) {
@ -185,20 +196,21 @@ public class TreatmentsTemporaryBasalsFragment extends SubscriberFragment {
}
}
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.treatments_tempbasals_fragment, container, false);
recyclerView = (RecyclerView) view.findViewById(R.id.tempbasals_recyclerview);
recyclerView = (RecyclerView)view.findViewById(R.id.tempbasals_recyclerview);
recyclerView.setHasFixedSize(true);
llm = new LinearLayoutManager(view.getContext());
recyclerView.setLayoutManager(llm);
RecyclerViewAdapter adapter = new RecyclerViewAdapter(TreatmentsPlugin.getPlugin().getTemporaryBasalsFromHistory());
RecyclerViewAdapter adapter = new RecyclerViewAdapter(TreatmentsPlugin.getPlugin()
.getTemporaryBasalsFromHistory());
recyclerView.setAdapter(adapter);
tempBasalTotalView = (TextView) view.findViewById(R.id.tempbasals_totaltempiob);
tempBasalTotalView = (TextView)view.findViewById(R.id.tempbasals_totaltempiob);
context = getContext();
@ -206,22 +218,26 @@ public class TreatmentsTemporaryBasalsFragment extends SubscriberFragment {
return view;
}
@Subscribe
public void onStatusEvent(final EventTempBasalChange ignored) {
updateGUI();
}
@Subscribe
public void onStatusEvent(final EventNewBG ignored) {
updateGUI();
}
@Override
protected void updateGUI() {
Activity activity = getActivity();
if (activity != null)
activity.runOnUiThread(() -> {
recyclerView.swapAdapter(new RecyclerViewAdapter(TreatmentsPlugin.getPlugin().getTemporaryBasalsFromHistory()), false);
recyclerView.swapAdapter(new RecyclerViewAdapter(TreatmentsPlugin.getPlugin()
.getTemporaryBasalsFromHistory()), false);
IobTotal tempBasalsCalculation = TreatmentsPlugin.getPlugin().getLastCalculationTempBasals();
if (tempBasalsCalculation != null)
tempBasalTotalView.setText(DecimalFormatter.to2Decimal(tempBasalsCalculation.basaliob, " U"));

View file

@ -1,20 +1,58 @@
package info.nightscout.androidaps.plugins.PumpMedtronic.data.dto;
import static org.powermock.api.mockito.PowerMockito.when;
import junit.framework.Assert;
import org.apache.commons.lang3.StringUtils;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import info.AAPSMocker;
import info.SPMocker;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.db.DatabaseHelper;
import info.nightscout.androidaps.interfaces.PumpDescription;
import info.nightscout.androidaps.plugins.PumpCommon.defs.PumpType;
import info.nightscout.androidaps.plugins.PumpMedtronic.driver.MedtronicPumpStatus;
import info.nightscout.androidaps.plugins.PumpMedtronic.util.MedtronicUtil;
import info.nightscout.utils.DateUtil;
import info.nightscout.utils.SP;
import info.nightscout.utils.T;
/**
* Created by andy on 6/16/18.
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest({ MainApp.class, DatabaseHelper.class, DateUtil.class, SP.class })
public class BasalProfileUTest {
// MainApp mainApp = new MainApp();
@Before
public void initMocking() {
AAPSMocker.mockMainApp();
AAPSMocker.mockStrings();
AAPSMocker.mockDatabaseHelper();
SPMocker.prepareMock();
PowerMockito.mockStatic(DateUtil.class);
when(DateUtil.now()).thenReturn(1514766900000L + T.mins(1).msecs());
}
@Test
public void getProfilesByHour() throws Exception {
MedtronicUtil.setPumpStatus(new MedtronicPumpStatus(new PumpDescription()));
MedtronicUtil.getPumpStatus().pumpType = PumpType.Medtronic_522_722;
PumpType pumpType = MedtronicUtil.getPumpStatus().pumpType;
BasalProfile basalProfile = new BasalProfile();
byte[] data = { //
0x48, 0x00, 0x00, 0x40, 0x00, 0x02, 0x38, 0x00, 0x04, 0x3A, 0x00, 0x06, 0x32, 0x00, 0x0C, 0x26, 0x00, //

View file

@ -24,6 +24,13 @@ CGMS [not in plan for now]:
AAPS-Medtronic
==============
- ? history: TDD query
history retrive doesn't show whats happening
datetime parsimg problem
Invalid entry:
Entry: EndResultTotals = [0x07 0x00 0x00 0x05 0xFA 0xBF 0x12] PumpHistoryRecord [type=EndResultTotals [7 , 0x07], DT: x , length=5,2,0(7), head=00 00 05 FA , datetime=BF 12 , rawData=07 00 00 05 FA BF 12 ]
- history: - integrate
- basal change code
@ -126,4 +133,62 @@ Bugs:
+ TBR (554) ?
+ Remaining Insulin [554]
+ Get Basal profile returns just part of profile
+ Set TBR problem (after Bolus fixes)
+ Set TBR problem (after Bolus fixes)
========================================================================================================
None(0, "None", 1, 0, 0), // Bolus(0x01, "Bolus", 4, 5, 4), // 4,5,0 -> 4,5,4 Bolus(0x01, "Bolus", 2, 5, 4),
// Thear
Bolus(0x01, "Bolus", 4, DateFormat.LongDate, 0), // 523+[H=8]
TempBasalRate(0x33, "TempBasal", 2, 5, 1), //
TempBasalDuration(0x16, "TempBasalDuration"), //
// Status changes
Prime(0x03, "Prime", 5, 5, 0), //
PumpSuspend(0x1e, "PumpSuspend"), //
PumpResume(0x1f, "PumpResume"), //
Rewind(0x21, "Rewind"), //
// time change
ChangeTime(0x17, "ChangeTime"), //
NewTimeSet(0x18, "NewTimeSet"), //
// settings
ClearSettings(0x22, "ClearSettings"), // 8?
SaveSettings(0x5d), //
SelectBasalProfile(0x14, "SelectBasalProfile"), //
ChangeMaxBolus(0x24), // 8?
ChangeMaxBasal(0x2c), //
ChangeTempBasalType((byte)0x62), // ChangeTempBasalTypePumpEvent
// basal profile
//ChangeBasalProfile_OldProfile(0x08, 2, 5, 145), // // V1: 2,5,42 V2:2,5,145; V4: V5
ChangeBasalProfile_NewProfile(0x09, 2, 5, 145), //
// Daily Totals
DailyTotals512(0x6c, "Daily Totals 512", 0, 0, 36), //
DailyTotals522(0x6d, "Daily Totals 522", 1, 2, 41), // // hack1(0x6d, "hack1", 46, 5, 0),
DailyTotals523(0x6e, "Daily Totals 523", 1, 2, 49), // 1102014-03-17T00:00:00
ChangeVariableBolus(0x5e), //
EndResultTotals(0x07, "ResultTotals", 5, 2, 0), // V1: 5/5/41 V2: 5,2,3 V3, 5,2,0 V5: 7/10(523)
BasalProfileStart(0x7b, 2, 5, 3), // // 722