From 253c2a34e52bec0cfda7734878c64490cba2c758 Mon Sep 17 00:00:00 2001 From: Milos Kozak Date: Wed, 24 May 2017 18:24:23 +0200 Subject: [PATCH 001/952] combo plugin skeleton --- .../info/nightscout/androidaps/Config.java | 1 + .../info/nightscout/androidaps/MainApp.java | 2 + .../androidaps/PreferencesActivity.java | 7 + .../plugins/PumpCombo/ComboFragment.java | 74 +++++ .../plugins/PumpCombo/ComboPlugin.java | 252 ++++++++++++++++++ .../events/EventComboPumpUpdateGUI.java | 8 + .../main/res/layout/combopump_fragment.xml | 20 ++ app/src/main/res/values/strings.xml | 2 + app/src/main/res/xml/pref_combo.xml | 9 + 9 files changed, 375 insertions(+) create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboFragment.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/events/EventComboPumpUpdateGUI.java create mode 100644 app/src/main/res/layout/combopump_fragment.xml create mode 100644 app/src/main/res/xml/pref_combo.xml diff --git a/app/src/main/java/info/nightscout/androidaps/Config.java b/app/src/main/java/info/nightscout/androidaps/Config.java index e6c06583c9..7f3aad2f93 100644 --- a/app/src/main/java/info/nightscout/androidaps/Config.java +++ b/app/src/main/java/info/nightscout/androidaps/Config.java @@ -15,6 +15,7 @@ public class Config { public static final boolean NSCLIENT = BuildConfig.NSCLIENTOLNY; + public static final boolean COMBO = true && BuildConfig.PUMPDRIVERS; public static final boolean DANAR = true && BuildConfig.PUMPDRIVERS; public static final boolean DANARv2 = true && BuildConfig.PUMPDRIVERS; diff --git a/app/src/main/java/info/nightscout/androidaps/MainApp.java b/app/src/main/java/info/nightscout/androidaps/MainApp.java index 9dff7b0b5a..17bf5ebb4c 100644 --- a/app/src/main/java/info/nightscout/androidaps/MainApp.java +++ b/app/src/main/java/info/nightscout/androidaps/MainApp.java @@ -40,6 +40,7 @@ import info.nightscout.androidaps.plugins.ProfileCircadianPercentage.CircadianPe import info.nightscout.androidaps.plugins.ProfileLocal.LocalProfileFragment; import info.nightscout.androidaps.plugins.ProfileNS.NSProfileFragment; import info.nightscout.androidaps.plugins.ProfileSimple.SimpleProfileFragment; +import info.nightscout.androidaps.plugins.PumpCombo.ComboFragment; import info.nightscout.androidaps.plugins.PumpDanaR.DanaRFragment; import info.nightscout.androidaps.plugins.PumpDanaR.services.DanaRExecutionService; import info.nightscout.androidaps.plugins.PumpDanaRKorean.DanaRKoreanFragment; @@ -106,6 +107,7 @@ public class MainApp extends Application { if (Config.DANAR) pluginsList.add(DanaRFragment.getPlugin()); if (Config.DANAR) pluginsList.add(DanaRKoreanFragment.getPlugin()); if (Config.DANARv2) pluginsList.add(DanaRv2Fragment.getPlugin()); + if (Config.COMBO) pluginsList.add(ComboFragment.getPlugin()); pluginsList.add(CareportalFragment.getPlugin()); if (Config.MDI) pluginsList.add(MDIPlugin.getPlugin()); if (Config.VIRTUALPUMP) pluginsList.add(VirtualPumpPlugin.getInstance()); diff --git a/app/src/main/java/info/nightscout/androidaps/PreferencesActivity.java b/app/src/main/java/info/nightscout/androidaps/PreferencesActivity.java index c5d8769639..71c1445298 100644 --- a/app/src/main/java/info/nightscout/androidaps/PreferencesActivity.java +++ b/app/src/main/java/info/nightscout/androidaps/PreferencesActivity.java @@ -14,6 +14,7 @@ import android.preference.PreferenceManager; import info.nightscout.androidaps.events.EventPreferenceChange; import info.nightscout.androidaps.events.EventRefreshGui; import info.nightscout.androidaps.interfaces.PluginBase; +import info.nightscout.androidaps.plugins.PumpCombo.ComboPlugin; import info.nightscout.androidaps.plugins.PumpDanaR.BluetoothDevicePreference; import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPlugin; import info.nightscout.androidaps.plugins.PumpDanaRKorean.DanaRKoreanPlugin; @@ -135,6 +136,12 @@ public class PreferencesActivity extends PreferenceActivity implements SharedPre addPreferencesFromResource(R.xml.pref_danarprofile); } } + if (Config.COMBO) { + ComboPlugin comboPlugin = (ComboPlugin) MainApp.getSpecificPlugin(ComboPlugin.class); + if (comboPlugin.isEnabled(PluginBase.PUMP)) { + addPreferencesFromResource(R.xml.pref_combo); + } + } VirtualPumpPlugin virtualPumpPlugin = (VirtualPumpPlugin) MainApp.getSpecificPlugin(VirtualPumpPlugin.class); if (virtualPumpPlugin != null && virtualPumpPlugin.isEnabled(PluginBase.PUMP)) { addPreferencesFromResource(R.xml.pref_virtualpump); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboFragment.java new file mode 100644 index 0000000000..49fc90c6ae --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboFragment.java @@ -0,0 +1,74 @@ +package info.nightscout.androidaps.plugins.PumpCombo; + + +import android.app.Activity; +import android.os.Bundle; +import android.os.Handler; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import com.squareup.otto.Subscribe; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Date; + +import info.nightscout.androidaps.MainApp; +import info.nightscout.androidaps.R; +import info.nightscout.androidaps.plugins.PumpCombo.events.EventComboPumpUpdateGUI; +import info.nightscout.androidaps.plugins.PumpVirtual.VirtualPumpPlugin; +import info.nightscout.androidaps.plugins.PumpVirtual.events.EventVirtualPumpUpdateGui; + +public class ComboFragment extends Fragment { + private static Logger log = LoggerFactory.getLogger(ComboFragment.class); + + private static ComboPlugin comboPlugin = new ComboPlugin(); + + public static ComboPlugin getPlugin() { + return comboPlugin; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.combopump_fragment, container, false); + + updateGUI(); + return view; + } + + @Override + public void onPause() { + super.onPause(); + MainApp.bus().unregister(this); + } + + @Override + public void onResume() { + super.onResume(); + MainApp.bus().register(this); + } + + @Subscribe + public void onStatusEvent(final EventComboPumpUpdateGUI ev) { + updateGUI(); + } + + public void updateGUI() { + Activity activity = getActivity(); + if (activity != null) + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + +// your rendering code here + + } + }); + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java new file mode 100644 index 0000000000..8f9bc20561 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java @@ -0,0 +1,252 @@ +package info.nightscout.androidaps.plugins.PumpCombo; + +import android.content.Context; + +import org.json.JSONException; +import org.json.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Date; + +import info.nightscout.androidaps.BuildConfig; +import info.nightscout.androidaps.Config; +import info.nightscout.androidaps.MainApp; +import info.nightscout.androidaps.R; +import info.nightscout.androidaps.data.PumpEnactResult; +import info.nightscout.androidaps.interfaces.InsulinInterface; +import info.nightscout.androidaps.interfaces.PluginBase; +import info.nightscout.androidaps.interfaces.PumpDescription; +import info.nightscout.androidaps.interfaces.PumpInterface; +import info.nightscout.androidaps.plugins.NSClientInternal.data.NSProfile; +import info.nightscout.androidaps.plugins.PumpCombo.events.EventComboPumpUpdateGUI; +import info.nightscout.androidaps.plugins.PumpMDI.MDIFragment; +import info.nightscout.androidaps.plugins.TreatmentsFromHistory.TreatmentsFromHistoryPlugin; +import info.nightscout.utils.DateUtil; + +/** + * Created by mike on 05.08.2016. + */ +public class ComboPlugin implements PluginBase, PumpInterface { + private static Logger log = LoggerFactory.getLogger(ComboPlugin.class); + + boolean fragmentEnabled = false; + boolean fragmentVisible = false; + + PumpDescription pumpDescription = new PumpDescription(); + + public ComboPlugin() { + pumpDescription.isBolusCapable = true; + pumpDescription.bolusStep = 0.5d; + + pumpDescription.isExtendedBolusCapable = false; + pumpDescription.extendedBolusStep = 0d; + + pumpDescription.isTempBasalCapable = false; + pumpDescription.lowTempBasalStyle = PumpDescription.NONE; + pumpDescription.highTempBasalStyle = PumpDescription.NONE; + pumpDescription.maxHighTempPercent = 0; + pumpDescription.maxHighTempAbsolute = 0; + pumpDescription.lowTempPercentStep = 0; + pumpDescription.lowTempAbsoluteStep = 0; + pumpDescription.lowTempPercentDuration = 0; + pumpDescription.lowTempAbsoluteDuration = 0; + pumpDescription.highTempPercentStep = 0; + pumpDescription.highTempAbsoluteStep = 0d; + pumpDescription.highTempPercentDuration = 0; + pumpDescription.highTempAbsoluteDuration = 0; + + pumpDescription.isSetBasalProfileCapable = false; + pumpDescription.basalStep = 0d; + pumpDescription.basalMinimumRate = 0d; + + pumpDescription.isRefillingCapable = false; + } + + @Override + public String getFragmentClass() { + return ComboFragment.class.getName(); + } + + @Override + public String getName() { + return MainApp.instance().getString(R.string.combopump); + } + + @Override + public String getNameShort() { + // use long name as fallback (not visible in tabs) + return getName(); + } + + @Override + public boolean isEnabled(int type) { + return type == PUMP && fragmentEnabled; + } + + @Override + public boolean isVisibleInTabs(int type) { + return type == PUMP && fragmentVisible; + } + + @Override + public boolean canBeHidden(int type) { + return true; + } + + @Override + public boolean hasFragment() { + return true; + } + + @Override + public boolean showInList(int type) { + return true; + } + + @Override + public void setFragmentEnabled(int type, boolean fragmentEnabled) { + if (type == PUMP) this.fragmentEnabled = fragmentEnabled; + } + + @Override + public void setFragmentVisible(int type, boolean fragmentVisible) { + if (type == PUMP) this.fragmentVisible = fragmentVisible; + } + + @Override + public int getType() { + return PluginBase.PUMP; + } + + @Override + public String treatmentPlugin() { + return TreatmentsFromHistoryPlugin.class.getName(); + } + + @Override + public boolean isInitialized() { + return true; + } + + @Override + public boolean isSuspended() { + return false; + } + + @Override + public boolean isBusy() { + return false; + } + + @Override + public int setNewBasalProfile(NSProfile profile) { + return FAILED; + } + + @Override + public boolean isThisProfileSet(NSProfile profile) { + return false; + } + + @Override + public Date lastDataTime() { + return new Date(); + } + + @Override + public void refreshDataFromPump(String reason) { +// this is called regulary from keepalive + } + + @Override + public double getBaseBasalRate() { + return 0d; + } + + @Override + public PumpEnactResult deliverTreatment(InsulinInterface insulinType, Double insulin, Integer carbs, Context context) { + PumpEnactResult result = new PumpEnactResult(); + return result; + } + + @Override + public void stopBolusDelivering() { + } + + @Override + public PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes) { + PumpEnactResult result = new PumpEnactResult(); + return result; + } + + @Override + public PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes) { + PumpEnactResult result = new PumpEnactResult(); + return result; + } + + @Override + public PumpEnactResult setExtendedBolus(Double insulin, Integer durationInMinutes) { + PumpEnactResult result = new PumpEnactResult(); + return result; + } + + @Override + public PumpEnactResult cancelTempBasal() { + PumpEnactResult result = new PumpEnactResult(); + return result; + } + + @Override + public PumpEnactResult cancelExtendedBolus() { + PumpEnactResult result = new PumpEnactResult(); + return result; + } + + @Override + public JSONObject getJSONStatus() { + JSONObject pump = new JSONObject(); + JSONObject status = new JSONObject(); + JSONObject extended = new JSONObject(); + try { + status.put("status", "normal"); + extended.put("Version", BuildConfig.VERSION_NAME + "-" + BuildConfig.BUILDVERSION); + try { + extended.put("ActiveProfile", MainApp.getConfigBuilder().getActiveProfile().getProfile().getActiveProfile()); + } catch (Exception e) { + } + status.put("timestamp", DateUtil.toISOString(new Date())); + +// more info here .... look at dana plugin + + pump.put("status", status); + pump.put("extended", extended); + pump.put("clock", DateUtil.toISOString(new Date())); + } catch (JSONException e) { + } + return pump; + } + + @Override + public String deviceID() { +// Serial number here + return "Combo"; + } + + @Override + public PumpDescription getPumpDescription() { + return pumpDescription; + } + + @Override + public String shortStatus(boolean veryShort) { + return deviceID(); + } + +} + + +// If you want update fragment call +// MainApp.bus().post(new EventComboPumpUpdateGUI()); +// fragment should fetch data from plugin and display status, buttons etc ... diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/events/EventComboPumpUpdateGUI.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/events/EventComboPumpUpdateGUI.java new file mode 100644 index 0000000000..e9bf3f8415 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/events/EventComboPumpUpdateGUI.java @@ -0,0 +1,8 @@ +package info.nightscout.androidaps.plugins.PumpCombo.events; + +/** + * Created by mike on 24.05.2017. + */ + +public class EventComboPumpUpdateGUI { +} diff --git a/app/src/main/res/layout/combopump_fragment.xml b/app/src/main/res/layout/combopump_fragment.xml new file mode 100644 index 0000000000..dd0948ef4c --- /dev/null +++ b/app/src/main/res/layout/combopump_fragment.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a44e5ef758..959aceb127 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -685,4 +685,6 @@ Values not stored! Overview Notifications Pass the Overview Notifications through as wear confirmation messages. + Accu-Chek Combo + Accu-Chek Combo settings diff --git a/app/src/main/res/xml/pref_combo.xml b/app/src/main/res/xml/pref_combo.xml new file mode 100644 index 0000000000..3f2a8800b7 --- /dev/null +++ b/app/src/main/res/xml/pref_combo.xml @@ -0,0 +1,9 @@ + + + + + + + \ No newline at end of file From e9f5241821f32f463ce5745bde09c1e06d96333e Mon Sep 17 00:00:00 2001 From: Milos Kozak Date: Mon, 29 May 2017 22:31:50 +0200 Subject: [PATCH 002/952] add missing interface functions to combo --- .../plugins/PumpCombo/ComboPlugin.java | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java index 8f9bc20561..697929284b 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java @@ -13,6 +13,7 @@ import info.nightscout.androidaps.BuildConfig; import info.nightscout.androidaps.Config; import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.R; +import info.nightscout.androidaps.data.DetailedBolusInfo; import info.nightscout.androidaps.data.PumpEnactResult; import info.nightscout.androidaps.interfaces.InsulinInterface; import info.nightscout.androidaps.interfaces.PluginBase; @@ -21,7 +22,6 @@ import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.plugins.NSClientInternal.data.NSProfile; import info.nightscout.androidaps.plugins.PumpCombo.events.EventComboPumpUpdateGUI; import info.nightscout.androidaps.plugins.PumpMDI.MDIFragment; -import info.nightscout.androidaps.plugins.TreatmentsFromHistory.TreatmentsFromHistoryPlugin; import info.nightscout.utils.DateUtil; /** @@ -119,11 +119,6 @@ public class ComboPlugin implements PluginBase, PumpInterface { return PluginBase.PUMP; } - @Override - public String treatmentPlugin() { - return TreatmentsFromHistoryPlugin.class.getName(); - } - @Override public boolean isInitialized() { return true; @@ -165,9 +160,8 @@ public class ComboPlugin implements PluginBase, PumpInterface { } @Override - public PumpEnactResult deliverTreatment(InsulinInterface insulinType, Double insulin, Integer carbs, Context context) { - PumpEnactResult result = new PumpEnactResult(); - return result; + public PumpEnactResult deliverTreatment(DetailedBolusInfo detailedBolusInfo) { + return null; } @Override @@ -244,6 +238,11 @@ public class ComboPlugin implements PluginBase, PumpInterface { return deviceID(); } + @Override + public boolean isFakingTempsByExtendedBoluses() { + return false; + } + } From 30b7697002d01366fa6ad3372a3aae2c590a8385 Mon Sep 17 00:00:00 2001 From: Milos Kozak Date: Thu, 8 Jun 2017 22:56:59 +0200 Subject: [PATCH 003/952] adjust combo driver for latest changes --- .../plugins/PumpCombo/ComboPlugin.java | 50 ++++++++----------- 1 file changed, 21 insertions(+), 29 deletions(-) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java index 697929284b..1034263a04 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java @@ -1,7 +1,5 @@ package info.nightscout.androidaps.plugins.PumpCombo; -import android.content.Context; - import org.json.JSONException; import org.json.JSONObject; import org.slf4j.Logger; @@ -10,18 +8,14 @@ import org.slf4j.LoggerFactory; import java.util.Date; import info.nightscout.androidaps.BuildConfig; -import info.nightscout.androidaps.Config; import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.R; import info.nightscout.androidaps.data.DetailedBolusInfo; +import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.PumpEnactResult; -import info.nightscout.androidaps.interfaces.InsulinInterface; import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PumpDescription; import info.nightscout.androidaps.interfaces.PumpInterface; -import info.nightscout.androidaps.plugins.NSClientInternal.data.NSProfile; -import info.nightscout.androidaps.plugins.PumpCombo.events.EventComboPumpUpdateGUI; -import info.nightscout.androidaps.plugins.PumpMDI.MDIFragment; import info.nightscout.utils.DateUtil; /** @@ -37,28 +31,26 @@ public class ComboPlugin implements PluginBase, PumpInterface { public ComboPlugin() { pumpDescription.isBolusCapable = true; - pumpDescription.bolusStep = 0.5d; + pumpDescription.bolusStep = 0.1d; - pumpDescription.isExtendedBolusCapable = false; - pumpDescription.extendedBolusStep = 0d; + pumpDescription.isExtendedBolusCapable = true; + pumpDescription.extendedBolusStep = 0.05d; + pumpDescription.extendedBolusDurationStep = 30; + pumpDescription.extendedBolusMaxDuration = 8 * 60; - pumpDescription.isTempBasalCapable = false; - pumpDescription.lowTempBasalStyle = PumpDescription.NONE; - pumpDescription.highTempBasalStyle = PumpDescription.NONE; - pumpDescription.maxHighTempPercent = 0; - pumpDescription.maxHighTempAbsolute = 0; - pumpDescription.lowTempPercentStep = 0; - pumpDescription.lowTempAbsoluteStep = 0; - pumpDescription.lowTempPercentDuration = 0; - pumpDescription.lowTempAbsoluteDuration = 0; - pumpDescription.highTempPercentStep = 0; - pumpDescription.highTempAbsoluteStep = 0d; - pumpDescription.highTempPercentDuration = 0; - pumpDescription.highTempAbsoluteDuration = 0; + pumpDescription.isTempBasalCapable = true; + pumpDescription.tempBasalStyle = PumpDescription.PERCENT; - pumpDescription.isSetBasalProfileCapable = false; - pumpDescription.basalStep = 0d; - pumpDescription.basalMinimumRate = 0d; + pumpDescription.maxTempPercent = 500; + pumpDescription.tempPercentStep = 10; + + pumpDescription.tempDurationStep = 30; + pumpDescription.tempMaxDuration = 24 * 60; + + + pumpDescription.isSetBasalProfileCapable = true; + pumpDescription.basalStep = 0.01d; + pumpDescription.basalMinimumRate = 0.01d; pumpDescription.isRefillingCapable = false; } @@ -135,12 +127,12 @@ public class ComboPlugin implements PluginBase, PumpInterface { } @Override - public int setNewBasalProfile(NSProfile profile) { + public int setNewBasalProfile(Profile profile) { return FAILED; } @Override - public boolean isThisProfileSet(NSProfile profile) { + public boolean isThisProfileSet(Profile profile) { return false; } @@ -207,7 +199,7 @@ public class ComboPlugin implements PluginBase, PumpInterface { status.put("status", "normal"); extended.put("Version", BuildConfig.VERSION_NAME + "-" + BuildConfig.BUILDVERSION); try { - extended.put("ActiveProfile", MainApp.getConfigBuilder().getActiveProfile().getProfile().getActiveProfile()); + extended.put("ActiveProfile", MainApp.getConfigBuilder().getProfileName()); } catch (Exception e) { } status.put("timestamp", DateUtil.toISOString(new Date())); From ab9908438e72a06e6f8ae70c612612193593bcef Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Thu, 13 Jul 2017 18:04:03 +0200 Subject: [PATCH 004/952] Add Combo short name. --- .../androidaps/plugins/PumpCombo/ComboPlugin.java | 7 ++++++- app/src/main/res/values/strings.xml | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java index 1034263a04..3aa2ff2678 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java @@ -67,7 +67,12 @@ public class ComboPlugin implements PluginBase, PumpInterface { @Override public String getNameShort() { - // use long name as fallback (not visible in tabs) + String name = MainApp.sResources.getString(R.string.combopump_shortname); + if (!name.trim().isEmpty()) { + //only if translation exists + return name; + } + // use long name as fallback return getName(); } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 959aceb127..84e3d3c928 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -687,4 +687,5 @@ Pass the Overview Notifications through as wear confirmation messages. Accu-Chek Combo Accu-Chek Combo settings + COMBO From 481c63fa57be59fae4f23e098c1d6a2d25cc7e7b Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Thu, 13 Jul 2017 18:15:37 +0200 Subject: [PATCH 005/952] Initial work on the ComboPlugin. --- .../plugins/PumpCombo/ComboPlugin.java | 160 ++++++++++++++++-- 1 file changed, 142 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java index 3aa2ff2678..ffc4657254 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java @@ -1,18 +1,34 @@ package info.nightscout.androidaps.plugins.PumpCombo; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.IBinder; + +import com.squareup.otto.Subscribe; + import org.json.JSONException; import org.json.JSONObject; +import org.monkey.d.ruffy.ruffy.driver.IRuffyService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Date; +import de.jotomo.ruffyscripter.RuffyScripter; +import de.jotomo.ruffyscripter.commands.BolusCommand; +import de.jotomo.ruffyscripter.commands.CancelTbrCommand; +import de.jotomo.ruffyscripter.commands.Command; +import de.jotomo.ruffyscripter.commands.CommandResult; +import de.jotomo.ruffyscripter.commands.SetTbrCommand; import info.nightscout.androidaps.BuildConfig; import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.R; import info.nightscout.androidaps.data.DetailedBolusInfo; import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.PumpEnactResult; +import info.nightscout.androidaps.events.EventAppExit; import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PumpDescription; import info.nightscout.androidaps.interfaces.PumpInterface; @@ -29,11 +45,65 @@ public class ComboPlugin implements PluginBase, PumpInterface { PumpDescription pumpDescription = new PumpDescription(); + private RuffyScripter ruffyScripter; + private Date lastCmdTime = new Date(0); + private ServiceConnection mRuffyServiceConnection; + + private static PumpEnactResult OPERATION_NOT_SUPPORTED = new PumpEnactResult(); + static { + OPERATION_NOT_SUPPORTED.success = false; + OPERATION_NOT_SUPPORTED.enacted = false; + OPERATION_NOT_SUPPORTED.comment = "Requested operation not supported by pump"; + } + + private double fakeBasalRate = 0.5d; + public ComboPlugin() { + definePumpCapabilities(); + bindRuffyService(); + MainApp.bus().register(this); + } + + private void bindRuffyService() { + Context context = MainApp.instance().getApplicationContext(); + + Intent intent = new Intent() + .setComponent(new ComponentName( + // this must be the base package of the app (check package attribute in + // manifest element in the manifest file of the providing app) + "org.monkey.d.ruffy.ruffy", + // full path to the driver + // in the logs this service is mentioned as (note the slash) + // "org.monkey.d.ruffy.ruffy/.driver.Ruffy" + "org.monkey.d.ruffy.ruffy.driver.Ruffy" + )); + context.startService(intent); + + mRuffyServiceConnection = new ServiceConnection() { + + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + ruffyScripter = new RuffyScripter(IRuffyService.Stub.asInterface(service)); + log.debug("ruffy serivce connected"); + } + + @Override + public void onServiceDisconnected(ComponentName name) { + log.debug("ruffy service disconnected"); + } + }; + + boolean success = context.bindService(intent, mRuffyServiceConnection, Context.BIND_AUTO_CREATE); + if(!success) { + log.error("Binding to ruffy service failed"); + } + } + + private void definePumpCapabilities() { pumpDescription.isBolusCapable = true; pumpDescription.bolusStep = 0.1d; - pumpDescription.isExtendedBolusCapable = true; + pumpDescription.isExtendedBolusCapable = false; // TODO pumpDescription.extendedBolusStep = 0.05d; pumpDescription.extendedBolusDurationStep = 30; pumpDescription.extendedBolusMaxDuration = 8 * 60; @@ -44,11 +114,11 @@ public class ComboPlugin implements PluginBase, PumpInterface { pumpDescription.maxTempPercent = 500; pumpDescription.tempPercentStep = 10; - pumpDescription.tempDurationStep = 30; + pumpDescription.tempDurationStep = 15; pumpDescription.tempMaxDuration = 24 * 60; - pumpDescription.isSetBasalProfileCapable = true; + pumpDescription.isSetBasalProfileCapable = false; // TODO pumpDescription.basalStep = 0.01d; pumpDescription.basalMinimumRate = 0.01d; @@ -118,7 +188,8 @@ public class ComboPlugin implements PluginBase, PumpInterface { @Override public boolean isInitialized() { - return true; + // TODO + return ruffyScripter != null; } @Override @@ -126,75 +197,122 @@ public class ComboPlugin implements PluginBase, PumpInterface { return false; } + // TODO @Override public boolean isBusy() { - return false; + return ruffyScripter.isPumpBusy(); } + // TODO @Override public int setNewBasalProfile(Profile profile) { return FAILED; } + // TODO @Override public boolean isThisProfileSet(Profile profile) { return false; } + // TODO @Override public Date lastDataTime() { - return new Date(); + return lastCmdTime; } + // TODO @Override public void refreshDataFromPump(String reason) { // this is called regulary from keepalive + + // TODO how often is this called? use this to run checks regularly, e.g. + // recheck active TBR, basal rate to ensure nothing broke? } + // TODO @Override public double getBaseBasalRate() { - return 0d; + // TODO this is simple to read, w/o causing vibirations, it's BASAL_RATE in the main menu + return fakeBasalRate; } @Override public PumpEnactResult deliverTreatment(DetailedBolusInfo detailedBolusInfo) { - return null; + Command command = new BolusCommand(detailedBolusInfo.insulin); + CommandResult commandResult = ruffyScripter.runCommand(command); + + PumpEnactResult pumpEnactResult = new PumpEnactResult(); + pumpEnactResult.success = commandResult.success; + pumpEnactResult.enacted = commandResult.enacted; + pumpEnactResult.comment = commandResult.message; + pumpEnactResult.bolusDelivered = detailedBolusInfo.insulin; + + return pumpEnactResult; } @Override public void stopBolusDelivering() { + // there's no way to stop the combo once delivery has started + // but before that, we could interrupt the command thread ... pause + // till pump times out or raises an error } + // TODO @Override public PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes) { - PumpEnactResult result = new PumpEnactResult(); - return result; + return OPERATION_NOT_SUPPORTED; } @Override public PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes) { - PumpEnactResult result = new PumpEnactResult(); - return result; + // TODO make each cmd return all the data the main screen displays and cache here ? + Command command = new SetTbrCommand(percent, durationInMinutes); + CommandResult commandResult = ruffyScripter.runCommand(command); + + PumpEnactResult pumpEnactResult = new PumpEnactResult(); + pumpEnactResult.success = commandResult.success; + pumpEnactResult.enacted = commandResult.enacted; + pumpEnactResult.comment = commandResult.message; + pumpEnactResult.isPercent = true; + pumpEnactResult.percent = percent; + + fakeBasalRate = fakeBasalRate * percent / 100; + + return pumpEnactResult; } + // TODO @Override public PumpEnactResult setExtendedBolus(Double insulin, Integer durationInMinutes) { - PumpEnactResult result = new PumpEnactResult(); - return result; + return OPERATION_NOT_SUPPORTED; } + // TODO @Override public PumpEnactResult cancelTempBasal() { - PumpEnactResult result = new PumpEnactResult(); - return result; + Command command = new CancelTbrCommand(); + CommandResult commandResult = ruffyScripter.runCommand(command); + + PumpEnactResult pumpEnactResult = new PumpEnactResult(); + pumpEnactResult.success = commandResult.success; + pumpEnactResult.enacted = commandResult.enacted; + pumpEnactResult.comment = commandResult.message; + pumpEnactResult.isTempCancel = true; + + fakeBasalRate = 0.5d; + + return pumpEnactResult; } + // TODO @Override public PumpEnactResult cancelExtendedBolus() { - PumpEnactResult result = new PumpEnactResult(); - return result; + return OPERATION_NOT_SUPPORTED; } + // TODO + // cache as much as possible - every time we interact with the pump it vibrates at the end @Override public JSONObject getJSONStatus() { JSONObject pump = new JSONObject(); @@ -219,6 +337,7 @@ public class ComboPlugin implements PluginBase, PumpInterface { return pump; } + // TODO @Override public String deviceID() { // Serial number here @@ -240,6 +359,11 @@ public class ComboPlugin implements PluginBase, PumpInterface { return false; } + @SuppressWarnings("UnusedParameters") + @Subscribe + public void onStatusEvent(final EventAppExit e) { + MainApp.instance().getApplicationContext().unbindService(mRuffyServiceConnection); + } } From 328009256687ead752ae04416c30873d6081a460 Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Thu, 13 Jul 2017 19:50:11 +0200 Subject: [PATCH 006/952] Source ruffy scripter for the time being (already some fixes and tweaks in). --- .../d/ruffy/ruffy/driver/IRTHandler.aidl | 21 ++ .../d/ruffy/ruffy/driver/IRuffyService.aidl | 14 + .../d/ruffy/ruffy/driver/display/Menu.aidl | 3 + .../jotomo/ruffyscripter/RuffyScripter.java | 286 ++++++++++++++++++ .../ruffyscripter/commands/BolusCommand.java | 89 ++++++ .../commands/CancelTbrCommand.java | 20 ++ .../ruffyscripter/commands/Command.java | 11 + .../commands/CommandException.java | 44 +++ .../ruffyscripter/commands/CommandResult.java | 41 +++ .../ruffyscripter/commands/SetTbrCommand.java | 238 +++++++++++++++ .../d/ruffy/ruffy/driver/display/Menu.java | 123 ++++++++ .../ruffy/driver/display/MenuAttribute.java | 34 +++ .../ruffy/ruffy/driver/display/MenuType.java | 42 +++ .../ruffy/driver/display/menu/BolusType.java | 13 + .../ruffy/driver/display/menu/MenuBlink.java | 12 + .../ruffy/driver/display/menu/MenuDate.java | 27 ++ .../ruffy/driver/display/menu/MenuTime.java | 36 +++ 17 files changed, 1054 insertions(+) create mode 100644 app/src/main/aidl/org/monkey/d/ruffy/ruffy/driver/IRTHandler.aidl create mode 100644 app/src/main/aidl/org/monkey/d/ruffy/ruffy/driver/IRuffyService.aidl create mode 100644 app/src/main/aidl/org/monkey/d/ruffy/ruffy/driver/display/Menu.aidl create mode 100644 app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java create mode 100644 app/src/main/java/de/jotomo/ruffyscripter/commands/BolusCommand.java create mode 100644 app/src/main/java/de/jotomo/ruffyscripter/commands/CancelTbrCommand.java create mode 100644 app/src/main/java/de/jotomo/ruffyscripter/commands/Command.java create mode 100644 app/src/main/java/de/jotomo/ruffyscripter/commands/CommandException.java create mode 100644 app/src/main/java/de/jotomo/ruffyscripter/commands/CommandResult.java create mode 100644 app/src/main/java/de/jotomo/ruffyscripter/commands/SetTbrCommand.java create mode 100644 app/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/Menu.java create mode 100644 app/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/MenuAttribute.java create mode 100644 app/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/MenuType.java create mode 100644 app/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/menu/BolusType.java create mode 100644 app/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/menu/MenuBlink.java create mode 100644 app/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/menu/MenuDate.java create mode 100644 app/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/menu/MenuTime.java diff --git a/app/src/main/aidl/org/monkey/d/ruffy/ruffy/driver/IRTHandler.aidl b/app/src/main/aidl/org/monkey/d/ruffy/ruffy/driver/IRTHandler.aidl new file mode 100644 index 0000000000..996b10b666 --- /dev/null +++ b/app/src/main/aidl/org/monkey/d/ruffy/ruffy/driver/IRTHandler.aidl @@ -0,0 +1,21 @@ +// IRTHandler.aidl +package org.monkey.d.ruffy.ruffy.driver; + +// Declare any non-default types here with import statements + +import org.monkey.d.ruffy.ruffy.driver.display.Menu; + +interface IRTHandler { + void log(String message); + void fail(String message); + + void requestBluetooth(); + void rtStopped(); + void rtStarted(); + + void rtClearDisplay(); + void rtUpdateDisplay(in byte[] quarter, int which); + + void rtDisplayHandleMenu(in Menu menu); + void rtDisplayHandleNoMenu(); +} diff --git a/app/src/main/aidl/org/monkey/d/ruffy/ruffy/driver/IRuffyService.aidl b/app/src/main/aidl/org/monkey/d/ruffy/ruffy/driver/IRuffyService.aidl new file mode 100644 index 0000000000..3baa4116e1 --- /dev/null +++ b/app/src/main/aidl/org/monkey/d/ruffy/ruffy/driver/IRuffyService.aidl @@ -0,0 +1,14 @@ +// IRuffyService.aidl +package org.monkey.d.ruffy.ruffy.driver; + +// Declare any non-default types here with import statements +import org.monkey.d.ruffy.ruffy.driver.IRTHandler; + +interface IRuffyService { + + void setHandler(IRTHandler handler); + int doRTConnect(); + void doRTDisconnect(); + void rtSendKey(byte keyCode, boolean changed); + void resetPairing(); +} diff --git a/app/src/main/aidl/org/monkey/d/ruffy/ruffy/driver/display/Menu.aidl b/app/src/main/aidl/org/monkey/d/ruffy/ruffy/driver/display/Menu.aidl new file mode 100644 index 0000000000..f0b99ec918 --- /dev/null +++ b/app/src/main/aidl/org/monkey/d/ruffy/ruffy/driver/display/Menu.aidl @@ -0,0 +1,3 @@ +package org.monkey.d.ruffy.ruffy.driver.display; + +parcelable Menu; \ No newline at end of file diff --git a/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java b/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java new file mode 100644 index 0000000000..3c25f325cf --- /dev/null +++ b/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java @@ -0,0 +1,286 @@ +package de.jotomo.ruffyscripter; + +import android.os.RemoteException; +import android.os.SystemClock; + +import org.monkey.d.ruffy.ruffy.driver.IRTHandler; +import org.monkey.d.ruffy.ruffy.driver.IRuffyService; +import org.monkey.d.ruffy.ruffy.driver.display.Menu; +import org.monkey.d.ruffy.ruffy.driver.display.MenuType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import de.jotomo.ruffyscripter.commands.Command; +import de.jotomo.ruffyscripter.commands.CommandException; +import de.jotomo.ruffyscripter.commands.CommandResult; + +// TODO regularly read "My data" history (boluses, TBR) to double check all commands ran successfully. +// Automatically compare against AAPS db, or log all requests in the PumpInterface (maybe Milos +// already logs those requests somewhere ... and verify they have all been ack'd by the pump properly + +/** + * provides scripting 'runtime' and operations. consider moving operations into a separate + * class and inject that into executing commands, so that commands operately solely on + * operations and are cleanly separated from the thread management, connection management etc + */ +public class RuffyScripter { + private static final Logger log = LoggerFactory.getLogger(RuffyScripter.class); + + public volatile Menu currentMenu; + + private final IRuffyService ruffyService; + private volatile CommandResult cmdResult; + private volatile long menuLastUpdated = 0; + + public RuffyScripter(IRuffyService ruffyService) { + this.ruffyService = ruffyService; + try { + ruffyService.setHandler(mHandler); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + private IRTHandler mHandler = new IRTHandler.Stub() { + @Override + public void log(String message) throws RemoteException { + log.trace(message); + } + + @Override + public void fail(String message) throws RemoteException { + log.warn(message); + } + + @Override + public void requestBluetooth() throws RemoteException { + log.trace("Ruffy invoked requestBluetooth callback"); + } + + @Override + public void rtStopped() throws RemoteException { + log.debug("rtStopped callback invoked"); + currentMenu = null; + } + + @Override + public void rtStarted() throws RemoteException { + log.debug("rtStarted callback invoked"); + } + + @Override + public void rtClearDisplay() throws RemoteException { + } + + @Override + public void rtUpdateDisplay(byte[] quarter, int which) throws RemoteException { + } + + @Override + public void rtDisplayHandleMenu(Menu menu) throws RemoteException { + // method is called every ~500ms + log.debug("rtDisplayHandleMenu: " + menu.getType()); + + currentMenu = menu; + menuLastUpdated = System.currentTimeMillis(); + + // note that a WARNING_OR_ERROR menu can be a valid temporary state (cancelling TBR) + // of a running command + if (activeCmd == null && currentMenu.getType() == MenuType.WARNING_OR_ERROR) { + log.warn("Warning/error menu encountered without a command running"); + } + } + + @Override + public void rtDisplayHandleNoMenu() throws RemoteException { + log.debug("rtDisplayHandleNoMenu callback invoked"); + } + + }; + + public boolean isPumpBusy() { + return activeCmd != null; // || currentMenu == null || currentMenu.getType() != MenuType.MAIN_MENU; + } + + private volatile Command activeCmd = null; + + // TODO take a callback to call when command finishes? + // TODO sometimes hangs ... we should timeout and raise an alert to check the pump and ruffy + // TODO not getting a menu update in a while is a good cue ... + // fire up a monitoring thread for that? + public CommandResult runCommand(final Command cmd) { + try { + if (isPumpBusy()) { + return new CommandResult().message("Pump is busy"); + } + ensureConnected(); + + // TODO make this a safe lock + synchronized (this) { + cmdResult = null; + activeCmd = cmd; + final RuffyScripter scripter = this; + // TODO hackish, to say the least ... + // wait till pump is ready for input + waitForMenuUpdate(); + log.debug("Cmd execution: connection ready, executing cmd " + cmd); + new Thread(new Runnable() { + @Override + public void run() { + try { + cmdResult = cmd.execute(scripter); + } catch (Exception e) { + cmdResult = new CommandResult().exception(e).message("Unexpected exception running cmd"); + } finally { + activeCmd = null; + } + + } + }).start(); + } + + // TODO really? + while (activeCmd != null) { + SystemClock.sleep(500); + log.trace("Waiting for running command to complete"); + } + log.debug("Command result: " + cmdResult); + + CommandResult r = cmdResult; + cmdResult = null; + return r; + } catch (CommandException e) { + return e.toCommandResult(); + } catch (Exception e) { + return new CommandResult().exception(e).message("Unexpected exception communication with ruffy"); + } + } + + public void ensureConnected() { + // did we get a menu update from the pump in the last 5s? Then we're connected + if (currentMenu != null && menuLastUpdated + 5000 > System.currentTimeMillis()) { + log.debug("Pump is sending us menu updating, so we're connected"); + return; + } + + try { + boolean connectSuccesful = ruffyService.doRTConnect() == 0; + log.debug("Connect init successful: " + connectSuccesful); + while (currentMenu == null) { + log.debug("Waiting for first menu update to be sent"); + waitForMenuUpdate(); + } + } catch (RemoteException e) { + throw new CommandException().exception(e).message("Unexpected exception while initiating/restoring pump connection"); + } + } + + public CommandResult disconnect() { + try { + ruffyService.doRTDisconnect(); + } catch (RemoteException e) { + return new CommandResult().exception(e).message("Unexpected exception trying to disconnect"); + } + return new CommandResult().success(true); + } + + // below: methods to be used by commands + + private static class Key { + static byte NO_KEY = (byte) 0x00; + static byte MENU = (byte) 0x03; + static byte CHECK = (byte) 0x0C; + static byte UP = (byte) 0x30; + static byte DOWN = (byte) 0xC0; + } + + public void pressUpKey() { + pressKey(Key.UP); + } + + public void pressDownKey() { + pressKey(Key.DOWN); + } + + public void pressCheckKey() { + pressKey(Key.CHECK); + } + + public void pressMenuKey() { + // TODO build 'wait for menu update' into this method? get current menu, press key, wait for update? + pressKey(Key.MENU); + } + + /** Wait until the menu update is in */ + public void waitForMenuUpdate() { + long timeoutExpired = System.currentTimeMillis() + 90 * 1000; + long initialUpdateTime = menuLastUpdated; + while (initialUpdateTime == menuLastUpdated) { + if(System.currentTimeMillis() > timeoutExpired) { + throw new CommandException().message("Timeout waiting for menu update"); + } + SystemClock.sleep(50); + } + } + + /** + * "Virtual" key, emulated by pressing menu and up simultaneously + */ + // Doesn't work +/* public void pressBackKey() throws RemoteException { + ruffyService.rtSendKey(Key.MENU, true); + SystemClock.sleep(50); + ruffyService.rtSendKey(Key.UP, true); + SystemClock.sleep(100); + ruffyService.rtSendKey(Key.NO_KEY, true); + }*/ + + private void pressKey(final byte key) { + try { + ruffyService.rtSendKey(key, true); + SystemClock.sleep(100); + ruffyService.rtSendKey(Key.NO_KEY, true); + } catch (RemoteException e) { + throw new CommandException().exception(e).message("Error while pressing buttons"); + } + } + + public void navigateToMenu(MenuType desiredMenu) { + // TODO menu var might not have been initialized if this is called to early + // though that's gonna be a problem for all code; + // wait during init till this is set? create a getter for currentMenu to do this? + MenuType startedFrom = currentMenu.getType(); + while (currentMenu.getType() != desiredMenu) { + MenuType currentType = currentMenu.getType(); +/* if (currentType == startedFrom) { + // TODO don't trigger right away, that's always a match ;-) + // failed to find the menu, after going through all the menus, bail out + throw new CommandException(false, null, "Menu not found searching for " + desiredMenu); + }*/ + pressMenuKey(); + waitForMenuToBeLeft(currentType); + } + } + + /** + * Wait till a menu changed has completed, "away" from the menu provided as argument. + */ + public void waitForMenuToBeLeft(MenuType menuType) { + while (currentMenu.getType() == menuType) { + SystemClock.sleep(250); + } + } + + public void verifyMenuIsDisplayed(MenuType menu) { + String message = "Invalid pump state, expected to be in menu " + + menu + ", but current menu is " + currentMenu.getType(); + verifyMenuIsDisplayed(menu, message); + } + + public void verifyMenuIsDisplayed(MenuType menu, String message) { + waitForMenuUpdate(); + if (currentMenu.getType() != menu) { + throw new CommandException().message(message); + } + } +} diff --git a/app/src/main/java/de/jotomo/ruffyscripter/commands/BolusCommand.java b/app/src/main/java/de/jotomo/ruffyscripter/commands/BolusCommand.java new file mode 100644 index 0000000000..2550c121e5 --- /dev/null +++ b/app/src/main/java/de/jotomo/ruffyscripter/commands/BolusCommand.java @@ -0,0 +1,89 @@ +package de.jotomo.ruffyscripter.commands; + +import android.os.SystemClock; + +import org.monkey.d.ruffy.ruffy.driver.display.MenuAttribute; +import org.monkey.d.ruffy.ruffy.driver.display.MenuType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Locale; + +import de.jotomo.ruffyscripter.RuffyScripter; + +public class BolusCommand implements Command { + private static final Logger log = LoggerFactory.getLogger(BolusCommand.class); + + private final double bolus; + + public BolusCommand(double bolus) { + this.bolus = bolus; + } + + @Override + public CommandResult execute(RuffyScripter scripter) { + try { + scripter.verifyMenuIsDisplayed(MenuType.MAIN_MENU); + enterBolusMenu(scripter); + inputBolusAmount(scripter); + SystemClock.sleep(500); + verifyDisplayedBolusAmount(scripter); + + // confirm bolus + scripter.pressCheckKey(); + + // the pump displays the entered bolus and waits a bit to let user check and cancel + scripter.waitForMenuToBeLeft(MenuType.BOLUS_ENTER); + + scripter.verifyMenuIsDisplayed(MenuType.MAIN_MENU, + "Pump did not return to MAIN_MEU from BOLUS_ENTER to deliver bolus. " + + "Check pump manually, the bolus might not have been delivered."); + + // wait for bolus delivery to complete + Double bolusRemaining = (Double) scripter.currentMenu.getAttribute(MenuAttribute.BOLUS_REMAINING); + while (bolusRemaining != null) { + log.debug("Delivering bolus, remaining: " + bolusRemaining); + SystemClock.sleep(200); + bolusRemaining = (Double) scripter.currentMenu.getAttribute(MenuAttribute.BOLUS_REMAINING); + } + + // TODO what if we hit 'cartridge low' alert here? is it immediately displayed or after the bolus? + // TODO how are error states reported back to the caller that occur outside of calls in genal? Low battery, low cartridge? + + // make sure no alert (occlusion, cartridge empty) has occurred. + scripter.verifyMenuIsDisplayed(MenuType.MAIN_MENU, + "Bolus delivery did not complete as expected. " + + "Check pump manually, the bolus might not have been delivered."); + + return new CommandResult().success(true).enacted(true) + .message(String.format(Locale.US, "Delivered %02.1f U", bolus)); + } catch (CommandException e) { + return e.toCommandResult(); + } + } + + private void enterBolusMenu(RuffyScripter scripter) { + scripter.navigateToMenu(MenuType.BOLUS_MENU); + scripter.pressCheckKey(); + scripter.waitForMenuUpdate(); + scripter.verifyMenuIsDisplayed(MenuType.BOLUS_ENTER); + } + + private void inputBolusAmount(RuffyScripter scripter) { + // press 'up' once for each 0.1 U increment + long steps = Math.round(bolus * 10); + for (int i = 0; i < steps; i++) { + scripter.pressUpKey(); + SystemClock.sleep(100); + } + } + + private void verifyDisplayedBolusAmount(RuffyScripter scripter) { + double displayedBolus = (double) scripter.currentMenu.getAttribute(MenuAttribute.BOLUS); + log.debug("Final bolus: " + displayedBolus); + // TODO can't we just use BigDecimal? doubles aren't precise ... + if (Math.abs(displayedBolus - bolus) > 0.001) { + throw new CommandException().message("Failed to set correct bolus. Expected: " + bolus + ", actual: " + displayedBolus); + } + } +} diff --git a/app/src/main/java/de/jotomo/ruffyscripter/commands/CancelTbrCommand.java b/app/src/main/java/de/jotomo/ruffyscripter/commands/CancelTbrCommand.java new file mode 100644 index 0000000000..40baeab2a6 --- /dev/null +++ b/app/src/main/java/de/jotomo/ruffyscripter/commands/CancelTbrCommand.java @@ -0,0 +1,20 @@ +package de.jotomo.ruffyscripter.commands; + +import org.monkey.d.ruffy.ruffy.driver.display.MenuAttribute; +import org.monkey.d.ruffy.ruffy.driver.display.MenuType; + +import de.jotomo.ruffyscripter.RuffyScripter; + +// TODO robustness: can a TBR run out, whilst we're trying to cancel it? +public class CancelTbrCommand implements Command { + @Override + public CommandResult execute(RuffyScripter scripter) { + scripter.verifyMenuIsDisplayed(MenuType.MAIN_MENU); + Double tbrPercentage = (Double) scripter.currentMenu.getAttribute(MenuAttribute.TBR); + boolean runtimeDisplayed = scripter.currentMenu.attributes().contains(MenuAttribute.RUNTIME); + if (tbrPercentage == 100 && !runtimeDisplayed) { + return new CommandResult().success(true).enacted(false).message("No TBR active"); + } + return new SetTbrCommand(100, 0).execute(scripter); + } +} diff --git a/app/src/main/java/de/jotomo/ruffyscripter/commands/Command.java b/app/src/main/java/de/jotomo/ruffyscripter/commands/Command.java new file mode 100644 index 0000000000..c70384ae36 --- /dev/null +++ b/app/src/main/java/de/jotomo/ruffyscripter/commands/Command.java @@ -0,0 +1,11 @@ +package de.jotomo.ruffyscripter.commands; + +import de.jotomo.ruffyscripter.RuffyScripter; + +public interface Command { + CommandResult execute(RuffyScripter ruffyScripter); + +// default String toString() { +// return getClass().getSimpleName(); +// } +} diff --git a/app/src/main/java/de/jotomo/ruffyscripter/commands/CommandException.java b/app/src/main/java/de/jotomo/ruffyscripter/commands/CommandException.java new file mode 100644 index 0000000000..4e6637f84f --- /dev/null +++ b/app/src/main/java/de/jotomo/ruffyscripter/commands/CommandException.java @@ -0,0 +1,44 @@ +package de.jotomo.ruffyscripter.commands; + +public class CommandException extends RuntimeException { + public boolean success = false; + public boolean enacted = false; + public Exception exception = null; + public String message = null; + + public CommandException() {} + + public CommandException success(boolean success) { + this.success = success; + return this; + } + + public CommandException enacted(boolean enacted) { + this.enacted = enacted; + return this; + } + + public CommandException exception(Exception exception) { + this.exception = exception; + return this; + } + + public CommandException message(String message) { + this.message = message; + return this; + } + + public CommandResult toCommandResult() { + return new CommandResult().success(success).enacted(enacted).exception(exception).message(message); + } + + @Override + public String toString() { + return "CommandException{" + + "success=" + success + + ", enacted=" + enacted + + ", exception=" + exception + + ", message='" + message + '\'' + + '}'; + } +} diff --git a/app/src/main/java/de/jotomo/ruffyscripter/commands/CommandResult.java b/app/src/main/java/de/jotomo/ruffyscripter/commands/CommandResult.java new file mode 100644 index 0000000000..0a78f2a147 --- /dev/null +++ b/app/src/main/java/de/jotomo/ruffyscripter/commands/CommandResult.java @@ -0,0 +1,41 @@ +package de.jotomo.ruffyscripter.commands; + +public class CommandResult { + public boolean success; + public boolean enacted; + public Exception exception; + public String message; + + public CommandResult() { + } + + public CommandResult success(boolean success) { + this.success = success; + return this; + } + + public CommandResult enacted(boolean enacted) { + this.enacted = enacted; + return this; + } + + public CommandResult exception(Exception exception) { + this.exception = exception; + return this; + } + + public CommandResult message(String message) { + this.message = message; + return this; + } + + @Override + public String toString() { + return "CommandResult{" + + "success=" + success + + ", enacted=" + enacted + + ", exception=" + exception + + ", message='" + message + '\'' + + '}'; + } +} diff --git a/app/src/main/java/de/jotomo/ruffyscripter/commands/SetTbrCommand.java b/app/src/main/java/de/jotomo/ruffyscripter/commands/SetTbrCommand.java new file mode 100644 index 0000000000..25a02229f9 --- /dev/null +++ b/app/src/main/java/de/jotomo/ruffyscripter/commands/SetTbrCommand.java @@ -0,0 +1,238 @@ +package de.jotomo.ruffyscripter.commands; + +import android.os.SystemClock; + +import org.monkey.d.ruffy.ruffy.driver.display.MenuAttribute; +import org.monkey.d.ruffy.ruffy.driver.display.MenuType; +import org.monkey.d.ruffy.ruffy.driver.display.menu.MenuTime; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Locale; + +import de.jotomo.ruffyscripter.RuffyScripter; + +public class SetTbrCommand implements Command { + private static final Logger log = LoggerFactory.getLogger(SetTbrCommand.class); + + private final long percentage; + private final long duration; + + public SetTbrCommand(long percentage, long duration) { + this.percentage = percentage; + this.duration = duration; + + if (percentage % 10 != 0) { + throw new IllegalArgumentException("TBR percentage must be set in 10% steps"); + } + if (percentage < 0 || percentage > 500) { + throw new IllegalArgumentException("TBR percentage must be within 0-500%"); + } + + if (percentage != 100) { + if (duration % 15 != 0) { + throw new IllegalArgumentException("TBR duration can only be set in 15 minute steps"); + } + if (duration > 60 * 24) { + throw new IllegalArgumentException("Maximum TBR duration is 24 hours"); + } + } + + if (percentage == 0 && duration > 120) { + throw new IllegalArgumentException("Max allowed zero-temp duration is 2h"); + } + } + + @Override + public CommandResult execute(RuffyScripter scripter) { + try { + scripter.verifyMenuIsDisplayed(MenuType.MAIN_MENU); + enterTbrMenu(scripter); + inputTbrPercentage(scripter); + SystemClock.sleep(500); + verifyDisplayedTbrPercentage(scripter); + + if (percentage == 100) { + cancelTbrAndConfirmCancellationWarning(scripter); + } else { + // switch to TBR_DURATION menu by pressing menu key + scripter.pressMenuKey(); + scripter.verifyMenuIsDisplayed(MenuType.TBR_DURATION); + + inputTbrDuration(scripter); + SystemClock.sleep(500); + verifyDisplayedTbrDuration(scripter); + + // confirm TBR + scripter.pressCheckKey(); + SystemClock.sleep(500); + } + + scripter.verifyMenuIsDisplayed(MenuType.MAIN_MENU, + "Pump did not return to MAIN_MEU after setting TBR. " + + "Check pump manually, the TBR might not have been set/cancelled."); + + // check main menu shows the same values we just set + if (percentage == 100) { + verifyMainMenuShowsNoActiveTbr(scripter); + return new CommandResult().success(true).enacted(true).message("TBR was cancelled"); + } else { + verifyMainMenuShowsExpectedTbrActive(scripter); + return new CommandResult().success(true).enacted(true).message( + String.format(Locale.US, "TBR set to %d%% for %d min", percentage, duration)); + } + + } catch (CommandException e) { + return e.toCommandResult(); + } + } + + private void enterTbrMenu(RuffyScripter scripter) { + scripter.navigateToMenu(MenuType.TBR_MENU); + scripter.pressCheckKey(); + scripter.waitForMenuUpdate(); + scripter.verifyMenuIsDisplayed(MenuType.TBR_SET); + } + + private void inputTbrPercentage(RuffyScripter scripter) { + long currentPercent = readDisplayedTbrPercentage(scripter); + log.debug("Current TBR %: " + currentPercent); + long percentageChange = percentage - currentPercent; + long percentageSteps = percentageChange / 10; + boolean increasePercentage = true; + if (percentageSteps < 0) { + increasePercentage = false; + percentageSteps = Math.abs(percentageSteps); + } + log.debug("Pressing " + (increasePercentage ? "up" : "down") + " " + percentageSteps + " times"); + for (int i = 0; i < percentageSteps; i++) { + if (increasePercentage) scripter.pressUpKey(); + else scripter.pressDownKey(); + // TODO waitForMenuChange instead // or have key press method handle that?? + SystemClock.sleep(100); + log.debug("Push #" + (i + 1)); + } + } + + private void verifyDisplayedTbrPercentage(RuffyScripter scripter) { + long displayedPercentage = readDisplayedTbrPercentage(scripter); + if (displayedPercentage != this.percentage) { + log.debug("Final displayed TBR percentage: " + displayedPercentage); + throw new CommandException().message("Failed to set TBR percentage"); + } + } + + private long readDisplayedTbrPercentage(RuffyScripter scripter) { + Object percentageObj = scripter.currentMenu.getAttribute(MenuAttribute.BASAL_RATE); + // this as a bit hacky, the display value is blinking, so we might catch that, so + // keep trying till we get the Double we want + while (!(percentageObj instanceof Double)) { + scripter.waitForMenuUpdate(); + percentageObj = scripter.currentMenu.getAttribute(MenuAttribute.BASAL_RATE); + } + return ((Double) percentageObj).longValue(); + } + + private void inputTbrDuration(RuffyScripter scripter) { + long currentDuration = readDisplayedTbrDuration(scripter); + if (currentDuration % 15 != 0) { + // The duration displayed is how long an active TBR will still run, + // which might be something like 0:43, hence not in 15 minute steps. + // Pressing down will go to the next lower 15 minute step. + scripter.pressDownKey(); + scripter.waitForMenuUpdate(); + currentDuration = readDisplayedTbrDuration(scripter); + } + log.debug("Current TBR duration: " + currentDuration); + long durationChange = duration - currentDuration; + long durationSteps = durationChange / 15; + boolean increaseDuration = true; + if (durationSteps < 0) { + increaseDuration = false; + durationSteps = Math.abs(durationSteps); + } + log.debug("Pressing " + (increaseDuration ? "up" : "down") + " " + durationSteps + " times"); + for (int i = 0; i < durationSteps; i++) { + if (increaseDuration) scripter.pressUpKey(); + else scripter.pressDownKey(); + // TODO waitForMenuChange instead // or have key press method handle that?? + SystemClock.sleep(100); + log.debug("Push #" + (i + 1)); + } + } + + private void verifyDisplayedTbrDuration(RuffyScripter scripter) { + long displayedDuration = readDisplayedTbrDuration(scripter); + if (displayedDuration != duration) { + log.debug("Final displayed TBR duration: " + displayedDuration); + throw new CommandException().message("Failed to set TBR duration"); + } + } + + private long readDisplayedTbrDuration(RuffyScripter scripter) { + Object durationObj = scripter.currentMenu.getAttribute(MenuAttribute.RUNTIME); + // this as a bit hacky, the display value is blinking, so we might catch that, so + // keep trying till we get the Double we want + while (!(durationObj instanceof MenuTime)) { + scripter.waitForMenuUpdate(); + durationObj = scripter.currentMenu.getAttribute(MenuAttribute.RUNTIME); + } + MenuTime duration = (MenuTime) durationObj; + return duration.getHour() * 60 + duration.getMinute(); + } + + private void cancelTbrAndConfirmCancellationWarning(RuffyScripter scripter) { + // TODO this will fail if no TBR is running; detect and just throw CE(success=true, msg="nothing to do")? + + // confirm entered TBR + scripter.pressCheckKey(); + scripter.waitForMenuUpdate(); + + // hm, waiting here (more) makes things worse, if we don't press the alert away quickly, + // the pump exits BT mode ... so I guess we'll live with the checks below, + // verifying we made it back to the main menu and the displayed TBR data + // corresponds to what we set. Hope the timing is stable enough ... + +/* scripter.waitForMenuToBeLeft(MenuType.TBR_SET); + if (scripter.currentMenu.getType() != MenuType.MAIN_MENU) { + // pump shortly enters the main menu before raising the alert + // TODO is this always entered? + log.debug("TBR cancelled, going over main menu"); + scripter.waitForMenuToBeLeft(MenuType.MAIN_MENU); + } + if (scripter.currentMenu.getType() != MenuType.WARNING_OR_ERROR) { + throw new CommandException(false, null, "Expected WARNING_OR_ERROR menu was not shown when cancelling TBR"); + }*/ + // confirm "TBR cancelled alert" + scripter.pressCheckKey(); + SystemClock.sleep(200); + // dismiss "TBR cancelled alert" + scripter.pressCheckKey(); + scripter.waitForMenuToBeLeft(MenuType.WARNING_OR_ERROR); + } + + private void verifyMainMenuShowsNoActiveTbr(RuffyScripter scripter) { + Double tbrPercentage = (Double) scripter.currentMenu.getAttribute(MenuAttribute.TBR); + boolean runtimeDisplayed = scripter.currentMenu.attributes().contains(MenuAttribute.RUNTIME); + if (tbrPercentage != 100 || runtimeDisplayed) { + throw new CommandException().message("Cancelling TBR failed, TBR is still set according to MAIN_MENU"); + } + } + + private void verifyMainMenuShowsExpectedTbrActive(RuffyScripter scripter) { + // new TBR set; percentage and duration must be displayed ... + if (!scripter.currentMenu.attributes().contains(MenuAttribute.TBR) || + !scripter.currentMenu.attributes().contains(MenuAttribute.TBR)) { + throw new CommandException().message("Setting TBR failed, according to MAIN_MENU no TBR is active"); + } + Double mmTbrPercentage = (Double) scripter.currentMenu.getAttribute(MenuAttribute.TBR); + MenuTime mmTbrDuration = (MenuTime) scripter.currentMenu.getAttribute(MenuAttribute.RUNTIME); + // ... and be the same as what we set + // note that displayed duration might have already counted down, e.g. from 30 minutes to + // 29 minutes and 59 seconds, so that 29 minutes are displayed + int mmTbrDurationInMinutes = mmTbrDuration.getHour() * 60 + mmTbrDuration.getMinute(); + if (mmTbrPercentage != percentage || (mmTbrDurationInMinutes != duration && mmTbrDurationInMinutes + 1 != duration)) { + throw new CommandException().message("Setting TBR failed, TBR in MAIN_MENU differs from expected"); + } + } +} diff --git a/app/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/Menu.java b/app/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/Menu.java new file mode 100644 index 0000000000..20e74c7805 --- /dev/null +++ b/app/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/Menu.java @@ -0,0 +1,123 @@ +package org.monkey.d.ruffy.ruffy.driver.display; + +import android.os.Parcel; +import android.os.Parcelable; +import android.util.Log; + +import org.monkey.d.ruffy.ruffy.driver.display.menu.BolusType; +import org.monkey.d.ruffy.ruffy.driver.display.menu.MenuBlink; +import org.monkey.d.ruffy.ruffy.driver.display.menu.MenuDate; +import org.monkey.d.ruffy.ruffy.driver.display.menu.MenuTime; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +/** + * Created by fishermen21 on 20.05.17. + */ + +public class Menu implements Parcelable{ + private MenuType type; + private Map attributes = new HashMap<>(); + + public Menu(MenuType type) + { + this.type = type; + } + + public Menu(Parcel in) { + this.type = MenuType.valueOf(in.readString()); + while(in.dataAvail()>0) { + try { + String attr = in.readString(); + String clas = in.readString(); + String value = in.readString(); + + MenuAttribute a = MenuAttribute.valueOf(attr); + Object o = null; + if (Integer.class.toString().equals(clas)) { + o = new Integer(value); + } else if (Double.class.toString().equals(clas)) { + o = new Double(value); + } else if (Boolean.class.toString().equals(clas)) { + o = new Boolean(value); + } else if (MenuDate.class.toString().equals(clas)) { + o = new MenuDate(value); + } else if (MenuTime.class.toString().equals(clas)) { + o = new MenuTime(value); + } else if (MenuBlink.class.toString().equals(clas)) { + o = new MenuBlink(); + } else if (BolusType.class.toString().equals(clas)) { + o = BolusType.valueOf(value); + } else if (String.class.toString().equals(clas)) { + o = new String(value); + } + + if (o != null) { + attributes.put(a, o); + } else { + Log.e("MenuIn", "failed to parse: " + attr + " / " + clas + " / " + value); + } + }catch(Exception e) + { + Log.e("MenuIn","Exception in read",e); + } + + } + } + + public void setAttribute(MenuAttribute key, Object value) + { + attributes.put(key,value); + } + + public List attributes() + { + return new LinkedList(attributes.keySet()); + } + + public Object getAttribute(MenuAttribute key) + { + return attributes.get(key); + } + + public MenuType getType() { + return type; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(type.toString()); + for(MenuAttribute a : attributes.keySet()) + { + try + { + dest.writeString(a.toString()); + Object o = attributes.get(a); + + dest.writeString(o.getClass().toString()); + dest.writeString(o.toString()); + }catch(Exception e) + { + Log.v("MenuOut","error in write",e); + } + } + } + public static final Creator CREATOR = new + Creator() { + public Menu createFromParcel(Parcel in) { + return new Menu(in); + } + + public Menu[] newArray(int size) { + return new Menu[size]; + } + }; +} diff --git a/app/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/MenuAttribute.java b/app/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/MenuAttribute.java new file mode 100644 index 0000000000..6176a2be54 --- /dev/null +++ b/app/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/MenuAttribute.java @@ -0,0 +1,34 @@ +package org.monkey.d.ruffy.ruffy.driver.display; + +/** + * Created by fishermen21 on 22.05.17. + */ + +public enum MenuAttribute { + RUNTIME,//runtime of current operation, remaining time on main menu + BOLUS,//double units + BOLUS_REMAINING,//double units remain from current bolus + TBR,//double 0-500% + BASAL_RATE,//double units/h + BASAL_SELECTED,//int selected basal profile + LOW_BATTERY,//boolean low battery warning + INSULIN_STATE,//int insulin warning 0 == no warning, 1== low, 2 == empty + LOCK_STATE,//int keylock state 0==no lock, 1==unlocked, 2==locked + MULTIWAVE_BOLUS,//double immediate bolus on multiwave + BOLUS_TYPE,//BolusType, only history uses MULTIWAVE + TIME,//time MenuTime + REMAINING_INSULIN,//double units + DATE,//date MenuDate + CURRENT_RECORD,//int current record + TOTAL_RECORD, //int total num record + ERROR, //int errorcode + WARNING, //int errorcode + MESSAGE, //string errormessage + DAILY_TOTAL, //double units + BASAL_TOTAL, //double total basal + BASAL_START, //time MenuTime the basalrate starts + BASAL_END, // time MenuTime the basalrate ends + DEBUG_TIMING, //double with timing infos + WARANTY, //boolean true if out of waranty + ERROR_OR_WARNING, // set if menu in blink during error/warning +} diff --git a/app/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/MenuType.java b/app/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/MenuType.java new file mode 100644 index 0000000000..4d00ea9155 --- /dev/null +++ b/app/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/MenuType.java @@ -0,0 +1,42 @@ +package org.monkey.d.ruffy.ruffy.driver.display; + +/** + * Created by fishermen21 on 22.05.17. + */ + +public enum MenuType { + MAIN_MENU, + STOP_MENU, + BOLUS_MENU, + BOLUS_ENTER, + EXTENDED_BOLUS_MENU, + BOLUS_DURATION, + MULTIWAVE_BOLUS_MENU, + IMMEDIATE_BOLUS, + TBR_MENU, + MY_DATA_MENU, + BASAL_MENU, + BASAL_1_MENU, + BASAL_2_MENU, + BASAL_3_MENU, + BASAL_4_MENU, + BASAL_5_MENU, + DATE_AND_TIME_MENU, + ALARM_MENU, + MENU_SETTINGS_MENU, + BLUETOOTH_MENU, + THERAPY_MENU, + PUMP_MENU, + QUICK_INFO, + BOLUS_DATA, + DAILY_DATA, + TBR_DATA, + ERROR_DATA, + TBR_SET, + TBR_DURATION, + STOP, + START_MENU, + BASAL_TOTAL, + BASAL_SET, + WARNING_OR_ERROR, +} diff --git a/app/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/menu/BolusType.java b/app/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/menu/BolusType.java new file mode 100644 index 0000000000..82572acc93 --- /dev/null +++ b/app/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/menu/BolusType.java @@ -0,0 +1,13 @@ +package org.monkey.d.ruffy.ruffy.driver.display.menu; + +/** + * Created by fishermen21 on 22.05.17. + */ + +public enum BolusType{ + NORMAL, + EXTENDED, + MULTIWAVE, + MULTIWAVE_BOLUS, + MULTIWAVE_EXTENDED, +} diff --git a/app/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/menu/MenuBlink.java b/app/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/menu/MenuBlink.java new file mode 100644 index 0000000000..18c0374dcb --- /dev/null +++ b/app/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/menu/MenuBlink.java @@ -0,0 +1,12 @@ +package org.monkey.d.ruffy.ruffy.driver.display.menu; + +/** + * Created by fishermen21 on 22.05.17. + */ + +public class MenuBlink { + @Override + public String toString() { + return "BLINK"; + } +} diff --git a/app/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/menu/MenuDate.java b/app/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/menu/MenuDate.java new file mode 100644 index 0000000000..9b727cc965 --- /dev/null +++ b/app/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/menu/MenuDate.java @@ -0,0 +1,27 @@ +package org.monkey.d.ruffy.ruffy.driver.display.menu; + +/** + * Created by fishermen21 on 24.05.17. + */ + +public class MenuDate { + private final int day; + private final int month; + + + public MenuDate(int day, int month) { + this.day = day; + this.month = month; + } + + public MenuDate(String value) { + String[] p = value.split("\\."); + day = Integer.parseInt(p[0]); + month = Integer.parseInt(p[1]); + } + + @Override + public String toString() { + return day+"."+String.format("%02d",month)+"."; + } +} diff --git a/app/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/menu/MenuTime.java b/app/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/menu/MenuTime.java new file mode 100644 index 0000000000..147aafc8eb --- /dev/null +++ b/app/src/main/java/org/monkey/d/ruffy/ruffy/driver/display/menu/MenuTime.java @@ -0,0 +1,36 @@ +package org.monkey.d.ruffy.ruffy.driver.display.menu; + +/** + * Created by fishermen21 on 22.05.17. + */ + +public class MenuTime { + + private final int hour; + private final int minute; + + public MenuTime(int hour, int minute) + { + this.hour = hour; + this.minute = minute; + } + + public MenuTime(String value) { + String[] p = value.split(":"); + hour = Integer.parseInt(p[0]); + minute = Integer.parseInt(p[1]); + } + + public int getHour() { + return hour; + } + + public int getMinute() { + return minute; + } + + @Override + public String toString() { + return hour+":"+String.format("%02d",minute); + } +} From 7cb0268afc652370c5aa4db987ddd09e4a6894ce Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Thu, 13 Jul 2017 20:17:20 +0200 Subject: [PATCH 007/952] Disconnect after issuing comand to Combo. --- .../plugins/PumpCombo/ComboPlugin.java | 75 +++++++++++-------- 1 file changed, 45 insertions(+), 30 deletions(-) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java index ffc4657254..5cbc914996 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java @@ -50,6 +50,7 @@ public class ComboPlugin implements PluginBase, PumpInterface { private ServiceConnection mRuffyServiceConnection; private static PumpEnactResult OPERATION_NOT_SUPPORTED = new PumpEnactResult(); + static { OPERATION_NOT_SUPPORTED.success = false; OPERATION_NOT_SUPPORTED.enacted = false; @@ -94,7 +95,7 @@ public class ComboPlugin implements PluginBase, PumpInterface { }; boolean success = context.bindService(intent, mRuffyServiceConnection, Context.BIND_AUTO_CREATE); - if(!success) { + if (!success) { log.error("Binding to ruffy service failed"); } } @@ -189,7 +190,8 @@ public class ComboPlugin implements PluginBase, PumpInterface { @Override public boolean isInitialized() { // TODO - return ruffyScripter != null; + // hm, lastCmdDate > 0, like the DanaR does it? + return true; // scripter does this as needed; ruffyScripter != null; } @Override @@ -239,16 +241,19 @@ public class ComboPlugin implements PluginBase, PumpInterface { @Override public PumpEnactResult deliverTreatment(DetailedBolusInfo detailedBolusInfo) { - Command command = new BolusCommand(detailedBolusInfo.insulin); - CommandResult commandResult = ruffyScripter.runCommand(command); + try { + Command command = new BolusCommand(detailedBolusInfo.insulin); + CommandResult commandResult = ruffyScripter.runCommand(command); - PumpEnactResult pumpEnactResult = new PumpEnactResult(); - pumpEnactResult.success = commandResult.success; - pumpEnactResult.enacted = commandResult.enacted; - pumpEnactResult.comment = commandResult.message; - pumpEnactResult.bolusDelivered = detailedBolusInfo.insulin; - - return pumpEnactResult; + PumpEnactResult pumpEnactResult = new PumpEnactResult(); + pumpEnactResult.success = commandResult.success; + pumpEnactResult.enacted = commandResult.enacted; + pumpEnactResult.comment = commandResult.message; + pumpEnactResult.bolusDelivered = detailedBolusInfo.insulin; + return pumpEnactResult; + } finally { + ruffyScripter.disconnect(); + } } @Override @@ -267,19 +272,24 @@ public class ComboPlugin implements PluginBase, PumpInterface { @Override public PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes) { // TODO make each cmd return all the data the main screen displays and cache here ? - Command command = new SetTbrCommand(percent, durationInMinutes); - CommandResult commandResult = ruffyScripter.runCommand(command); + try { + Command command = new SetTbrCommand(percent, durationInMinutes); + CommandResult commandResult = ruffyScripter.runCommand(command); - PumpEnactResult pumpEnactResult = new PumpEnactResult(); - pumpEnactResult.success = commandResult.success; - pumpEnactResult.enacted = commandResult.enacted; - pumpEnactResult.comment = commandResult.message; - pumpEnactResult.isPercent = true; - pumpEnactResult.percent = percent; + PumpEnactResult pumpEnactResult = new PumpEnactResult(); + pumpEnactResult.success = commandResult.success; + pumpEnactResult.enacted = commandResult.enacted; + pumpEnactResult.comment = commandResult.message; + pumpEnactResult.isPercent = true; + pumpEnactResult.percent = percent; - fakeBasalRate = fakeBasalRate * percent / 100; + //TODO + fakeBasalRate = fakeBasalRate * percent / 100; - return pumpEnactResult; + return pumpEnactResult; + } finally { + ruffyScripter.disconnect(); + } } // TODO @@ -291,18 +301,23 @@ public class ComboPlugin implements PluginBase, PumpInterface { // TODO @Override public PumpEnactResult cancelTempBasal() { - Command command = new CancelTbrCommand(); - CommandResult commandResult = ruffyScripter.runCommand(command); + try { + Command command = new CancelTbrCommand(); + CommandResult commandResult = ruffyScripter.runCommand(command); - PumpEnactResult pumpEnactResult = new PumpEnactResult(); - pumpEnactResult.success = commandResult.success; - pumpEnactResult.enacted = commandResult.enacted; - pumpEnactResult.comment = commandResult.message; - pumpEnactResult.isTempCancel = true; + PumpEnactResult pumpEnactResult = new PumpEnactResult(); + pumpEnactResult.success = commandResult.success; + pumpEnactResult.enacted = commandResult.enacted; + pumpEnactResult.comment = commandResult.message; + pumpEnactResult.isTempCancel = true; - fakeBasalRate = 0.5d; + //TODO + fakeBasalRate = 0.5d; - return pumpEnactResult; + return pumpEnactResult; + } finally { + ruffyScripter.disconnect(); + } } // TODO From 1f5c03b64e7a487deede381c87fb0fcb3a8c4bef Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Thu, 13 Jul 2017 20:19:22 +0200 Subject: [PATCH 008/952] Cleanups. --- .../main/java/de/jotomo/ruffyscripter/RuffyScripter.java | 6 ++---- .../java/de/jotomo/ruffyscripter/commands/BolusCommand.java | 3 +-- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java b/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java index 3c25f325cf..5b1c9b2ff8 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java @@ -104,10 +104,8 @@ public class RuffyScripter { private volatile Command activeCmd = null; - // TODO take a callback to call when command finishes? - // TODO sometimes hangs ... we should timeout and raise an alert to check the pump and ruffy - // TODO not getting a menu update in a while is a good cue ... - // fire up a monitoring thread for that? + // TODO fire up a monitoring thread to intervene when we're stuck? re-bind service + // in case ruffy app went away public CommandResult runCommand(final Command cmd) { try { if (isPumpBusy()) { diff --git a/app/src/main/java/de/jotomo/ruffyscripter/commands/BolusCommand.java b/app/src/main/java/de/jotomo/ruffyscripter/commands/BolusCommand.java index 2550c121e5..9a13180855 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/commands/BolusCommand.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/commands/BolusCommand.java @@ -81,8 +81,7 @@ public class BolusCommand implements Command { private void verifyDisplayedBolusAmount(RuffyScripter scripter) { double displayedBolus = (double) scripter.currentMenu.getAttribute(MenuAttribute.BOLUS); log.debug("Final bolus: " + displayedBolus); - // TODO can't we just use BigDecimal? doubles aren't precise ... - if (Math.abs(displayedBolus - bolus) > 0.001) { + if (Math.abs(displayedBolus - bolus) > 0.05) { throw new CommandException().message("Failed to set correct bolus. Expected: " + bolus + ", actual: " + displayedBolus); } } From 3b50a5ae70427630e115d1d068fed085cba14c37 Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Thu, 13 Jul 2017 22:17:07 +0200 Subject: [PATCH 009/952] Update Combo PumpDescription w.r.t extended bolus. --- .../androidaps/plugins/PumpCombo/ComboPlugin.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java index 5cbc914996..76ffd9352c 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java @@ -105,9 +105,9 @@ public class ComboPlugin implements PluginBase, PumpInterface { pumpDescription.bolusStep = 0.1d; pumpDescription.isExtendedBolusCapable = false; // TODO - pumpDescription.extendedBolusStep = 0.05d; - pumpDescription.extendedBolusDurationStep = 30; - pumpDescription.extendedBolusMaxDuration = 8 * 60; + pumpDescription.extendedBolusStep = 0.1d; + pumpDescription.extendedBolusDurationStep = 15; + pumpDescription.extendedBolusMaxDuration = 12 * 60; pumpDescription.isTempBasalCapable = true; pumpDescription.tempBasalStyle = PumpDescription.PERCENT; From 6842abd157df8ccccb822a42a1cc084764f13192 Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Fri, 14 Jul 2017 13:44:26 +0200 Subject: [PATCH 010/952] Provide fake current basal rate. --- .../plugins/PumpCombo/ComboPlugin.java | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java index 76ffd9352c..557b2caae4 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java @@ -57,8 +57,6 @@ public class ComboPlugin implements PluginBase, PumpInterface { OPERATION_NOT_SUPPORTED.comment = "Requested operation not supported by pump"; } - private double fakeBasalRate = 0.5d; - public ComboPlugin() { definePumpCapabilities(); bindRuffyService(); @@ -121,7 +119,7 @@ public class ComboPlugin implements PluginBase, PumpInterface { pumpDescription.isSetBasalProfileCapable = false; // TODO pumpDescription.basalStep = 0.01d; - pumpDescription.basalMinimumRate = 0.01d; + pumpDescription.basalMinimumRate = 0.0d; pumpDescription.isRefillingCapable = false; } @@ -235,8 +233,9 @@ public class ComboPlugin implements PluginBase, PumpInterface { // TODO @Override public double getBaseBasalRate() { - // TODO this is simple to read, w/o causing vibirations, it's BASAL_RATE in the main menu - return fakeBasalRate; + // TODO this is simple to read, w/o causing vibrations, it's BASAL_RATE in the main menu + // and/or read this from a cached basal rate profile + return 0.5d; } @Override @@ -282,10 +281,6 @@ public class ComboPlugin implements PluginBase, PumpInterface { pumpEnactResult.comment = commandResult.message; pumpEnactResult.isPercent = true; pumpEnactResult.percent = percent; - - //TODO - fakeBasalRate = fakeBasalRate * percent / 100; - return pumpEnactResult; } finally { ruffyScripter.disconnect(); @@ -310,10 +305,6 @@ public class ComboPlugin implements PluginBase, PumpInterface { pumpEnactResult.enacted = commandResult.enacted; pumpEnactResult.comment = commandResult.message; pumpEnactResult.isTempCancel = true; - - //TODO - fakeBasalRate = 0.5d; - return pumpEnactResult; } finally { ruffyScripter.disconnect(); From 5f1ab4e45cf47268469247db5c6f8764ae28f7cf Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Fri, 14 Jul 2017 14:15:35 +0200 Subject: [PATCH 011/952] Set duration in PumpEnactResult when issuing SetTbrCommand. --- .../nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java index 557b2caae4..da1097152a 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java @@ -248,6 +248,8 @@ public class ComboPlugin implements PluginBase, PumpInterface { pumpEnactResult.success = commandResult.success; pumpEnactResult.enacted = commandResult.enacted; pumpEnactResult.comment = commandResult.message; + // Combo would have bailed if this wasn't set properly. Maybe we should + // have the command return this anyways ... pumpEnactResult.bolusDelivered = detailedBolusInfo.insulin; return pumpEnactResult; } finally { @@ -280,7 +282,10 @@ public class ComboPlugin implements PluginBase, PumpInterface { pumpEnactResult.enacted = commandResult.enacted; pumpEnactResult.comment = commandResult.message; pumpEnactResult.isPercent = true; + // Combo would have bailed if this wasn't set properly. Maybe we should + // have the command return this anyways ... pumpEnactResult.percent = percent; + pumpEnactResult.duration = durationInMinutes; return pumpEnactResult; } finally { ruffyScripter.disconnect(); From 1c1a28f0a82b867d45321fda37e2a3d76bc7250d Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Fri, 14 Jul 2017 14:52:39 +0200 Subject: [PATCH 012/952] Ignore requests to issue BolusCommands for zero units. --- .../androidaps/plugins/PumpCombo/ComboPlugin.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java index da1097152a..61965da5d7 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java @@ -240,6 +240,17 @@ public class ComboPlugin implements PluginBase, PumpInterface { @Override public PumpEnactResult deliverTreatment(DetailedBolusInfo detailedBolusInfo) { + if (detailedBolusInfo.insulin < 0.05) { + log.debug("Ignoring request to deliver bolus of " + detailedBolusInfo.insulin + " U"); + // Don't bother the pump when only carbs have been entered + // TODO find out if this should be prevented earlier on, or if there's a reason + // the pump (danar?) is still called (fetch data for next calc?) + PumpEnactResult pumpEnactResult = new PumpEnactResult(); + pumpEnactResult.success = true; + pumpEnactResult.enacted = false; + pumpEnactResult.bolusDelivered = 0d; + return pumpEnactResult; + } try { Command command = new BolusCommand(detailedBolusInfo.insulin); CommandResult commandResult = ruffyScripter.runCommand(command); From 97f9e9943727758e887730dcdcfe54e42376a4dc Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Fri, 14 Jul 2017 15:01:20 +0200 Subject: [PATCH 013/952] toString methods for Commands. --- .../de/jotomo/ruffyscripter/commands/BolusCommand.java | 7 +++++++ .../jotomo/ruffyscripter/commands/CancelTbrCommand.java | 5 +++++ .../de/jotomo/ruffyscripter/commands/SetTbrCommand.java | 8 ++++++++ 3 files changed, 20 insertions(+) diff --git a/app/src/main/java/de/jotomo/ruffyscripter/commands/BolusCommand.java b/app/src/main/java/de/jotomo/ruffyscripter/commands/BolusCommand.java index 9a13180855..a957015604 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/commands/BolusCommand.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/commands/BolusCommand.java @@ -85,4 +85,11 @@ public class BolusCommand implements Command { throw new CommandException().message("Failed to set correct bolus. Expected: " + bolus + ", actual: " + displayedBolus); } } + + @Override + public String toString() { + return "BolusCommand{" + + "bolus=" + bolus + + '}'; + } } diff --git a/app/src/main/java/de/jotomo/ruffyscripter/commands/CancelTbrCommand.java b/app/src/main/java/de/jotomo/ruffyscripter/commands/CancelTbrCommand.java index 40baeab2a6..ed9fb1e18f 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/commands/CancelTbrCommand.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/commands/CancelTbrCommand.java @@ -17,4 +17,9 @@ public class CancelTbrCommand implements Command { } return new SetTbrCommand(100, 0).execute(scripter); } + + @Override + public String toString() { + return "CancelTbrCommand{}"; + } } diff --git a/app/src/main/java/de/jotomo/ruffyscripter/commands/SetTbrCommand.java b/app/src/main/java/de/jotomo/ruffyscripter/commands/SetTbrCommand.java index 25a02229f9..33efba8318 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/commands/SetTbrCommand.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/commands/SetTbrCommand.java @@ -235,4 +235,12 @@ public class SetTbrCommand implements Command { throw new CommandException().message("Setting TBR failed, TBR in MAIN_MENU differs from expected"); } } + + @Override + public String toString() { + return "SetTbrCommand{" + + "percentage=" + percentage + + ", duration=" + duration + + '}'; + } } From e07d62bf7926b1db3d912bc1bbda44e060f97a7b Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Fri, 14 Jul 2017 15:59:47 +0200 Subject: [PATCH 014/952] Fix setting TBR when existing TBR has runtime < 15m. --- .../de/jotomo/ruffyscripter/commands/SetTbrCommand.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/de/jotomo/ruffyscripter/commands/SetTbrCommand.java b/app/src/main/java/de/jotomo/ruffyscripter/commands/SetTbrCommand.java index 33efba8318..6059252c3a 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/commands/SetTbrCommand.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/commands/SetTbrCommand.java @@ -137,9 +137,11 @@ public class SetTbrCommand implements Command { long currentDuration = readDisplayedTbrDuration(scripter); if (currentDuration % 15 != 0) { // The duration displayed is how long an active TBR will still run, - // which might be something like 0:43, hence not in 15 minute steps. - // Pressing down will go to the next lower 15 minute step. - scripter.pressDownKey(); + // which might be something like 0:13, hence not in 15 minute steps. + // Pressing up will go to the next higher 15 minute step. + // Don't press down, from 0:13 it can't go down, so press up. + // Pressing up from 23:59 works to go to 24:00. + scripter.pressUpKey(); scripter.waitForMenuUpdate(); currentDuration = readDisplayedTbrDuration(scripter); } From d39d58913d0b34891e3330ba121b59ebb2ae6796 Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Fri, 14 Jul 2017 16:19:53 +0200 Subject: [PATCH 015/952] Implement #8, add treatment to history. --- .../plugins/PumpCombo/ComboPlugin.java | 60 ++++++++++++------- 1 file changed, 39 insertions(+), 21 deletions(-) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java index 61965da5d7..e8ff5ada8b 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java @@ -23,6 +23,7 @@ import de.jotomo.ruffyscripter.commands.Command; import de.jotomo.ruffyscripter.commands.CommandResult; import de.jotomo.ruffyscripter.commands.SetTbrCommand; import info.nightscout.androidaps.BuildConfig; +import info.nightscout.androidaps.Config; import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.R; import info.nightscout.androidaps.data.DetailedBolusInfo; @@ -32,6 +33,7 @@ import info.nightscout.androidaps.events.EventAppExit; import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PumpDescription; import info.nightscout.androidaps.interfaces.PumpInterface; +import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.utils.DateUtil; /** @@ -240,29 +242,45 @@ public class ComboPlugin implements PluginBase, PumpInterface { @Override public PumpEnactResult deliverTreatment(DetailedBolusInfo detailedBolusInfo) { - if (detailedBolusInfo.insulin < 0.05) { - log.debug("Ignoring request to deliver bolus of " + detailedBolusInfo.insulin + " U"); - // Don't bother the pump when only carbs have been entered - // TODO find out if this should be prevented earlier on, or if there's a reason - // the pump (danar?) is still called (fetch data for next calc?) - PumpEnactResult pumpEnactResult = new PumpEnactResult(); - pumpEnactResult.success = true; - pumpEnactResult.enacted = false; - pumpEnactResult.bolusDelivered = 0d; - return pumpEnactResult; + ConfigBuilderPlugin configBuilderPlugin = MainApp.getConfigBuilder(); + detailedBolusInfo.insulin = configBuilderPlugin.applyBolusConstraints(detailedBolusInfo.insulin); + if (detailedBolusInfo.insulin > 0 || detailedBolusInfo.carbs > 0) { + PumpEnactResult result = new PumpEnactResult(); + if (detailedBolusInfo.insulin > 0) { + CommandResult bolusCmdResult = runCommand(new BolusCommand(detailedBolusInfo.insulin)); + result.success = bolusCmdResult.success; + result.enacted = bolusCmdResult.enacted; + result.bolusDelivered = detailedBolusInfo.insulin; + result.comment = MainApp.instance().getString(R.string.virtualpump_resultok); + } else { + result.success = true; + result.enacted = false; + } + result.carbsDelivered = detailedBolusInfo.carbs; + result.comment = MainApp.instance().getString(R.string.virtualpump_resultok); + if (Config.logPumpActions) + log.debug("deliverTreatment: OK. Asked: " + detailedBolusInfo.insulin + " Delivered: " + result.bolusDelivered); + detailedBolusInfo.date = new Date().getTime(); + MainApp.getConfigBuilder().addToHistoryTreatment(detailedBolusInfo); + return result; + } else { + PumpEnactResult result = new PumpEnactResult(); + result.success = false; + result.bolusDelivered = 0d; + result.carbsDelivered = 0d; + result.comment = MainApp.instance().getString(R.string.danar_invalidinput); + log.error("deliverTreatment: Invalid input"); + return result; } - try { - Command command = new BolusCommand(detailedBolusInfo.insulin); - CommandResult commandResult = ruffyScripter.runCommand(command); + } - PumpEnactResult pumpEnactResult = new PumpEnactResult(); - pumpEnactResult.success = commandResult.success; - pumpEnactResult.enacted = commandResult.enacted; - pumpEnactResult.comment = commandResult.message; - // Combo would have bailed if this wasn't set properly. Maybe we should - // have the command return this anyways ... - pumpEnactResult.bolusDelivered = detailedBolusInfo.insulin; - return pumpEnactResult; + private CommandResult runCommand(Command command) { + // TODO call this for all cmnds + // TODO use this to disptach methods to a service thread, like DanaRs executionService + // TODO add a monitor-something that raises an alarm if the command has finished + // with 90s or so + try { + return ruffyScripter.runCommand(command); } finally { ruffyScripter.disconnect(); } From 76578872d10f5ee5e84b1d6f85bf6b14d9bbc232 Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Fri, 14 Jul 2017 17:07:50 +0200 Subject: [PATCH 016/952] ComoPlugin.deliverTreatment: take more time. Even if not interacting with the pump, AAPS calculator doesn't dismiss the dialog if we return within the first 5s. --- .../nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java index e8ff5ada8b..89cbe4e86b 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java @@ -5,6 +5,7 @@ import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.IBinder; +import android.os.SystemClock; import com.squareup.otto.Subscribe; @@ -253,6 +254,10 @@ public class ComboPlugin implements PluginBase, PumpInterface { result.bolusDelivered = detailedBolusInfo.insulin; result.comment = MainApp.instance().getString(R.string.virtualpump_resultok); } else { + // TODO the ui freezes when the calculator issues a carb-only treatment + // so just wait, yeah, this is dumb. for now; proper fix via GL#10 + // info.nightscout.androidaps.plugins.Overview.Dialogs.BolusProgressDialog.scheduleDismiss() + SystemClock.sleep(6000); result.success = true; result.enacted = false; } From d35d93ed445d2bb41b7accc6d48c54b926b2bb9c Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Fri, 14 Jul 2017 17:28:57 +0200 Subject: [PATCH 017/952] RuffyScripter.verifyMenuIsDisplayed: wait a bit longer if needed. Sometimes the pump seems to take a bit longer. --- .../jotomo/ruffyscripter/RuffyScripter.java | 41 +++++++++++-------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java b/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java index 5b1c9b2ff8..11c782b5b7 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java @@ -158,16 +158,16 @@ public class RuffyScripter { // did we get a menu update from the pump in the last 5s? Then we're connected if (currentMenu != null && menuLastUpdated + 5000 > System.currentTimeMillis()) { log.debug("Pump is sending us menu updating, so we're connected"); - return; + return; } try { - boolean connectSuccesful = ruffyService.doRTConnect() == 0; - log.debug("Connect init successful: " + connectSuccesful); - while (currentMenu == null) { - log.debug("Waiting for first menu update to be sent"); - waitForMenuUpdate(); - } + boolean connectSuccesful = ruffyService.doRTConnect() == 0; + log.debug("Connect init successful: " + connectSuccesful); + while (currentMenu == null) { + log.debug("Waiting for first menu update to be sent"); + waitForMenuUpdate(); + } } catch (RemoteException e) { throw new CommandException().exception(e).message("Unexpected exception while initiating/restoring pump connection"); } @@ -209,12 +209,14 @@ public class RuffyScripter { pressKey(Key.MENU); } - /** Wait until the menu update is in */ + /** + * Wait until the menu update is in + */ public void waitForMenuUpdate() { long timeoutExpired = System.currentTimeMillis() + 90 * 1000; long initialUpdateTime = menuLastUpdated; while (initialUpdateTime == menuLastUpdated) { - if(System.currentTimeMillis() > timeoutExpired) { + if (System.currentTimeMillis() > timeoutExpired) { throw new CommandException().message("Timeout waiting for menu update"); } SystemClock.sleep(50); @@ -232,7 +234,6 @@ public class RuffyScripter { SystemClock.sleep(100); ruffyService.rtSendKey(Key.NO_KEY, true); }*/ - private void pressKey(final byte key) { try { ruffyService.rtSendKey(key, true); @@ -269,16 +270,22 @@ public class RuffyScripter { } } - public void verifyMenuIsDisplayed(MenuType menu) { - String message = "Invalid pump state, expected to be in menu " - + menu + ", but current menu is " + currentMenu.getType(); - verifyMenuIsDisplayed(menu, message); + public void verifyMenuIsDisplayed(MenuType expectedMenu) { + String failureMessage = "Invalid pump state, expected to be in menu " + + expectedMenu + ", but current menu is " + currentMenu.getType(); + verifyMenuIsDisplayed(expectedMenu, failureMessage); } - public void verifyMenuIsDisplayed(MenuType menu, String message) { + public void verifyMenuIsDisplayed(MenuType expectedMenu, String failureMessage) { waitForMenuUpdate(); - if (currentMenu.getType() != menu) { - throw new CommandException().message(message); + int retries = 5; + while (currentMenu.getType() != expectedMenu) { + if (retries > 0) { + SystemClock.sleep(200); + retries = retries - 1; + } else { + throw new CommandException().message(failureMessage); + } } } } From a27bb28e87f70b262fd9e291a889b162a6bc7360 Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Fri, 14 Jul 2017 17:30:04 +0200 Subject: [PATCH 018/952] ComboPlugin.deliverTreatment: return command message as comment in PumpEnactResult. Important when there's an error. --- .../nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java index 89cbe4e86b..a7edba0f17 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java @@ -252,7 +252,7 @@ public class ComboPlugin implements PluginBase, PumpInterface { result.success = bolusCmdResult.success; result.enacted = bolusCmdResult.enacted; result.bolusDelivered = detailedBolusInfo.insulin; - result.comment = MainApp.instance().getString(R.string.virtualpump_resultok); + result.comment = bolusCmdResult.message; } else { // TODO the ui freezes when the calculator issues a carb-only treatment // so just wait, yeah, this is dumb. for now; proper fix via GL#10 From e29ef5ffce4fd9500fded4a32c12a21738008461 Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Fri, 14 Jul 2017 18:20:36 +0200 Subject: [PATCH 019/952] Update treatment history when setting/cancelling a TBR. --- .../plugins/PumpCombo/ComboPlugin.java | 73 +++++++++++-------- 1 file changed, 42 insertions(+), 31 deletions(-) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java index a7edba0f17..b1ce489b5f 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java @@ -30,7 +30,10 @@ import info.nightscout.androidaps.R; 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.TemporaryBasal; import info.nightscout.androidaps.events.EventAppExit; +import info.nightscout.androidaps.events.EventPumpStatusChanged; import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PumpDescription; import info.nightscout.androidaps.interfaces.PumpInterface; @@ -287,7 +290,10 @@ public class ComboPlugin implements PluginBase, PumpInterface { try { return ruffyScripter.runCommand(command); } finally { +// MainApp.bus().post(new EventPumpStatusChanged(EventPumpStatusChanged.DISCONNECTING)); ruffyScripter.disconnect(); +// MainApp.bus().post(new EventPumpStatusChanged(EventPumpStatusChanged.DISCONNECTED)); +// MainApp.bus().post(new EventComboPumpUpdateGUI()); } } @@ -306,48 +312,53 @@ public class ComboPlugin implements PluginBase, PumpInterface { @Override public PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes) { - // TODO make each cmd return all the data the main screen displays and cache here ? - try { - Command command = new SetTbrCommand(percent, durationInMinutes); - CommandResult commandResult = ruffyScripter.runCommand(command); - - PumpEnactResult pumpEnactResult = new PumpEnactResult(); - pumpEnactResult.success = commandResult.success; - pumpEnactResult.enacted = commandResult.enacted; - pumpEnactResult.comment = commandResult.message; - pumpEnactResult.isPercent = true; - // Combo would have bailed if this wasn't set properly. Maybe we should - // have the command return this anyways ... - pumpEnactResult.percent = percent; - pumpEnactResult.duration = durationInMinutes; - return pumpEnactResult; - } finally { - ruffyScripter.disconnect(); + MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.settingtempbasal))); + CommandResult commandResult = runCommand(new SetTbrCommand(percent, durationInMinutes)); + if (commandResult.enacted) { + TemporaryBasal tempStart = new TemporaryBasal(System.currentTimeMillis()); + tempStart.durationInMinutes = durationInMinutes; + tempStart.percentRate = percent; + tempStart.isAbsolute = false; + tempStart.source = Source.USER; + ConfigBuilderPlugin treatmentsInterface = MainApp.getConfigBuilder(); + treatmentsInterface.addToHistoryTempBasal(tempStart); } + + PumpEnactResult pumpEnactResult = new PumpEnactResult(); + pumpEnactResult.success = commandResult.success; + pumpEnactResult.enacted = commandResult.enacted; + pumpEnactResult.comment = commandResult.message; + pumpEnactResult.isPercent = true; + // Combo would have bailed if this wasn't set properly. Maybe we should + // have the command return this anyways ... + pumpEnactResult.percent = percent; + pumpEnactResult.duration = durationInMinutes; + return pumpEnactResult; } - // TODO @Override public PumpEnactResult setExtendedBolus(Double insulin, Integer durationInMinutes) { return OPERATION_NOT_SUPPORTED; } - // TODO @Override public PumpEnactResult cancelTempBasal() { - try { - Command command = new CancelTbrCommand(); - CommandResult commandResult = ruffyScripter.runCommand(command); - - PumpEnactResult pumpEnactResult = new PumpEnactResult(); - pumpEnactResult.success = commandResult.success; - pumpEnactResult.enacted = commandResult.enacted; - pumpEnactResult.comment = commandResult.message; - pumpEnactResult.isTempCancel = true; - return pumpEnactResult; - } finally { - ruffyScripter.disconnect(); + MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.stoppingtempbasal))); + CommandResult commandResult = runCommand(new CancelTbrCommand()); + if(commandResult.enacted) { + TemporaryBasal tempStop = new TemporaryBasal(new Date().getTime()); + tempStop.durationInMinutes = 0; // == ending temp basal + tempStop.source = Source.USER; + ConfigBuilderPlugin treatmentsInterface = MainApp.getConfigBuilder(); + treatmentsInterface.addToHistoryTempBasal(tempStop); } + + PumpEnactResult pumpEnactResult = new PumpEnactResult(); + pumpEnactResult.success = commandResult.success; + pumpEnactResult.enacted = commandResult.enacted; + pumpEnactResult.comment = commandResult.message; + pumpEnactResult.isTempCancel = true; + return pumpEnactResult; } // TODO From f34fed1f050376e21f05f977e325cffbb2d035d2 Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Fri, 14 Jul 2017 20:23:54 +0200 Subject: [PATCH 020/952] Semi-fix bolusing not logging a treatment when there was an error. --- .../plugins/PumpCombo/ComboPlugin.java | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java index b1ce489b5f..3b5bcb11a9 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java @@ -244,6 +244,7 @@ public class ComboPlugin implements PluginBase, PumpInterface { return 0.5d; } + // TODO rewrite this crap into something comprehensible @Override public PumpEnactResult deliverTreatment(DetailedBolusInfo detailedBolusInfo) { ConfigBuilderPlugin configBuilderPlugin = MainApp.getConfigBuilder(); @@ -254,6 +255,9 @@ public class ComboPlugin implements PluginBase, PumpInterface { CommandResult bolusCmdResult = runCommand(new BolusCommand(detailedBolusInfo.insulin)); result.success = bolusCmdResult.success; result.enacted = bolusCmdResult.enacted; + // TODO if no error occurred, the requested bolus is what the pump delievered, + // that has been checked. If an error occurred, we should check how much insulin + // was delivered, e.g. when the cartridge went empty mid-bolus result.bolusDelivered = detailedBolusInfo.insulin; result.comment = bolusCmdResult.message; } else { @@ -264,12 +268,14 @@ public class ComboPlugin implements PluginBase, PumpInterface { result.success = true; result.enacted = false; } - result.carbsDelivered = detailedBolusInfo.carbs; - result.comment = MainApp.instance().getString(R.string.virtualpump_resultok); - if (Config.logPumpActions) - log.debug("deliverTreatment: OK. Asked: " + detailedBolusInfo.insulin + " Delivered: " + result.bolusDelivered); - detailedBolusInfo.date = new Date().getTime(); - MainApp.getConfigBuilder().addToHistoryTreatment(detailedBolusInfo); + if (result.enacted) { + result.carbsDelivered = detailedBolusInfo.carbs; + result.comment = MainApp.instance().getString(R.string.virtualpump_resultok); + if (Config.logPumpActions) + log.debug("deliverTreatment: OK. Asked: " + detailedBolusInfo.insulin + " Delivered: " + result.bolusDelivered); + detailedBolusInfo.date = new Date().getTime(); + MainApp.getConfigBuilder().addToHistoryTreatment(detailedBolusInfo); + } return result; } else { PumpEnactResult result = new PumpEnactResult(); @@ -346,8 +352,8 @@ public class ComboPlugin implements PluginBase, PumpInterface { MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.stoppingtempbasal))); CommandResult commandResult = runCommand(new CancelTbrCommand()); if(commandResult.enacted) { - TemporaryBasal tempStop = new TemporaryBasal(new Date().getTime()); - tempStop.durationInMinutes = 0; // == ending temp basal + TemporaryBasal tempStop = new TemporaryBasal(System.currentTimeMillis()); + tempStop.durationInMinutes = 0; // ending temp basal tempStop.source = Source.USER; ConfigBuilderPlugin treatmentsInterface = MainApp.getConfigBuilder(); treatmentsInterface.addToHistoryTempBasal(tempStop); From 0729d7a114af89559259aedc9ed0d7da49f45f3b Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Fri, 14 Jul 2017 20:24:32 +0200 Subject: [PATCH 021/952] RuffyScripter: Abort a running command after 90s timeout --- .../jotomo/ruffyscripter/RuffyScripter.java | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java b/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java index 11c782b5b7..175536172a 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java @@ -113,6 +113,9 @@ public class RuffyScripter { } ensureConnected(); + // TODO reuse thread, scheduler ... + Thread cmdThread; + // TODO make this a safe lock synchronized (this) { cmdResult = null; @@ -122,7 +125,7 @@ public class RuffyScripter { // wait till pump is ready for input waitForMenuUpdate(); log.debug("Cmd execution: connection ready, executing cmd " + cmd); - new Thread(new Runnable() { + cmdThread = new Thread(new Runnable() { @Override public void run() { try { @@ -134,16 +137,25 @@ public class RuffyScripter { } } - }).start(); + }); + cmdThread.start(); } // TODO really? + long timeout = System.currentTimeMillis() + 90 * 1000; while (activeCmd != null) { SystemClock.sleep(500); log.trace("Waiting for running command to complete"); + if (System.currentTimeMillis() > timeout) { + log.error("Running command " + activeCmd + " timed out"); + cmdThread.interrupt(); + activeCmd = null; + cmdResult = null; + return new CommandResult().success(false).enacted(false).message("Command timed out"); + } } - log.debug("Command result: " + cmdResult); + log.debug("Command result: " + cmdResult); CommandResult r = cmdResult; cmdResult = null; return r; @@ -162,10 +174,11 @@ public class RuffyScripter { } try { - boolean connectSuccesful = ruffyService.doRTConnect() == 0; - log.debug("Connect init successful: " + connectSuccesful); + boolean connectInitSuccessful = ruffyService.doRTConnect() == 0; + log.debug("Connect init successful: " + connectInitSuccessful); while (currentMenu == null) { log.debug("Waiting for first menu update to be sent"); + // waitForMenuUpdate times out after 90s and throws a CommandException waitForMenuUpdate(); } } catch (RemoteException e) { From 336315823e8febb8e8bf8c8fdc3586fd50da5f93 Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Fri, 14 Jul 2017 21:49:43 +0200 Subject: [PATCH 022/952] ComboPlugin.getBaseBasalRate: return profile value. --- .../androidaps/plugins/PumpCombo/ComboPlugin.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java index 3b5bcb11a9..e545cd5509 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java @@ -230,18 +230,22 @@ public class ComboPlugin implements PluginBase, PumpInterface { // TODO @Override public void refreshDataFromPump(String reason) { -// this is called regulary from keepalive + log.debug("RefreshDataFromPump called"); + + // this is called regulary from keepalive // TODO how often is this called? use this to run checks regularly, e.g. // recheck active TBR, basal rate to ensure nothing broke? } - // TODO + // TODO uses profile values for the time being + // this get's called mulitple times a minute, must absolutely be cached @Override public double getBaseBasalRate() { - // TODO this is simple to read, w/o causing vibrations, it's BASAL_RATE in the main menu - // and/or read this from a cached basal rate profile - return 0.5d; + Profile profile = MainApp.getConfigBuilder().getProfile(); + Double basal = profile.getBasal(); + log.debug("getBaseBasalrate returning " + basal); + return basal; } // TODO rewrite this crap into something comprehensible From 264e252300591f6b17feb6e9f0b194bf3aad7366 Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Fri, 14 Jul 2017 21:57:30 +0200 Subject: [PATCH 023/952] Set last command date. Though this is only relevant when starting to fetch data from the pump. --- .../nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java index e545cd5509..115445683a 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java @@ -301,6 +301,7 @@ public class ComboPlugin implements PluginBase, PumpInterface { return ruffyScripter.runCommand(command); } finally { // MainApp.bus().post(new EventPumpStatusChanged(EventPumpStatusChanged.DISCONNECTING)); + lastCmdTime = new Date(); ruffyScripter.disconnect(); // MainApp.bus().post(new EventPumpStatusChanged(EventPumpStatusChanged.DISCONNECTED)); // MainApp.bus().post(new EventComboPumpUpdateGUI()); From 9674db8d855a09b8cdd673b261d76575694ae624 Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Fri, 14 Jul 2017 23:00:15 +0200 Subject: [PATCH 024/952] CancelTbrCommand: set enacted=true, even when there was no TBR to cancel. This helps recover when there was an issue. AAPS thinks there's a TBR running and by reporting back 'enacted', the plugin will create a "Cancel temp" treatment. --- .../de/jotomo/ruffyscripter/commands/CancelTbrCommand.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/de/jotomo/ruffyscripter/commands/CancelTbrCommand.java b/app/src/main/java/de/jotomo/ruffyscripter/commands/CancelTbrCommand.java index ed9fb1e18f..2f5c03f6e5 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/commands/CancelTbrCommand.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/commands/CancelTbrCommand.java @@ -13,7 +13,11 @@ public class CancelTbrCommand implements Command { Double tbrPercentage = (Double) scripter.currentMenu.getAttribute(MenuAttribute.TBR); boolean runtimeDisplayed = scripter.currentMenu.attributes().contains(MenuAttribute.RUNTIME); if (tbrPercentage == 100 && !runtimeDisplayed) { - return new CommandResult().success(true).enacted(false).message("No TBR active"); + return new CommandResult() + .success(true) + .enacted(true) // technically, nothing was enacted, but AAPS needs this to recover + // when there was an issue and AAPS thinks a TBR is still active + .message("No TBR active"); } return new SetTbrCommand(100, 0).execute(scripter); } From 848a32eade9680bcc7ad65c5b927d8a3a1aab752 Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Fri, 14 Jul 2017 23:06:34 +0200 Subject: [PATCH 025/952] Logging cleanup. --- .../androidaps/plugins/PumpCombo/ComboPlugin.java | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java index 115445683a..b0bab1769e 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java @@ -244,13 +244,14 @@ public class ComboPlugin implements PluginBase, PumpInterface { public double getBaseBasalRate() { Profile profile = MainApp.getConfigBuilder().getProfile(); Double basal = profile.getBasal(); - log.debug("getBaseBasalrate returning " + basal); + log.trace("getBaseBasalrate returning " + basal); return basal; } // TODO rewrite this crap into something comprehensible @Override public PumpEnactResult deliverTreatment(DetailedBolusInfo detailedBolusInfo) { + log.debug("deliver treatment called with dbi: " + detailedBolusInfo); ConfigBuilderPlugin configBuilderPlugin = MainApp.getConfigBuilder(); detailedBolusInfo.insulin = configBuilderPlugin.applyBolusConstraints(detailedBolusInfo.insulin); if (detailedBolusInfo.insulin > 0 || detailedBolusInfo.carbs > 0) { @@ -293,18 +294,14 @@ public class ComboPlugin implements PluginBase, PumpInterface { } private CommandResult runCommand(Command command) { - // TODO call this for all cmnds - // TODO use this to disptach methods to a service thread, like DanaRs executionService - // TODO add a monitor-something that raises an alarm if the command has finished - // with 90s or so + // TODO use this to dispatch methods to a service thread, like DanaRs executionService try { + MainApp.bus().post(new EventPumpStatusChanged(EventPumpStatusChanged.CONNECTED)); return ruffyScripter.runCommand(command); } finally { -// MainApp.bus().post(new EventPumpStatusChanged(EventPumpStatusChanged.DISCONNECTING)); lastCmdTime = new Date(); ruffyScripter.disconnect(); -// MainApp.bus().post(new EventPumpStatusChanged(EventPumpStatusChanged.DISCONNECTED)); -// MainApp.bus().post(new EventComboPumpUpdateGUI()); + MainApp.bus().post(new EventPumpStatusChanged(EventPumpStatusChanged.DISCONNECTED)); } } @@ -323,6 +320,7 @@ public class ComboPlugin implements PluginBase, PumpInterface { @Override public PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes) { + log.debug("setTempBasalPercent called with " + percent + "% for " + durationInMinutes + "min"); MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.settingtempbasal))); CommandResult commandResult = runCommand(new SetTbrCommand(percent, durationInMinutes)); if (commandResult.enacted) { @@ -354,6 +352,7 @@ public class ComboPlugin implements PluginBase, PumpInterface { @Override public PumpEnactResult cancelTempBasal() { + log.debug("cancelTempBasal called"); MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.stoppingtempbasal))); CommandResult commandResult = runCommand(new CancelTbrCommand()); if(commandResult.enacted) { From a21da8aba7464a746618c782344ad3e9ae1bb3d1 Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Sat, 15 Jul 2017 02:00:20 +0200 Subject: [PATCH 026/952] Remove pointless events about connection status. --- .../nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java index b0bab1769e..1cd73c58e0 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java @@ -296,12 +296,10 @@ public class ComboPlugin implements PluginBase, PumpInterface { private CommandResult runCommand(Command command) { // TODO use this to dispatch methods to a service thread, like DanaRs executionService try { - MainApp.bus().post(new EventPumpStatusChanged(EventPumpStatusChanged.CONNECTED)); return ruffyScripter.runCommand(command); } finally { lastCmdTime = new Date(); ruffyScripter.disconnect(); - MainApp.bus().post(new EventPumpStatusChanged(EventPumpStatusChanged.DISCONNECTED)); } } From 8e2cd844a552386600674cc7f3fa22ee17cfb66a Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Sat, 15 Jul 2017 03:04:25 +0200 Subject: [PATCH 027/952] Round requested absolute TBR to percent TBR. --- .../androidaps/plugins/PumpCombo/ComboPlugin.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java index 1cd73c58e0..9033faffe2 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java @@ -310,15 +310,25 @@ public class ComboPlugin implements PluginBase, PumpInterface { // till pump times out or raises an error } - // TODO @Override public PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes) { - return OPERATION_NOT_SUPPORTED; + log.debug("setTempBasalAbsolute called with a rate of " + absoluteRate + " for " + durationInMinutes + " min."); + int unroundedPercentage = Double.valueOf(absoluteRate / getBaseBasalRate() * 100).intValue(); + int roundedPercentage = (int) (Math.round(absoluteRate/ getBaseBasalRate() * 10) * 10); + if (unroundedPercentage != roundedPercentage) + log.debug("Rounded requested rate " + unroundedPercentage + "% -> " + roundedPercentage + "%"); + return setTempBasalPercent(roundedPercentage, durationInMinutes); } @Override public PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes) { log.debug("setTempBasalPercent called with " + percent + "% for " + durationInMinutes + "min"); + if (percent % 10 != 0) { + int rounded = percent; + while (rounded % 10 != 0) rounded = rounded - 1; + log.debug("Rounded requested percentage from " + percent + " to " + rounded); + percent = rounded; + } MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.settingtempbasal))); CommandResult commandResult = runCommand(new SetTbrCommand(percent, durationInMinutes)); if (commandResult.enacted) { From df58b6d1c22e51c9dd0aa5e6d52c8187348b87ec Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Sat, 15 Jul 2017 11:16:06 +0200 Subject: [PATCH 028/952] CancelTbrCommand: log running TBR to be cancelled. --- .../de/jotomo/ruffyscripter/commands/CancelTbrCommand.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/src/main/java/de/jotomo/ruffyscripter/commands/CancelTbrCommand.java b/app/src/main/java/de/jotomo/ruffyscripter/commands/CancelTbrCommand.java index 2f5c03f6e5..847d9b6fb8 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/commands/CancelTbrCommand.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/commands/CancelTbrCommand.java @@ -2,11 +2,15 @@ package de.jotomo.ruffyscripter.commands; import org.monkey.d.ruffy.ruffy.driver.display.MenuAttribute; import org.monkey.d.ruffy.ruffy.driver.display.MenuType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import de.jotomo.ruffyscripter.RuffyScripter; // TODO robustness: can a TBR run out, whilst we're trying to cancel it? public class CancelTbrCommand implements Command { + private static final Logger log = LoggerFactory.getLogger(CancelTbrCommand.class); + @Override public CommandResult execute(RuffyScripter scripter) { scripter.verifyMenuIsDisplayed(MenuType.MAIN_MENU); @@ -19,6 +23,7 @@ public class CancelTbrCommand implements Command { // when there was an issue and AAPS thinks a TBR is still active .message("No TBR active"); } + log.debug("Cancelling active TBR of " + tbrPercentage + "% with " + runtimeDisplayed + "min remaining"); return new SetTbrCommand(100, 0).execute(scripter); } From 8c107cb48a00b2173e93d98179d307b72c34dc70 Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Sat, 15 Jul 2017 11:17:24 +0200 Subject: [PATCH 029/952] RuffyScripter: Log button presses. --- .../main/java/de/jotomo/ruffyscripter/RuffyScripter.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java b/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java index 175536172a..be59c82c09 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java @@ -206,20 +206,28 @@ public class RuffyScripter { } public void pressUpKey() { + log.debug("Pressing up key"); pressKey(Key.UP); + log.debug("Releasing up key"); } public void pressDownKey() { + log.debug("Pressing down key"); pressKey(Key.DOWN); + log.debug("Releasing down key"); } public void pressCheckKey() { + log.debug("Pressing check key"); pressKey(Key.CHECK); + log.debug("Releasing check key"); } public void pressMenuKey() { // TODO build 'wait for menu update' into this method? get current menu, press key, wait for update? + log.debug("Pressing menu key"); pressKey(Key.MENU); + log.debug("Releasing menu key"); } /** From 347890496b5d1fb735da46600eeda286b87cc4e1 Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Sat, 15 Jul 2017 11:20:35 +0200 Subject: [PATCH 030/952] SetTbrCommand: wain for menu update when switching to TBR_DURATION to make it safer, hopefully. --- .../java/de/jotomo/ruffyscripter/commands/SetTbrCommand.java | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/de/jotomo/ruffyscripter/commands/SetTbrCommand.java b/app/src/main/java/de/jotomo/ruffyscripter/commands/SetTbrCommand.java index 6059252c3a..185e9974f3 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/commands/SetTbrCommand.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/commands/SetTbrCommand.java @@ -57,6 +57,7 @@ public class SetTbrCommand implements Command { } else { // switch to TBR_DURATION menu by pressing menu key scripter.pressMenuKey(); + scripter.waitForMenuUpdate(); scripter.verifyMenuIsDisplayed(MenuType.TBR_DURATION); inputTbrDuration(scripter); From a2b3c26b33e022a72eb1c0c580b6c3e4f65f6dca Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Sat, 15 Jul 2017 11:34:59 +0200 Subject: [PATCH 031/952] Log pump status on connect. --- .../jotomo/ruffyscripter/RuffyScripter.java | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java b/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java index be59c82c09..ef6166c0bb 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java @@ -6,7 +6,9 @@ import android.os.SystemClock; import org.monkey.d.ruffy.ruffy.driver.IRTHandler; import org.monkey.d.ruffy.ruffy.driver.IRuffyService; import org.monkey.d.ruffy.ruffy.driver.display.Menu; +import org.monkey.d.ruffy.ruffy.driver.display.MenuAttribute; import org.monkey.d.ruffy.ruffy.driver.display.MenuType; +import org.monkey.d.ruffy.ruffy.driver.display.menu.MenuTime; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -124,6 +126,7 @@ public class RuffyScripter { // TODO hackish, to say the least ... // wait till pump is ready for input waitForMenuUpdate(); + logPumpStatus(); log.debug("Cmd execution: connection ready, executing cmd " + cmd); cmdThread = new Thread(new Runnable() { @Override @@ -166,6 +169,28 @@ public class RuffyScripter { } } + private void logPumpStatus() { + log.debug("Pump status:"); + MenuType currentMenuType = currentMenu.getType(); + if (currentMenuType == MenuType.MAIN_MENU) { + Double tbrPercentage = (Double) currentMenu.getAttribute(MenuAttribute.TBR); + if (tbrPercentage != 100) { + MenuTime durationMenuTime = ((MenuTime) currentMenu.getAttribute(MenuAttribute.RUNTIME)); + long durationRemainging = durationMenuTime.getHour() * 60 + durationMenuTime.getMinute(); + log.debug(" TBR active: " + tbrPercentage + "%/" + durationRemainging + "m remaining"); + } else { + log.debug(" TBR active: no"); + } + } else { + log.warn(" !!! Pump is on unexpected screen " + currentMenuType + " !!!"); + log.warn(" Dumping all displayed attributes:"); + for (MenuAttribute menuAttribute : currentMenu.attributes()) { + log.warn(" " + menuAttribute + ": " + currentMenu.getAttribute(menuAttribute)); + } + + } + } + public void ensureConnected() { // did we get a menu update from the pump in the last 5s? Then we're connected if (currentMenu != null && menuLastUpdated + 5000 > System.currentTimeMillis()) { From 8b21bb120384d00a60ec9e0cdad709acacb31261 Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Sat, 15 Jul 2017 11:50:29 +0200 Subject: [PATCH 032/952] Skip TBR changes smaller than 20%. ~50 TBR changes in a 6 hour night seem excessive, even if pump was handicapped by not being connected and thus not having any effect to work with. --- .../androidaps/plugins/PumpCombo/ComboPlugin.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java index 9033faffe2..fbc18fc760 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java @@ -51,6 +51,9 @@ public class ComboPlugin implements PluginBase, PumpInterface { PumpDescription pumpDescription = new PumpDescription(); + // TODO quick hack until pump state is more thoroughly supported + int activeTbrPercentage = -1; + private RuffyScripter ruffyScripter; private Date lastCmdTime = new Date(0); private ServiceConnection mRuffyServiceConnection; @@ -329,6 +332,15 @@ public class ComboPlugin implements PluginBase, PumpInterface { log.debug("Rounded requested percentage from " + percent + " to " + rounded); percent = rounded; } + if (activeTbrPercentage != -1 && Math.abs(activeTbrPercentage - percent) <= 20) { + log.debug("Not bothering the pump for a small TBR change from " + activeTbrPercentage + "% -> " + percent + "%"); + PumpEnactResult pumpEnactResult = new PumpEnactResult(); + pumpEnactResult.success = true; + pumpEnactResult.enacted = false; + pumpEnactResult.percent = activeTbrPercentage; + pumpEnactResult.comment = "TBR change too small, skipping"; + return pumpEnactResult; + } MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.settingtempbasal))); CommandResult commandResult = runCommand(new SetTbrCommand(percent, durationInMinutes)); if (commandResult.enacted) { @@ -339,6 +351,7 @@ public class ComboPlugin implements PluginBase, PumpInterface { tempStart.source = Source.USER; ConfigBuilderPlugin treatmentsInterface = MainApp.getConfigBuilder(); treatmentsInterface.addToHistoryTempBasal(tempStart); + activeTbrPercentage = percent; } PumpEnactResult pumpEnactResult = new PumpEnactResult(); @@ -369,6 +382,7 @@ public class ComboPlugin implements PluginBase, PumpInterface { tempStop.source = Source.USER; ConfigBuilderPlugin treatmentsInterface = MainApp.getConfigBuilder(); treatmentsInterface.addToHistoryTempBasal(tempStop); + activeTbrPercentage = 100; } PumpEnactResult pumpEnactResult = new PumpEnactResult(); From 5631488cc818d74a8468c2a6639dc65f816ac14d Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Sat, 15 Jul 2017 12:40:06 +0200 Subject: [PATCH 033/952] Add ReadStateCommand. --- .../ruffyscripter/commands/CommandResult.java | 12 +++++ .../ruffyscripter/commands/History.java | 5 ++ .../commands/ReadStateCommand.java | 44 +++++++++++++++++ .../jotomo/ruffyscripter/commands/State.java | 48 +++++++++++++++++++ 4 files changed, 109 insertions(+) create mode 100644 app/src/main/java/de/jotomo/ruffyscripter/commands/History.java create mode 100644 app/src/main/java/de/jotomo/ruffyscripter/commands/ReadStateCommand.java create mode 100644 app/src/main/java/de/jotomo/ruffyscripter/commands/State.java diff --git a/app/src/main/java/de/jotomo/ruffyscripter/commands/CommandResult.java b/app/src/main/java/de/jotomo/ruffyscripter/commands/CommandResult.java index 0a78f2a147..2bdd4bba46 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/commands/CommandResult.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/commands/CommandResult.java @@ -5,6 +5,8 @@ public class CommandResult { public boolean enacted; public Exception exception; public String message; + public State state; + public History history; public CommandResult() { } @@ -29,6 +31,16 @@ public class CommandResult { return this; } + public CommandResult state(State state) { + this.state = state; + return this; + } + + public CommandResult history(History history) { + this.history = history; + return this; + } + @Override public String toString() { return "CommandResult{" + diff --git a/app/src/main/java/de/jotomo/ruffyscripter/commands/History.java b/app/src/main/java/de/jotomo/ruffyscripter/commands/History.java new file mode 100644 index 0000000000..ca322f4ac3 --- /dev/null +++ b/app/src/main/java/de/jotomo/ruffyscripter/commands/History.java @@ -0,0 +1,5 @@ +package de.jotomo.ruffyscripter.commands; + +/** The history data read from "My data" */ +public class History { +} diff --git a/app/src/main/java/de/jotomo/ruffyscripter/commands/ReadStateCommand.java b/app/src/main/java/de/jotomo/ruffyscripter/commands/ReadStateCommand.java new file mode 100644 index 0000000000..e4d87a7d9f --- /dev/null +++ b/app/src/main/java/de/jotomo/ruffyscripter/commands/ReadStateCommand.java @@ -0,0 +1,44 @@ +package de.jotomo.ruffyscripter.commands; + +import org.monkey.d.ruffy.ruffy.driver.display.Menu; +import org.monkey.d.ruffy.ruffy.driver.display.MenuAttribute; +import org.monkey.d.ruffy.ruffy.driver.display.MenuType; +import org.monkey.d.ruffy.ruffy.driver.display.menu.MenuTime; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import de.jotomo.ruffyscripter.RuffyScripter; + +/** + * Reads the status displayed in the main menu. Usually TBR state or warning/error if any. + * This command is 'read-only', no buttons are pushed and so no vibrations are caused. + */ +public class ReadStateCommand implements Command { + private static final Logger log = LoggerFactory.getLogger(ReadStateCommand.class); + + @Override + public CommandResult execute(RuffyScripter scripter) { + try { + State state = new State(); + Menu displayedMenu = scripter.currentMenu; + MenuType displayedMenuType = displayedMenu.getType(); + if (displayedMenuType == MenuType.MAIN_MENU) { + Double tbrPercentage = (Double) displayedMenu.getAttribute(MenuAttribute.TBR); + if (tbrPercentage != 100) { + state.tbrActive = true; + MenuTime durationMenuTime = ((MenuTime) displayedMenu.getAttribute(MenuAttribute.RUNTIME)); + state.tbrRemainingDuration = durationMenuTime.getHour() * 60 + durationMenuTime.getMinute(); + } + } else if (displayedMenuType == MenuType.WARNING_OR_ERROR) { + state.isErrorOrWarning = true; + state.errorCode = (int) displayedMenu.getAttribute(MenuAttribute.ERROR); + } else { + throw new CommandException().success(false).message("Neither MAIN_MENU nor WARNING_OR_ERROR is displayed, but " + displayedMenuType); + } + + return new CommandResult().success(true).enacted(false).state(state); + } catch (CommandException e) { + return e.toCommandResult(); + } + } +} diff --git a/app/src/main/java/de/jotomo/ruffyscripter/commands/State.java b/app/src/main/java/de/jotomo/ruffyscripter/commands/State.java new file mode 100644 index 0000000000..e2bc75a58f --- /dev/null +++ b/app/src/main/java/de/jotomo/ruffyscripter/commands/State.java @@ -0,0 +1,48 @@ +package de.jotomo.ruffyscripter.commands; + +/** + * State represeting the state of the MAIN_MENU + */ +public class State { + public boolean tbrActive = false; + public int tbrPercent = -1; + public int tbrRemainingDuration = -1; + public boolean isErrorOrWarning = false; + public int errorCode = -1; + + public State tbrActive(boolean tbrActive) { + this.tbrActive = tbrActive; + return this; + } + + public State tbrPercent(int tbrPercent) { + this.tbrPercent = tbrPercent; + return this; + } + + public State tbrRemainingDuration(int tbrRemainingDuration) { + this.tbrRemainingDuration = tbrRemainingDuration; + return this; + } + + public State isErrorOrWarning(boolean isErrorOrWarning) { + this.isErrorOrWarning = isErrorOrWarning; + return this; + } + + public State errorCode(int errorCode) { + this.errorCode = errorCode; + return this; + } + + @Override + public String toString() { + return "State{" + + "tbrActive=" + tbrActive + + ", tbrPercent=" + tbrPercent + + ", tbrRemainingDuration=" + tbrRemainingDuration + + ", isErrorOrWarning=" + isErrorOrWarning + + ", errorCode=" + errorCode + + '}'; + } +} From 30fc385970f57a4929b87e2a4adb376389485afc Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Sat, 15 Jul 2017 12:46:43 +0200 Subject: [PATCH 034/952] Apply pump specific modifications to OpenAPS suggestion in ComboPlugin. --- .../plugins/PumpCombo/ComboPlugin.java | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java index fbc18fc760..f08304f532 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java @@ -313,16 +313,33 @@ public class ComboPlugin implements PluginBase, PumpInterface { // till pump times out or raises an error } + // Note: AAPS calls this only to enact OpenAPS recommendations @Override public PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes) { log.debug("setTempBasalAbsolute called with a rate of " + absoluteRate + " for " + durationInMinutes + " min."); int unroundedPercentage = Double.valueOf(absoluteRate / getBaseBasalRate() * 100).intValue(); int roundedPercentage = (int) (Math.round(absoluteRate/ getBaseBasalRate() * 10) * 10); - if (unroundedPercentage != roundedPercentage) + if (unroundedPercentage != roundedPercentage) { log.debug("Rounded requested rate " + unroundedPercentage + "% -> " + roundedPercentage + "%"); + } + if (activeTbrPercentage != -1 && Math.abs(activeTbrPercentage - roundedPercentage) <= 20) { + log.debug("Not bothering the pump for a small TBR change from " + activeTbrPercentage + "% -> " + roundedPercentage + "%"); + PumpEnactResult pumpEnactResult = new PumpEnactResult(); + pumpEnactResult.success = true; + pumpEnactResult.enacted = false; + pumpEnactResult.percent = activeTbrPercentage; + pumpEnactResult.comment = "TBR change too small, skipping"; + return pumpEnactResult; + } + int stepSize = pumpDescription.tempPercentStep; + if (durationInMinutes > stepSize) { + log.debug("Reducing requested duration of " + durationInMinutes + "m to minimal duration supported by the pump: " + stepSize + "m"); + durationInMinutes = stepSize; + } return setTempBasalPercent(roundedPercentage, durationInMinutes); } + // Note: AAPS calls this only for setting a temp basal issued by the user @Override public PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes) { log.debug("setTempBasalPercent called with " + percent + "% for " + durationInMinutes + "min"); @@ -332,15 +349,6 @@ public class ComboPlugin implements PluginBase, PumpInterface { log.debug("Rounded requested percentage from " + percent + " to " + rounded); percent = rounded; } - if (activeTbrPercentage != -1 && Math.abs(activeTbrPercentage - percent) <= 20) { - log.debug("Not bothering the pump for a small TBR change from " + activeTbrPercentage + "% -> " + percent + "%"); - PumpEnactResult pumpEnactResult = new PumpEnactResult(); - pumpEnactResult.success = true; - pumpEnactResult.enacted = false; - pumpEnactResult.percent = activeTbrPercentage; - pumpEnactResult.comment = "TBR change too small, skipping"; - return pumpEnactResult; - } MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.settingtempbasal))); CommandResult commandResult = runCommand(new SetTbrCommand(percent, durationInMinutes)); if (commandResult.enacted) { From 0345a01fc127624e3cec7633ae3db2d26b9fd5a8 Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Sat, 15 Jul 2017 12:47:11 +0200 Subject: [PATCH 035/952] Make CancelTbrCommand more robust. --- .../commands/CancelTbrCommand.java | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/de/jotomo/ruffyscripter/commands/CancelTbrCommand.java b/app/src/main/java/de/jotomo/ruffyscripter/commands/CancelTbrCommand.java index 847d9b6fb8..e87a4ebf2d 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/commands/CancelTbrCommand.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/commands/CancelTbrCommand.java @@ -13,17 +13,21 @@ public class CancelTbrCommand implements Command { @Override public CommandResult execute(RuffyScripter scripter) { - scripter.verifyMenuIsDisplayed(MenuType.MAIN_MENU); - Double tbrPercentage = (Double) scripter.currentMenu.getAttribute(MenuAttribute.TBR); - boolean runtimeDisplayed = scripter.currentMenu.attributes().contains(MenuAttribute.RUNTIME); - if (tbrPercentage == 100 && !runtimeDisplayed) { - return new CommandResult() - .success(true) - .enacted(true) // technically, nothing was enacted, but AAPS needs this to recover - // when there was an issue and AAPS thinks a TBR is still active - .message("No TBR active"); + try { + scripter.verifyMenuIsDisplayed(MenuType.MAIN_MENU); + Double tbrPercentage = (Double) scripter.currentMenu.getAttribute(MenuAttribute.TBR); + boolean runtimeDisplayed = scripter.currentMenu.attributes().contains(MenuAttribute.RUNTIME); + if (tbrPercentage == 100 && !runtimeDisplayed) { + return new CommandResult() + .success(true) + .enacted(true) // technically, nothing was enacted, but AAPS needs this to recover + // when there was an issue and AAPS thinks a TBR is still active + .message("No TBR active"); + } + log.debug("Cancelling active TBR of " + tbrPercentage + "% with " + runtimeDisplayed + "min remaining"); + } catch (CommandException e) { + return e.toCommandResult(); } - log.debug("Cancelling active TBR of " + tbrPercentage + "% with " + runtimeDisplayed + "min remaining"); return new SetTbrCommand(100, 0).execute(scripter); } From fa039e6961527f63b2c9e43d40ea16636d99ec4f Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Sat, 15 Jul 2017 12:47:53 +0200 Subject: [PATCH 036/952] Note on cancelling TBRs that don't trigger a pump alert. --- .../de/jotomo/ruffyscripter/commands/SetTbrCommand.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/de/jotomo/ruffyscripter/commands/SetTbrCommand.java b/app/src/main/java/de/jotomo/ruffyscripter/commands/SetTbrCommand.java index 185e9974f3..013e0c642a 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/commands/SetTbrCommand.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/commands/SetTbrCommand.java @@ -185,7 +185,12 @@ public class SetTbrCommand implements Command { } private void cancelTbrAndConfirmCancellationWarning(RuffyScripter scripter) { - // TODO this will fail if no TBR is running; detect and just throw CE(success=true, msg="nothing to do")? + // TODO tbr with 1m remaining doesn't raise an alert; + // BT connection is NOT lost when an alarm is raised, see if we can improve checking for + // and acknowleding errors; + // i think timing is crucial: waiting too long and the pump display activates and we lose + // connection. we can reconnect, but by then the pump might be noisy already. + // confirm entered TBR scripter.pressCheckKey(); From 375eb466959a765fcd72c61a505a4b6c0aca74e3 Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Sat, 15 Jul 2017 13:34:18 +0200 Subject: [PATCH 037/952] ReadStateCommand: properly read TBR %. --- .../ruffyscripter/commands/ReadStateCommand.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/de/jotomo/ruffyscripter/commands/ReadStateCommand.java b/app/src/main/java/de/jotomo/ruffyscripter/commands/ReadStateCommand.java index e4d87a7d9f..7d07079ab3 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/commands/ReadStateCommand.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/commands/ReadStateCommand.java @@ -4,8 +4,6 @@ import org.monkey.d.ruffy.ruffy.driver.display.Menu; import org.monkey.d.ruffy.ruffy.driver.display.MenuAttribute; import org.monkey.d.ruffy.ruffy.driver.display.MenuType; import org.monkey.d.ruffy.ruffy.driver.display.menu.MenuTime; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import de.jotomo.ruffyscripter.RuffyScripter; @@ -14,8 +12,6 @@ import de.jotomo.ruffyscripter.RuffyScripter; * This command is 'read-only', no buttons are pushed and so no vibrations are caused. */ public class ReadStateCommand implements Command { - private static final Logger log = LoggerFactory.getLogger(ReadStateCommand.class); - @Override public CommandResult execute(RuffyScripter scripter) { try { @@ -26,6 +22,8 @@ public class ReadStateCommand implements Command { Double tbrPercentage = (Double) displayedMenu.getAttribute(MenuAttribute.TBR); if (tbrPercentage != 100) { state.tbrActive = true; + Double displayedTbr = (Double) scripter.currentMenu.getAttribute(MenuAttribute.TBR); + state.tbrPercent = displayedTbr.intValue(); MenuTime durationMenuTime = ((MenuTime) displayedMenu.getAttribute(MenuAttribute.RUNTIME)); state.tbrRemainingDuration = durationMenuTime.getHour() * 60 + durationMenuTime.getMinute(); } @@ -41,4 +39,10 @@ public class ReadStateCommand implements Command { return e.toCommandResult(); } } + + @Override + public String toString() { + return "ReadStateCommand{}"; + } + } From e76524a5394d64c1010cddd894ce6a42587cb240 Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Sat, 15 Jul 2017 13:34:37 +0200 Subject: [PATCH 038/952] Include state in CommandResult.toString. --- .../java/de/jotomo/ruffyscripter/commands/CommandResult.java | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/de/jotomo/ruffyscripter/commands/CommandResult.java b/app/src/main/java/de/jotomo/ruffyscripter/commands/CommandResult.java index 2bdd4bba46..f76d00c763 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/commands/CommandResult.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/commands/CommandResult.java @@ -48,6 +48,7 @@ public class CommandResult { ", enacted=" + enacted + ", exception=" + exception + ", message='" + message + '\'' + + ", state=" + state + '}'; } } From eab9d8dcd7f4bc8ff50fbc3575e146be8b8ce57a Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Sat, 15 Jul 2017 13:44:14 +0200 Subject: [PATCH 039/952] Fix reducing duration of OpenAPS TBRs --- .../nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java index f08304f532..8920ef196c 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java @@ -331,7 +331,7 @@ public class ComboPlugin implements PluginBase, PumpInterface { pumpEnactResult.comment = "TBR change too small, skipping"; return pumpEnactResult; } - int stepSize = pumpDescription.tempPercentStep; + int stepSize = pumpDescription.tempDurationStep; if (durationInMinutes > stepSize) { log.debug("Reducing requested duration of " + durationInMinutes + "m to minimal duration supported by the pump: " + stepSize + "m"); durationInMinutes = stepSize; From 9d8d12fcb993dc0762f48541c81464004890e161 Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Sat, 15 Jul 2017 13:45:57 +0200 Subject: [PATCH 040/952] Cleanups. --- .../main/java/de/jotomo/ruffyscripter/RuffyScripter.java | 2 -- .../androidaps/plugins/PumpCombo/ComboPlugin.java | 6 +++--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java b/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java index ef6166c0bb..413f4f8401 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java @@ -106,8 +106,6 @@ public class RuffyScripter { private volatile Command activeCmd = null; - // TODO fire up a monitoring thread to intervene when we're stuck? re-bind service - // in case ruffy app went away public CommandResult runCommand(final Command cmd) { try { if (isPumpBusy()) { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java index 8920ef196c..dc01bbce95 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java @@ -46,10 +46,10 @@ import info.nightscout.utils.DateUtil; public class ComboPlugin implements PluginBase, PumpInterface { private static Logger log = LoggerFactory.getLogger(ComboPlugin.class); - boolean fragmentEnabled = false; - boolean fragmentVisible = false; + private boolean fragmentEnabled = false; + private boolean fragmentVisible = false; - PumpDescription pumpDescription = new PumpDescription(); + private PumpDescription pumpDescription = new PumpDescription(); // TODO quick hack until pump state is more thoroughly supported int activeTbrPercentage = -1; From f28a27a93f1290ced3254a989bad91eb929bc2c6 Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Sat, 15 Jul 2017 13:53:56 +0200 Subject: [PATCH 041/952] Read pump state. --- .../plugins/PumpCombo/ComboPlugin.java | 52 ++++++++++++++----- 1 file changed, 40 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java index dc01bbce95..7cce074434 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java @@ -6,6 +6,7 @@ import android.content.Intent; import android.content.ServiceConnection; import android.os.IBinder; import android.os.SystemClock; +import android.support.annotation.Nullable; import com.squareup.otto.Subscribe; @@ -22,7 +23,9 @@ import de.jotomo.ruffyscripter.commands.BolusCommand; import de.jotomo.ruffyscripter.commands.CancelTbrCommand; import de.jotomo.ruffyscripter.commands.Command; import de.jotomo.ruffyscripter.commands.CommandResult; +import de.jotomo.ruffyscripter.commands.ReadStateCommand; import de.jotomo.ruffyscripter.commands.SetTbrCommand; +import de.jotomo.ruffyscripter.commands.State; import info.nightscout.androidaps.BuildConfig; import info.nightscout.androidaps.Config; import info.nightscout.androidaps.MainApp; @@ -51,13 +54,13 @@ public class ComboPlugin implements PluginBase, PumpInterface { private PumpDescription pumpDescription = new PumpDescription(); - // TODO quick hack until pump state is more thoroughly supported - int activeTbrPercentage = -1; - private RuffyScripter ruffyScripter; private Date lastCmdTime = new Date(0); private ServiceConnection mRuffyServiceConnection; + @Nullable + private volatile State pumpState; + private static PumpEnactResult OPERATION_NOT_SUPPORTED = new PumpEnactResult(); static { @@ -92,7 +95,13 @@ public class ComboPlugin implements PluginBase, PumpInterface { @Override public void onServiceConnected(ComponentName name, IBinder service) { ruffyScripter = new RuffyScripter(IRuffyService.Stub.asInterface(service)); - log.debug("ruffy serivce connected"); + log.debug("ruffy serivce connected, fetching initial pump state"); + new Thread(new Runnable() { + @Override + public void run() { + readPumpState(false); + } + }).start(); } @Override @@ -107,6 +116,13 @@ public class ComboPlugin implements PluginBase, PumpInterface { } } + private CommandResult readPumpState(boolean keepConnectionOpen) { + CommandResult commandResult = runCommand(new ReadStateCommand(), keepConnectionOpen); + pumpState = commandResult.state; + log.debug("Pump state: " + commandResult.state); + return commandResult; + } + private void definePumpCapabilities() { pumpDescription.isBolusCapable = true; pumpDescription.bolusStep = 0.1d; @@ -260,7 +276,7 @@ public class ComboPlugin implements PluginBase, PumpInterface { if (detailedBolusInfo.insulin > 0 || detailedBolusInfo.carbs > 0) { PumpEnactResult result = new PumpEnactResult(); if (detailedBolusInfo.insulin > 0) { - CommandResult bolusCmdResult = runCommand(new BolusCommand(detailedBolusInfo.insulin)); + CommandResult bolusCmdResult = runCommand(new BolusCommand(detailedBolusInfo.insulin), false); result.success = bolusCmdResult.success; result.enacted = bolusCmdResult.enacted; // TODO if no error occurred, the requested bolus is what the pump delievered, @@ -296,13 +312,15 @@ public class ComboPlugin implements PluginBase, PumpInterface { } } - private CommandResult runCommand(Command command) { + private CommandResult runCommand(Command command, boolean keepConnectionOpen) { // TODO use this to dispatch methods to a service thread, like DanaRs executionService try { return ruffyScripter.runCommand(command); } finally { lastCmdTime = new Date(); - ruffyScripter.disconnect(); + if(!keepConnectionOpen) { + ruffyScripter.disconnect(); + } } } @@ -322,6 +340,14 @@ public class ComboPlugin implements PluginBase, PumpInterface { if (unroundedPercentage != roundedPercentage) { log.debug("Rounded requested rate " + unroundedPercentage + "% -> " + roundedPercentage + "%"); } + CommandResult readStateCmdResult = readPumpState(true); + if (!readStateCmdResult.success) { + PumpEnactResult pumpEnactResult = new PumpEnactResult(); + pumpEnactResult.success = false; + pumpEnactResult.enacted = false; + pumpEnactResult.comment = "Failed to read pump state"; + } + int activeTbrPercentage = pumpState != null ? pumpState.tbrPercent : 100; if (activeTbrPercentage != -1 && Math.abs(activeTbrPercentage - roundedPercentage) <= 20) { log.debug("Not bothering the pump for a small TBR change from " + activeTbrPercentage + "% -> " + roundedPercentage + "%"); PumpEnactResult pumpEnactResult = new PumpEnactResult(); @@ -350,7 +376,7 @@ public class ComboPlugin implements PluginBase, PumpInterface { percent = rounded; } MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.settingtempbasal))); - CommandResult commandResult = runCommand(new SetTbrCommand(percent, durationInMinutes)); + CommandResult commandResult = runCommand(new SetTbrCommand(percent, durationInMinutes), false); if (commandResult.enacted) { TemporaryBasal tempStart = new TemporaryBasal(System.currentTimeMillis()); tempStart.durationInMinutes = durationInMinutes; @@ -359,9 +385,10 @@ public class ComboPlugin implements PluginBase, PumpInterface { tempStart.source = Source.USER; ConfigBuilderPlugin treatmentsInterface = MainApp.getConfigBuilder(); treatmentsInterface.addToHistoryTempBasal(tempStart); - activeTbrPercentage = percent; } + readPumpState(false); + PumpEnactResult pumpEnactResult = new PumpEnactResult(); pumpEnactResult.success = commandResult.success; pumpEnactResult.enacted = commandResult.enacted; @@ -383,16 +410,17 @@ public class ComboPlugin implements PluginBase, PumpInterface { public PumpEnactResult cancelTempBasal() { log.debug("cancelTempBasal called"); MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.stoppingtempbasal))); - CommandResult commandResult = runCommand(new CancelTbrCommand()); - if(commandResult.enacted) { + CommandResult commandResult = runCommand(new CancelTbrCommand(), true); + if (commandResult.enacted) { TemporaryBasal tempStop = new TemporaryBasal(System.currentTimeMillis()); tempStop.durationInMinutes = 0; // ending temp basal tempStop.source = Source.USER; ConfigBuilderPlugin treatmentsInterface = MainApp.getConfigBuilder(); treatmentsInterface.addToHistoryTempBasal(tempStop); - activeTbrPercentage = 100; } + readPumpState(false); + PumpEnactResult pumpEnactResult = new PumpEnactResult(); pumpEnactResult.success = commandResult.success; pumpEnactResult.enacted = commandResult.enacted; From f5ef66606171849a1751d9bc31728a39740f1177 Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Sat, 15 Jul 2017 13:56:31 +0200 Subject: [PATCH 042/952] Add timestamp to State and rename to PumpState. --- .../ruffyscripter/commands/CommandResult.java | 4 ++-- .../commands/{State.java => PumpState.java} | 20 +++++++++++-------- .../commands/ReadStateCommand.java | 2 +- .../plugins/PumpCombo/ComboPlugin.java | 4 ++-- 4 files changed, 17 insertions(+), 13 deletions(-) rename app/src/main/java/de/jotomo/ruffyscripter/commands/{State.java => PumpState.java} (65%) diff --git a/app/src/main/java/de/jotomo/ruffyscripter/commands/CommandResult.java b/app/src/main/java/de/jotomo/ruffyscripter/commands/CommandResult.java index f76d00c763..999eaf36b8 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/commands/CommandResult.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/commands/CommandResult.java @@ -5,7 +5,7 @@ public class CommandResult { public boolean enacted; public Exception exception; public String message; - public State state; + public PumpState state; public History history; public CommandResult() { @@ -31,7 +31,7 @@ public class CommandResult { return this; } - public CommandResult state(State state) { + public CommandResult state(PumpState state) { this.state = state; return this; } diff --git a/app/src/main/java/de/jotomo/ruffyscripter/commands/State.java b/app/src/main/java/de/jotomo/ruffyscripter/commands/PumpState.java similarity index 65% rename from app/src/main/java/de/jotomo/ruffyscripter/commands/State.java rename to app/src/main/java/de/jotomo/ruffyscripter/commands/PumpState.java index e2bc75a58f..767f22b19a 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/commands/State.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/commands/PumpState.java @@ -1,48 +1,52 @@ package de.jotomo.ruffyscripter.commands; +import java.util.Date; + /** - * State represeting the state of the MAIN_MENU + * State representing the state of the MAIN_MENU. */ -public class State { +public class PumpState { + public Date timestamp = new Date(); public boolean tbrActive = false; public int tbrPercent = -1; public int tbrRemainingDuration = -1; public boolean isErrorOrWarning = false; public int errorCode = -1; - public State tbrActive(boolean tbrActive) { + public PumpState tbrActive(boolean tbrActive) { this.tbrActive = tbrActive; return this; } - public State tbrPercent(int tbrPercent) { + public PumpState tbrPercent(int tbrPercent) { this.tbrPercent = tbrPercent; return this; } - public State tbrRemainingDuration(int tbrRemainingDuration) { + public PumpState tbrRemainingDuration(int tbrRemainingDuration) { this.tbrRemainingDuration = tbrRemainingDuration; return this; } - public State isErrorOrWarning(boolean isErrorOrWarning) { + public PumpState isErrorOrWarning(boolean isErrorOrWarning) { this.isErrorOrWarning = isErrorOrWarning; return this; } - public State errorCode(int errorCode) { + public PumpState errorCode(int errorCode) { this.errorCode = errorCode; return this; } @Override public String toString() { - return "State{" + + return "PumpState{" + "tbrActive=" + tbrActive + ", tbrPercent=" + tbrPercent + ", tbrRemainingDuration=" + tbrRemainingDuration + ", isErrorOrWarning=" + isErrorOrWarning + ", errorCode=" + errorCode + + ", timestamp=" + timestamp + '}'; } } diff --git a/app/src/main/java/de/jotomo/ruffyscripter/commands/ReadStateCommand.java b/app/src/main/java/de/jotomo/ruffyscripter/commands/ReadStateCommand.java index 7d07079ab3..ac77dee602 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/commands/ReadStateCommand.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/commands/ReadStateCommand.java @@ -15,7 +15,7 @@ public class ReadStateCommand implements Command { @Override public CommandResult execute(RuffyScripter scripter) { try { - State state = new State(); + PumpState state = new PumpState(); Menu displayedMenu = scripter.currentMenu; MenuType displayedMenuType = displayedMenu.getType(); if (displayedMenuType == MenuType.MAIN_MENU) { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java index 7cce074434..96b3630fb2 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java @@ -25,7 +25,7 @@ import de.jotomo.ruffyscripter.commands.Command; import de.jotomo.ruffyscripter.commands.CommandResult; import de.jotomo.ruffyscripter.commands.ReadStateCommand; import de.jotomo.ruffyscripter.commands.SetTbrCommand; -import de.jotomo.ruffyscripter.commands.State; +import de.jotomo.ruffyscripter.commands.PumpState; import info.nightscout.androidaps.BuildConfig; import info.nightscout.androidaps.Config; import info.nightscout.androidaps.MainApp; @@ -59,7 +59,7 @@ public class ComboPlugin implements PluginBase, PumpInterface { private ServiceConnection mRuffyServiceConnection; @Nullable - private volatile State pumpState; + private volatile PumpState pumpState; private static PumpEnactResult OPERATION_NOT_SUPPORTED = new PumpEnactResult(); From 8bc4cd255a9a1f7a2d1872f225d2544663a928d5 Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Sat, 15 Jul 2017 14:19:54 +0200 Subject: [PATCH 043/952] Don't close connection when other cmds are about to be run. --- .../androidaps/plugins/PumpCombo/ComboPlugin.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java index 96b3630fb2..86272be29e 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java @@ -118,8 +118,12 @@ public class ComboPlugin implements PluginBase, PumpInterface { private CommandResult readPumpState(boolean keepConnectionOpen) { CommandResult commandResult = runCommand(new ReadStateCommand(), keepConnectionOpen); - pumpState = commandResult.state; - log.debug("Pump state: " + commandResult.state); + if (commandResult.success) { + pumpState = commandResult.state; + log.debug("Pump state: " + commandResult.state); + } else { + log.warn("Reading pump status failed: " + commandResult.message); + } return commandResult; } @@ -376,7 +380,7 @@ public class ComboPlugin implements PluginBase, PumpInterface { percent = rounded; } MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.settingtempbasal))); - CommandResult commandResult = runCommand(new SetTbrCommand(percent, durationInMinutes), false); + CommandResult commandResult = runCommand(new SetTbrCommand(percent, durationInMinutes), true); if (commandResult.enacted) { TemporaryBasal tempStart = new TemporaryBasal(System.currentTimeMillis()); tempStart.durationInMinutes = durationInMinutes; From 2c706e7c22cbcdabdf00ac69281cabc77f118f28 Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Sat, 15 Jul 2017 14:21:37 +0200 Subject: [PATCH 044/952] Remove status logging in Ruffy, now done by command. --- .../jotomo/ruffyscripter/RuffyScripter.java | 28 ++----------------- 1 file changed, 3 insertions(+), 25 deletions(-) diff --git a/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java b/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java index 413f4f8401..b472b11c22 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java @@ -6,9 +6,7 @@ import android.os.SystemClock; import org.monkey.d.ruffy.ruffy.driver.IRTHandler; import org.monkey.d.ruffy.ruffy.driver.IRuffyService; import org.monkey.d.ruffy.ruffy.driver.display.Menu; -import org.monkey.d.ruffy.ruffy.driver.display.MenuAttribute; import org.monkey.d.ruffy.ruffy.driver.display.MenuType; -import org.monkey.d.ruffy.ruffy.driver.display.menu.MenuTime; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -124,7 +122,9 @@ public class RuffyScripter { // TODO hackish, to say the least ... // wait till pump is ready for input waitForMenuUpdate(); - logPumpStatus(); + // TODO check pump state; currently most command check their in the MAIN_MENU; + // run ReadStateCommand, which handles possible states ... and then do wait? + // Return an unsuccessful CommandResult and make the caller do something loud with it log.debug("Cmd execution: connection ready, executing cmd " + cmd); cmdThread = new Thread(new Runnable() { @Override @@ -167,28 +167,6 @@ public class RuffyScripter { } } - private void logPumpStatus() { - log.debug("Pump status:"); - MenuType currentMenuType = currentMenu.getType(); - if (currentMenuType == MenuType.MAIN_MENU) { - Double tbrPercentage = (Double) currentMenu.getAttribute(MenuAttribute.TBR); - if (tbrPercentage != 100) { - MenuTime durationMenuTime = ((MenuTime) currentMenu.getAttribute(MenuAttribute.RUNTIME)); - long durationRemainging = durationMenuTime.getHour() * 60 + durationMenuTime.getMinute(); - log.debug(" TBR active: " + tbrPercentage + "%/" + durationRemainging + "m remaining"); - } else { - log.debug(" TBR active: no"); - } - } else { - log.warn(" !!! Pump is on unexpected screen " + currentMenuType + " !!!"); - log.warn(" Dumping all displayed attributes:"); - for (MenuAttribute menuAttribute : currentMenu.attributes()) { - log.warn(" " + menuAttribute + ": " + currentMenu.getAttribute(menuAttribute)); - } - - } - } - public void ensureConnected() { // did we get a menu update from the pump in the last 5s? Then we're connected if (currentMenu != null && menuLastUpdated + 5000 > System.currentTimeMillis()) { From d8011aeaa441a58672f1352b69749d59b1a0dccf Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Sat, 15 Jul 2017 14:46:58 +0200 Subject: [PATCH 045/952] Make cancelling TBR more robust to dismiss TBR cancelled alert specifially and only if it is raised. Cancelling a TBR with a runtime < 60s (0:01 in the display) does NOT raise a TBR cancelled alert. --- .../ruffyscripter/commands/SetTbrCommand.java | 53 +++++++++---------- 1 file changed, 25 insertions(+), 28 deletions(-) diff --git a/app/src/main/java/de/jotomo/ruffyscripter/commands/SetTbrCommand.java b/app/src/main/java/de/jotomo/ruffyscripter/commands/SetTbrCommand.java index 013e0c642a..7c72f52ac5 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/commands/SetTbrCommand.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/commands/SetTbrCommand.java @@ -185,38 +185,35 @@ public class SetTbrCommand implements Command { } private void cancelTbrAndConfirmCancellationWarning(RuffyScripter scripter) { - // TODO tbr with 1m remaining doesn't raise an alert; - // BT connection is NOT lost when an alarm is raised, see if we can improve checking for - // and acknowleding errors; - // i think timing is crucial: waiting too long and the pump display activates and we lose - // connection. we can reconnect, but by then the pump might be noisy already. - - // confirm entered TBR scripter.pressCheckKey(); - scripter.waitForMenuUpdate(); - // hm, waiting here (more) makes things worse, if we don't press the alert away quickly, - // the pump exits BT mode ... so I guess we'll live with the checks below, - // verifying we made it back to the main menu and the displayed TBR data - // corresponds to what we set. Hope the timing is stable enough ... - -/* scripter.waitForMenuToBeLeft(MenuType.TBR_SET); - if (scripter.currentMenu.getType() != MenuType.MAIN_MENU) { - // pump shortly enters the main menu before raising the alert - // TODO is this always entered? - log.debug("TBR cancelled, going over main menu"); - scripter.waitForMenuToBeLeft(MenuType.MAIN_MENU); + // we could read remaining duration from MAIN_MENU, but but the time we're here, + // we could have moved from 0:02 to 0:01, so instead,/ check if a TBR CANCELLED alert + // is raised and if so dismiss it + scripter.waitForMenuToBeLeft(MenuType.TBR_SET); + long inTwoSeconds = System.currentTimeMillis() + 2 * 1000; + boolean alertProcessed = false; + while (System.currentTimeMillis() < inTwoSeconds && !alertProcessed) { + if (scripter.currentMenu.getType() == MenuType.WARNING_OR_ERROR) { + // check the raised alarm is TBR CANCELLED + int errorCode = (int) scripter.currentMenu.getAttribute(MenuAttribute.ERROR); + String errorMsg = (String) scripter.currentMenu.getAttribute(MenuAttribute.MESSAGE); + if (errorCode != 6 || errorMsg.equals("TBR CANCELLED")) { + throw new CommandException().success(false).enacted(false) + .message("An alert other than the expected TBR CANCELLED was raised by the pump: " + + errorMsg + "(" + errorCode + "). Please check the pump."); } - if (scripter.currentMenu.getType() != MenuType.WARNING_OR_ERROR) { - throw new CommandException(false, null, "Expected WARNING_OR_ERROR menu was not shown when cancelling TBR"); - }*/ - // confirm "TBR cancelled alert" - scripter.pressCheckKey(); - SystemClock.sleep(200); - // dismiss "TBR cancelled alert" - scripter.pressCheckKey(); - scripter.waitForMenuToBeLeft(MenuType.WARNING_OR_ERROR); + // confirm "TBR CANCELLED alert" + scripter.pressCheckKey(); + SystemClock.sleep(200); + // dismiss "TBR CANCELLED alert" + scripter.pressCheckKey(); + scripter.waitForMenuToBeLeft(MenuType.WARNING_OR_ERROR); + alertProcessed = true; + } + SystemClock.sleep(50); + } } private void verifyMainMenuShowsNoActiveTbr(RuffyScripter scripter) { From 77711b21745a6f30cace0dc81aa39035629b5fc0 Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Sat, 15 Jul 2017 15:00:27 +0200 Subject: [PATCH 046/952] ComboPlugin.runCommand: wait if pump is busy with a command. --- .../androidaps/plugins/PumpCombo/ComboPlugin.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java index 86272be29e..d1b05151b5 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java @@ -319,10 +319,17 @@ public class ComboPlugin implements PluginBase, PumpInterface { private CommandResult runCommand(Command command, boolean keepConnectionOpen) { // TODO use this to dispatch methods to a service thread, like DanaRs executionService try { + long timeout = System.currentTimeMillis() + 10 * 1000; + while (ruffyScripter.isPumpBusy()) { + if (System.currentTimeMillis() < timeout) { + return new CommandResult().success(false).enacted(false).message("Timeout waiting for the pump to be ready"); + } + SystemClock.sleep(200); + } return ruffyScripter.runCommand(command); } finally { lastCmdTime = new Date(); - if(!keepConnectionOpen) { + if (!keepConnectionOpen) { ruffyScripter.disconnect(); } } @@ -340,7 +347,7 @@ public class ComboPlugin implements PluginBase, PumpInterface { public PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes) { log.debug("setTempBasalAbsolute called with a rate of " + absoluteRate + " for " + durationInMinutes + " min."); int unroundedPercentage = Double.valueOf(absoluteRate / getBaseBasalRate() * 100).intValue(); - int roundedPercentage = (int) (Math.round(absoluteRate/ getBaseBasalRate() * 10) * 10); + int roundedPercentage = (int) (Math.round(absoluteRate / getBaseBasalRate() * 10) * 10); if (unroundedPercentage != roundedPercentage) { log.debug("Rounded requested rate " + unroundedPercentage + "% -> " + roundedPercentage + "%"); } From 952aa0e8a2dc242d7b5293e292d9f86375a6c0c7 Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Sat, 15 Jul 2017 15:00:41 +0200 Subject: [PATCH 047/952] RuffyScripter.waitForMenuToBeLeft: add timeout. --- .../main/java/de/jotomo/ruffyscripter/RuffyScripter.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java b/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java index b472b11c22..89237d793f 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java @@ -99,7 +99,7 @@ public class RuffyScripter { }; public boolean isPumpBusy() { - return activeCmd != null; // || currentMenu == null || currentMenu.getType() != MenuType.MAIN_MENU; + return activeCmd != null; } private volatile Command activeCmd = null; @@ -287,8 +287,12 @@ public class RuffyScripter { * Wait till a menu changed has completed, "away" from the menu provided as argument. */ public void waitForMenuToBeLeft(MenuType menuType) { + long timeout = System.currentTimeMillis() + 30 * 1000; while (currentMenu.getType() == menuType) { - SystemClock.sleep(250); + if (System.currentTimeMillis() > timeout) { + throw new CommandException().message("Timeout waiting for menu " + menuType + " to be left"); + } + SystemClock.sleep(50); } } From d0dabf34dae67740e17e2f61986a753da9de7ea0 Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Sat, 15 Jul 2017 15:51:48 +0200 Subject: [PATCH 048/952] Fix handling TBR CANCELLED alert, remove ill-advised attempts to fake a command queue and have all commands return a state object. --- .../jotomo/ruffyscripter/RuffyScripter.java | 36 ++++++++++++ .../ruffyscripter/commands/PumpAlert.java | 19 +++++++ .../ruffyscripter/commands/SetTbrCommand.java | 8 +-- .../plugins/PumpCombo/ComboPlugin.java | 55 ++++--------------- 4 files changed, 71 insertions(+), 47 deletions(-) create mode 100644 app/src/main/java/de/jotomo/ruffyscripter/commands/PumpAlert.java diff --git a/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java b/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java index 89237d793f..a26cf8acbd 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java @@ -6,13 +6,17 @@ import android.os.SystemClock; import org.monkey.d.ruffy.ruffy.driver.IRTHandler; import org.monkey.d.ruffy.ruffy.driver.IRuffyService; import org.monkey.d.ruffy.ruffy.driver.display.Menu; +import org.monkey.d.ruffy.ruffy.driver.display.MenuAttribute; import org.monkey.d.ruffy.ruffy.driver.display.MenuType; +import org.monkey.d.ruffy.ruffy.driver.display.menu.MenuTime; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import de.jotomo.ruffyscripter.commands.Command; import de.jotomo.ruffyscripter.commands.CommandException; import de.jotomo.ruffyscripter.commands.CommandResult; +import de.jotomo.ruffyscripter.commands.PumpAlert; +import de.jotomo.ruffyscripter.commands.PumpState; // TODO regularly read "My data" history (boluses, TBR) to double check all commands ran successfully. // Automatically compare against AAPS db, or log all requests in the PumpInterface (maybe Milos @@ -156,6 +160,9 @@ public class RuffyScripter { } } + if (cmdResult.state == null) { + cmdResult.state = readPumpState(); + } log.debug("Command result: " + cmdResult); CommandResult r = cmdResult; cmdResult = null; @@ -314,4 +321,33 @@ public class RuffyScripter { } } } + + private PumpState readPumpState() { + verifyMenuIsDisplayed(MenuType.MAIN_MENU); + PumpState state = new PumpState(); + Double tbrPercentage = (Double) currentMenu.getAttribute(MenuAttribute.TBR); + if (tbrPercentage != 100) { + state.tbrActive = true; + Double displayedTbr = (Double) currentMenu.getAttribute(MenuAttribute.TBR); + state.tbrPercent = displayedTbr.intValue(); + MenuTime durationMenuTime = ((MenuTime) currentMenu.getAttribute(MenuAttribute.RUNTIME)); + state.tbrRemainingDuration = durationMenuTime.getHour() * 60 + durationMenuTime.getMinute(); + } + return state; + } + + public PumpAlert readDisplayPumpAlert() { + Object errorObj = currentMenu.getAttribute(MenuAttribute.ERROR); + Object errorMsgObj = currentMenu.getAttribute(MenuAttribute.MESSAGE); + while (errorObj == null) { + SystemClock.sleep(10); + errorObj = currentMenu.getAttribute(MenuAttribute.ERROR); + errorMsgObj = currentMenu.getAttribute(MenuAttribute.MESSAGE); + } + while (errorMsgObj == null) { + SystemClock.sleep(10); + errorMsgObj = currentMenu.getAttribute(MenuAttribute.MESSAGE); + } + return new PumpAlert((int) errorObj, (String) errorMsgObj); + } } diff --git a/app/src/main/java/de/jotomo/ruffyscripter/commands/PumpAlert.java b/app/src/main/java/de/jotomo/ruffyscripter/commands/PumpAlert.java new file mode 100644 index 0000000000..2e7ad3f511 --- /dev/null +++ b/app/src/main/java/de/jotomo/ruffyscripter/commands/PumpAlert.java @@ -0,0 +1,19 @@ +package de.jotomo.ruffyscripter.commands; + +public class PumpAlert { + public final int code; + public final String msg; + + public PumpAlert(int code, String msg) { + this.code = code; + this.msg = msg; + } + + @Override + public String toString() { + return "PumpAlert{" + + "code=" + code + + ", msg='" + msg + '\'' + + '}'; + } +} diff --git a/app/src/main/java/de/jotomo/ruffyscripter/commands/SetTbrCommand.java b/app/src/main/java/de/jotomo/ruffyscripter/commands/SetTbrCommand.java index 7c72f52ac5..5bb90b2861 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/commands/SetTbrCommand.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/commands/SetTbrCommand.java @@ -9,6 +9,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Locale; +import java.util.Objects; import de.jotomo.ruffyscripter.RuffyScripter; @@ -197,12 +198,11 @@ public class SetTbrCommand implements Command { while (System.currentTimeMillis() < inTwoSeconds && !alertProcessed) { if (scripter.currentMenu.getType() == MenuType.WARNING_OR_ERROR) { // check the raised alarm is TBR CANCELLED - int errorCode = (int) scripter.currentMenu.getAttribute(MenuAttribute.ERROR); - String errorMsg = (String) scripter.currentMenu.getAttribute(MenuAttribute.MESSAGE); - if (errorCode != 6 || errorMsg.equals("TBR CANCELLED")) { + PumpAlert alert = scripter.readDisplayPumpAlert(); + if (alert.code != 6 || Objects.equals(alert.msg, "TBR CANCELLED")) { throw new CommandException().success(false).enacted(false) .message("An alert other than the expected TBR CANCELLED was raised by the pump: " - + errorMsg + "(" + errorCode + "). Please check the pump."); + + alert.code + "(" + alert.msg + "). Please check the pump."); } // confirm "TBR CANCELLED alert" scripter.pressCheckKey(); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java index d1b05151b5..947b22077c 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java @@ -95,13 +95,7 @@ public class ComboPlugin implements PluginBase, PumpInterface { @Override public void onServiceConnected(ComponentName name, IBinder service) { ruffyScripter = new RuffyScripter(IRuffyService.Stub.asInterface(service)); - log.debug("ruffy serivce connected, fetching initial pump state"); - new Thread(new Runnable() { - @Override - public void run() { - readPumpState(false); - } - }).start(); + log.debug("ruffy serivce connected"); } @Override @@ -116,17 +110,6 @@ public class ComboPlugin implements PluginBase, PumpInterface { } } - private CommandResult readPumpState(boolean keepConnectionOpen) { - CommandResult commandResult = runCommand(new ReadStateCommand(), keepConnectionOpen); - if (commandResult.success) { - pumpState = commandResult.state; - log.debug("Pump state: " + commandResult.state); - } else { - log.warn("Reading pump status failed: " + commandResult.message); - } - return commandResult; - } - private void definePumpCapabilities() { pumpDescription.isBolusCapable = true; pumpDescription.bolusStep = 0.1d; @@ -280,7 +263,7 @@ public class ComboPlugin implements PluginBase, PumpInterface { if (detailedBolusInfo.insulin > 0 || detailedBolusInfo.carbs > 0) { PumpEnactResult result = new PumpEnactResult(); if (detailedBolusInfo.insulin > 0) { - CommandResult bolusCmdResult = runCommand(new BolusCommand(detailedBolusInfo.insulin), false); + CommandResult bolusCmdResult = runCommand(new BolusCommand(detailedBolusInfo.insulin)); result.success = bolusCmdResult.success; result.enacted = bolusCmdResult.enacted; // TODO if no error occurred, the requested bolus is what the pump delievered, @@ -316,22 +299,19 @@ public class ComboPlugin implements PluginBase, PumpInterface { } } - private CommandResult runCommand(Command command, boolean keepConnectionOpen) { + private CommandResult runCommand(Command command) { // TODO use this to dispatch methods to a service thread, like DanaRs executionService + // will be required when doing multiple commands in sequence. + // Alternatively provide 'composite commands' to return everything needed in one go? try { - long timeout = System.currentTimeMillis() + 10 * 1000; - while (ruffyScripter.isPumpBusy()) { - if (System.currentTimeMillis() < timeout) { - return new CommandResult().success(false).enacted(false).message("Timeout waiting for the pump to be ready"); - } - SystemClock.sleep(200); + CommandResult commandResult = ruffyScripter.runCommand(command); + if (commandResult.success && commandResult.state != null) { + pumpState = commandResult.state; } - return ruffyScripter.runCommand(command); + return commandResult; } finally { lastCmdTime = new Date(); - if (!keepConnectionOpen) { - ruffyScripter.disconnect(); - } + ruffyScripter.disconnect(); } } @@ -351,13 +331,6 @@ public class ComboPlugin implements PluginBase, PumpInterface { if (unroundedPercentage != roundedPercentage) { log.debug("Rounded requested rate " + unroundedPercentage + "% -> " + roundedPercentage + "%"); } - CommandResult readStateCmdResult = readPumpState(true); - if (!readStateCmdResult.success) { - PumpEnactResult pumpEnactResult = new PumpEnactResult(); - pumpEnactResult.success = false; - pumpEnactResult.enacted = false; - pumpEnactResult.comment = "Failed to read pump state"; - } int activeTbrPercentage = pumpState != null ? pumpState.tbrPercent : 100; if (activeTbrPercentage != -1 && Math.abs(activeTbrPercentage - roundedPercentage) <= 20) { log.debug("Not bothering the pump for a small TBR change from " + activeTbrPercentage + "% -> " + roundedPercentage + "%"); @@ -387,7 +360,7 @@ public class ComboPlugin implements PluginBase, PumpInterface { percent = rounded; } MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.settingtempbasal))); - CommandResult commandResult = runCommand(new SetTbrCommand(percent, durationInMinutes), true); + CommandResult commandResult = runCommand(new SetTbrCommand(percent, durationInMinutes)); if (commandResult.enacted) { TemporaryBasal tempStart = new TemporaryBasal(System.currentTimeMillis()); tempStart.durationInMinutes = durationInMinutes; @@ -398,8 +371,6 @@ public class ComboPlugin implements PluginBase, PumpInterface { treatmentsInterface.addToHistoryTempBasal(tempStart); } - readPumpState(false); - PumpEnactResult pumpEnactResult = new PumpEnactResult(); pumpEnactResult.success = commandResult.success; pumpEnactResult.enacted = commandResult.enacted; @@ -421,7 +392,7 @@ public class ComboPlugin implements PluginBase, PumpInterface { public PumpEnactResult cancelTempBasal() { log.debug("cancelTempBasal called"); MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.stoppingtempbasal))); - CommandResult commandResult = runCommand(new CancelTbrCommand(), true); + CommandResult commandResult = runCommand(new CancelTbrCommand()); if (commandResult.enacted) { TemporaryBasal tempStop = new TemporaryBasal(System.currentTimeMillis()); tempStop.durationInMinutes = 0; // ending temp basal @@ -430,8 +401,6 @@ public class ComboPlugin implements PluginBase, PumpInterface { treatmentsInterface.addToHistoryTempBasal(tempStop); } - readPumpState(false); - PumpEnactResult pumpEnactResult = new PumpEnactResult(); pumpEnactResult.success = commandResult.success; pumpEnactResult.enacted = commandResult.enacted; From 364123c2612f6983e9d13ffa32af70f6b926d98d Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Sat, 15 Jul 2017 16:13:31 +0200 Subject: [PATCH 049/952] Fix carb only treatment. --- .../androidaps/plugins/PumpCombo/ComboPlugin.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java index 947b22077c..6ddfb1c8e7 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java @@ -254,12 +254,11 @@ public class ComboPlugin implements PluginBase, PumpInterface { return basal; } - // TODO rewrite this crap into something comprehensible + // what a mess: pump integration code reading carb info from Detailed**Bolus**Info, + // writing carb treatments to the history table. What's PumpEnactResult for again? @Override public PumpEnactResult deliverTreatment(DetailedBolusInfo detailedBolusInfo) { log.debug("deliver treatment called with dbi: " + detailedBolusInfo); - ConfigBuilderPlugin configBuilderPlugin = MainApp.getConfigBuilder(); - detailedBolusInfo.insulin = configBuilderPlugin.applyBolusConstraints(detailedBolusInfo.insulin); if (detailedBolusInfo.insulin > 0 || detailedBolusInfo.carbs > 0) { PumpEnactResult result = new PumpEnactResult(); if (detailedBolusInfo.insulin > 0) { @@ -269,6 +268,7 @@ public class ComboPlugin implements PluginBase, PumpInterface { // TODO if no error occurred, the requested bolus is what the pump delievered, // that has been checked. If an error occurred, we should check how much insulin // was delivered, e.g. when the cartridge went empty mid-bolus + // For the first iteration, the alert the pump raises must suffice result.bolusDelivered = detailedBolusInfo.insulin; result.comment = bolusCmdResult.message; } else { @@ -277,11 +277,11 @@ public class ComboPlugin implements PluginBase, PumpInterface { // info.nightscout.androidaps.plugins.Overview.Dialogs.BolusProgressDialog.scheduleDismiss() SystemClock.sleep(6000); result.success = true; - result.enacted = false; + result.enacted = true; + result.comment = MainApp.instance().getString(R.string.virtualpump_resultok); } if (result.enacted) { result.carbsDelivered = detailedBolusInfo.carbs; - result.comment = MainApp.instance().getString(R.string.virtualpump_resultok); if (Config.logPumpActions) log.debug("deliverTreatment: OK. Asked: " + detailedBolusInfo.insulin + " Delivered: " + result.bolusDelivered); detailedBolusInfo.date = new Date().getTime(); @@ -291,6 +291,7 @@ public class ComboPlugin implements PluginBase, PumpInterface { } else { PumpEnactResult result = new PumpEnactResult(); result.success = false; + result.enacted = false; result.bolusDelivered = 0d; result.carbsDelivered = 0d; result.comment = MainApp.instance().getString(R.string.danar_invalidinput); From e01e85c54f06e9148d57dc38ca67b64941752a63 Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Sat, 15 Jul 2017 16:14:11 +0200 Subject: [PATCH 050/952] On connect, check if pump is in an error state. --- .../main/java/de/jotomo/ruffyscripter/RuffyScripter.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java b/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java index a26cf8acbd..69aa33bc44 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java @@ -126,6 +126,15 @@ public class RuffyScripter { // TODO hackish, to say the least ... // wait till pump is ready for input waitForMenuUpdate(); + // check if pump is an an error state + if (currentMenu != null && currentMenu.getType() == MenuType.WARNING_OR_ERROR) { + try { + PumpAlert alert = readDisplayPumpAlert(); + return new CommandResult().message("Pump is in an error state: " + alert + " (" + alert.code + ")"); + } catch (Exception e) { + return new CommandResult().message("Pump is in an error state, reading the error state resulted in the attached exception").exception(e); + } + } // TODO check pump state; currently most command check their in the MAIN_MENU; // run ReadStateCommand, which handles possible states ... and then do wait? // Return an unsuccessful CommandResult and make the caller do something loud with it From 4ff81e885cde5033e676d50a215d54671d3c5b58 Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Sat, 15 Jul 2017 16:14:38 +0200 Subject: [PATCH 051/952] Simplify reading alerts (message doesn't blink) --- .../main/java/de/jotomo/ruffyscripter/RuffyScripter.java | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java b/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java index 69aa33bc44..7fb389d8b9 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java @@ -347,16 +347,11 @@ public class RuffyScripter { public PumpAlert readDisplayPumpAlert() { Object errorObj = currentMenu.getAttribute(MenuAttribute.ERROR); - Object errorMsgObj = currentMenu.getAttribute(MenuAttribute.MESSAGE); while (errorObj == null) { SystemClock.sleep(10); errorObj = currentMenu.getAttribute(MenuAttribute.ERROR); - errorMsgObj = currentMenu.getAttribute(MenuAttribute.MESSAGE); } - while (errorMsgObj == null) { - SystemClock.sleep(10); - errorMsgObj = currentMenu.getAttribute(MenuAttribute.MESSAGE); - } - return new PumpAlert((int) errorObj, (String) errorMsgObj); + String errorMsg = (String) currentMenu.getAttribute(MenuAttribute.MESSAGE); + return new PumpAlert((int) errorObj, errorMsg); } } From f6c8f3638b6be40cff03cf8b55fbae8d0c7f1e2c Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Sat, 15 Jul 2017 16:21:16 +0200 Subject: [PATCH 052/952] Reflect reject TBR change in comment. --- .../nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java index 6ddfb1c8e7..9cf3dd8559 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java @@ -339,7 +339,7 @@ public class ComboPlugin implements PluginBase, PumpInterface { pumpEnactResult.success = true; pumpEnactResult.enacted = false; pumpEnactResult.percent = activeTbrPercentage; - pumpEnactResult.comment = "TBR change too small, skipping"; + pumpEnactResult.comment = "TBR change too small, skipping change from " + activeTbrPercentage + "% -> " + roundedPercentage + "%"; return pumpEnactResult; } int stepSize = pumpDescription.tempDurationStep; From 99830b05b65d8576ade8f8a32dd67260236b57cf Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Sat, 15 Jul 2017 16:46:12 +0200 Subject: [PATCH 053/952] Fix detecting error state on connection and fix cancelling TBR. When there's an error, timing is crucial. Waiting for the blinking error code to be readable hangs the thread running the command. --- .../java/de/jotomo/ruffyscripter/RuffyScripter.java | 13 +------------ .../ruffyscripter/commands/SetTbrCommand.java | 13 ++++++++----- 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java b/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java index 7fb389d8b9..c58f43d95c 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java @@ -129,8 +129,7 @@ public class RuffyScripter { // check if pump is an an error state if (currentMenu != null && currentMenu.getType() == MenuType.WARNING_OR_ERROR) { try { - PumpAlert alert = readDisplayPumpAlert(); - return new CommandResult().message("Pump is in an error state: " + alert + " (" + alert.code + ")"); + return new CommandResult().message("Pump is in an error state: " + currentMenu.getAttribute(MenuAttribute.MESSAGE)); } catch (Exception e) { return new CommandResult().message("Pump is in an error state, reading the error state resulted in the attached exception").exception(e); } @@ -344,14 +343,4 @@ public class RuffyScripter { } return state; } - - public PumpAlert readDisplayPumpAlert() { - Object errorObj = currentMenu.getAttribute(MenuAttribute.ERROR); - while (errorObj == null) { - SystemClock.sleep(10); - errorObj = currentMenu.getAttribute(MenuAttribute.ERROR); - } - String errorMsg = (String) currentMenu.getAttribute(MenuAttribute.MESSAGE); - return new PumpAlert((int) errorObj, errorMsg); - } } diff --git a/app/src/main/java/de/jotomo/ruffyscripter/commands/SetTbrCommand.java b/app/src/main/java/de/jotomo/ruffyscripter/commands/SetTbrCommand.java index 5bb90b2861..c12d588a51 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/commands/SetTbrCommand.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/commands/SetTbrCommand.java @@ -190,19 +190,22 @@ public class SetTbrCommand implements Command { scripter.pressCheckKey(); // we could read remaining duration from MAIN_MENU, but but the time we're here, - // we could have moved from 0:02 to 0:01, so instead,/ check if a TBR CANCELLED alert + // we could have moved from 0:02 to 0:01, so instead, check if a "TBR CANCELLED alert" // is raised and if so dismiss it scripter.waitForMenuToBeLeft(MenuType.TBR_SET); long inTwoSeconds = System.currentTimeMillis() + 2 * 1000; boolean alertProcessed = false; while (System.currentTimeMillis() < inTwoSeconds && !alertProcessed) { if (scripter.currentMenu.getType() == MenuType.WARNING_OR_ERROR) { - // check the raised alarm is TBR CANCELLED - PumpAlert alert = scripter.readDisplayPumpAlert(); - if (alert.code != 6 || Objects.equals(alert.msg, "TBR CANCELLED")) { + // check the raised alarm is TBR CANCELLED. + // note that the message is permanently displayed, while the error code is blinking. + // wait till the error code can be read results in the code hanging, despite + // menu updates coming in, so just check the message + String errorMsg = (String) scripter.currentMenu.getAttribute(MenuAttribute.MESSAGE); + if (!errorMsg.equals("TBR CANCELLED")) { throw new CommandException().success(false).enacted(false) .message("An alert other than the expected TBR CANCELLED was raised by the pump: " - + alert.code + "(" + alert.msg + "). Please check the pump."); + + errorMsg + ". Please check the pump."); } // confirm "TBR CANCELLED alert" scripter.pressCheckKey(); From 7e538cbcf6cdc84d5180a320f29e308059369a1b Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Sat, 15 Jul 2017 16:57:56 +0200 Subject: [PATCH 054/952] Update PumpState s/errorCode/errorMsg/g --- .../java/de/jotomo/ruffyscripter/commands/PumpState.java | 8 ++++---- .../jotomo/ruffyscripter/commands/ReadStateCommand.java | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/de/jotomo/ruffyscripter/commands/PumpState.java b/app/src/main/java/de/jotomo/ruffyscripter/commands/PumpState.java index 767f22b19a..95a5aa2bbf 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/commands/PumpState.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/commands/PumpState.java @@ -11,7 +11,7 @@ public class PumpState { public int tbrPercent = -1; public int tbrRemainingDuration = -1; public boolean isErrorOrWarning = false; - public int errorCode = -1; + public String errorMsg; public PumpState tbrActive(boolean tbrActive) { this.tbrActive = tbrActive; @@ -33,8 +33,8 @@ public class PumpState { return this; } - public PumpState errorCode(int errorCode) { - this.errorCode = errorCode; + public PumpState errorMsg(String errorMsg) { + this.errorMsg = errorMsg; return this; } @@ -45,7 +45,7 @@ public class PumpState { ", tbrPercent=" + tbrPercent + ", tbrRemainingDuration=" + tbrRemainingDuration + ", isErrorOrWarning=" + isErrorOrWarning + - ", errorCode=" + errorCode + + ", errorMsg=" + errorMsg + ", timestamp=" + timestamp + '}'; } diff --git a/app/src/main/java/de/jotomo/ruffyscripter/commands/ReadStateCommand.java b/app/src/main/java/de/jotomo/ruffyscripter/commands/ReadStateCommand.java index ac77dee602..139e727aad 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/commands/ReadStateCommand.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/commands/ReadStateCommand.java @@ -29,7 +29,7 @@ public class ReadStateCommand implements Command { } } else if (displayedMenuType == MenuType.WARNING_OR_ERROR) { state.isErrorOrWarning = true; - state.errorCode = (int) displayedMenu.getAttribute(MenuAttribute.ERROR); + state.errorMsg = (String) displayedMenu.getAttribute(MenuAttribute.MESSAGE); } else { throw new CommandException().success(false).message("Neither MAIN_MENU nor WARNING_OR_ERROR is displayed, but " + displayedMenuType); } From 9653af5501bb8e35fa84544862e753fe1db1a25b Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Sat, 15 Jul 2017 17:09:04 +0200 Subject: [PATCH 055/952] RuffyScripter.navigateToMenu: detect if we're wrapping around not finding a menu (likely because it's hidden) --- .../de/jotomo/ruffyscripter/RuffyScripter.java | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java b/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java index c58f43d95c..0e5f06d05c 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java @@ -282,19 +282,17 @@ public class RuffyScripter { } public void navigateToMenu(MenuType desiredMenu) { - // TODO menu var might not have been initialized if this is called to early - // though that's gonna be a problem for all code; - // wait during init till this is set? create a getter for currentMenu to do this? MenuType startedFrom = currentMenu.getType(); + boolean movedOnce = false; while (currentMenu.getType() != desiredMenu) { - MenuType currentType = currentMenu.getType(); -/* if (currentType == startedFrom) { - // TODO don't trigger right away, that's always a match ;-) - // failed to find the menu, after going through all the menus, bail out - throw new CommandException(false, null, "Menu not found searching for " + desiredMenu); - }*/ + MenuType currentMenuType = currentMenu.getType(); + if (movedOnce && currentMenuType == startedFrom) { + throw new CommandException().message("Menu not found searching for " + desiredMenu + + ". Check menu settings on your pump to ensure it's not hidden."); + } pressMenuKey(); - waitForMenuToBeLeft(currentType); + waitForMenuToBeLeft(currentMenuType); + movedOnce = true; } } From 69b98c54c67074133d22ccbbf8a77b46d4e0f78f Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Sat, 15 Jul 2017 17:09:23 +0200 Subject: [PATCH 056/952] Polish. --- .../jotomo/ruffyscripter/RuffyScripter.java | 19 +------------------ .../commands/CancelTbrCommand.java | 2 ++ .../ruffyscripter/commands/Command.java | 4 ---- .../ruffyscripter/commands/SetTbrCommand.java | 2 -- .../plugins/PumpCombo/ComboPlugin.java | 2 -- 5 files changed, 3 insertions(+), 26 deletions(-) diff --git a/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java b/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java index 0e5f06d05c..d5a04bdc2e 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java @@ -15,7 +15,6 @@ import org.slf4j.LoggerFactory; import de.jotomo.ruffyscripter.commands.Command; import de.jotomo.ruffyscripter.commands.CommandException; import de.jotomo.ruffyscripter.commands.CommandResult; -import de.jotomo.ruffyscripter.commands.PumpAlert; import de.jotomo.ruffyscripter.commands.PumpState; // TODO regularly read "My data" history (boluses, TBR) to double check all commands ran successfully. @@ -122,8 +121,6 @@ public class RuffyScripter { synchronized (this) { cmdResult = null; activeCmd = cmd; - final RuffyScripter scripter = this; - // TODO hackish, to say the least ... // wait till pump is ready for input waitForMenuUpdate(); // check if pump is an an error state @@ -134,10 +131,8 @@ public class RuffyScripter { return new CommandResult().message("Pump is in an error state, reading the error state resulted in the attached exception").exception(e); } } - // TODO check pump state; currently most command check their in the MAIN_MENU; - // run ReadStateCommand, which handles possible states ... and then do wait? - // Return an unsuccessful CommandResult and make the caller do something loud with it log.debug("Cmd execution: connection ready, executing cmd " + cmd); + final RuffyScripter scripter = this; cmdThread = new Thread(new Runnable() { @Override public void run() { @@ -240,7 +235,6 @@ public class RuffyScripter { } public void pressMenuKey() { - // TODO build 'wait for menu update' into this method? get current menu, press key, wait for update? log.debug("Pressing menu key"); pressKey(Key.MENU); log.debug("Releasing menu key"); @@ -260,17 +254,6 @@ public class RuffyScripter { } } - /** - * "Virtual" key, emulated by pressing menu and up simultaneously - */ - // Doesn't work -/* public void pressBackKey() throws RemoteException { - ruffyService.rtSendKey(Key.MENU, true); - SystemClock.sleep(50); - ruffyService.rtSendKey(Key.UP, true); - SystemClock.sleep(100); - ruffyService.rtSendKey(Key.NO_KEY, true); - }*/ private void pressKey(final byte key) { try { ruffyService.rtSendKey(key, true); diff --git a/app/src/main/java/de/jotomo/ruffyscripter/commands/CancelTbrCommand.java b/app/src/main/java/de/jotomo/ruffyscripter/commands/CancelTbrCommand.java index e87a4ebf2d..043a2de388 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/commands/CancelTbrCommand.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/commands/CancelTbrCommand.java @@ -8,6 +8,8 @@ import org.slf4j.LoggerFactory; import de.jotomo.ruffyscripter.RuffyScripter; // TODO robustness: can a TBR run out, whilst we're trying to cancel it? +// Hm, we could just ignore TBRs that run out within the next 60s (0:01 or even 0:02 +// given we need some time to process the request). public class CancelTbrCommand implements Command { private static final Logger log = LoggerFactory.getLogger(CancelTbrCommand.class); diff --git a/app/src/main/java/de/jotomo/ruffyscripter/commands/Command.java b/app/src/main/java/de/jotomo/ruffyscripter/commands/Command.java index c70384ae36..4763d5d521 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/commands/Command.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/commands/Command.java @@ -4,8 +4,4 @@ import de.jotomo.ruffyscripter.RuffyScripter; public interface Command { CommandResult execute(RuffyScripter ruffyScripter); - -// default String toString() { -// return getClass().getSimpleName(); -// } } diff --git a/app/src/main/java/de/jotomo/ruffyscripter/commands/SetTbrCommand.java b/app/src/main/java/de/jotomo/ruffyscripter/commands/SetTbrCommand.java index c12d588a51..f826f8a753 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/commands/SetTbrCommand.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/commands/SetTbrCommand.java @@ -110,7 +110,6 @@ public class SetTbrCommand implements Command { for (int i = 0; i < percentageSteps; i++) { if (increasePercentage) scripter.pressUpKey(); else scripter.pressDownKey(); - // TODO waitForMenuChange instead // or have key press method handle that?? SystemClock.sleep(100); log.debug("Push #" + (i + 1)); } @@ -159,7 +158,6 @@ public class SetTbrCommand implements Command { for (int i = 0; i < durationSteps; i++) { if (increaseDuration) scripter.pressUpKey(); else scripter.pressDownKey(); - // TODO waitForMenuChange instead // or have key press method handle that?? SystemClock.sleep(100); log.debug("Push #" + (i + 1)); } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java index 9cf3dd8559..707cde8764 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java @@ -209,7 +209,6 @@ public class ComboPlugin implements PluginBase, PumpInterface { return false; } - // TODO @Override public boolean isBusy() { return ruffyScripter.isPumpBusy(); @@ -227,7 +226,6 @@ public class ComboPlugin implements PluginBase, PumpInterface { return false; } - // TODO @Override public Date lastDataTime() { return lastCmdTime; From ec6491fcb77ac21c6a591de4a90ebac92a8ed11f Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Sat, 15 Jul 2017 18:19:10 +0200 Subject: [PATCH 057/952] Return absolute TBR rate in PumpState. --- app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java | 1 + .../java/de/jotomo/ruffyscripter/commands/NoOpCommand.java | 4 ++++ 2 files changed, 5 insertions(+) create mode 100644 app/src/main/java/de/jotomo/ruffyscripter/commands/NoOpCommand.java diff --git a/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java b/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java index d5a04bdc2e..f9fe9893ba 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java @@ -321,6 +321,7 @@ public class RuffyScripter { state.tbrPercent = displayedTbr.intValue(); MenuTime durationMenuTime = ((MenuTime) currentMenu.getAttribute(MenuAttribute.RUNTIME)); state.tbrRemainingDuration = durationMenuTime.getHour() * 60 + durationMenuTime.getMinute(); + state.tbrRate = ((double) currentMenu.getAttribute(MenuAttribute.BASAL_RATE)); } return state; } diff --git a/app/src/main/java/de/jotomo/ruffyscripter/commands/NoOpCommand.java b/app/src/main/java/de/jotomo/ruffyscripter/commands/NoOpCommand.java new file mode 100644 index 0000000000..25f3e2127c --- /dev/null +++ b/app/src/main/java/de/jotomo/ruffyscripter/commands/NoOpCommand.java @@ -0,0 +1,4 @@ +package de.jotomo.ruffyscripter.commands; + +public class NoOpCommand { +} From f251427d1b35c8c2e84f246c3539aa8f1e42d9fb Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Sat, 15 Jul 2017 18:35:41 +0200 Subject: [PATCH 058/952] Remove ReadStateCommand, all state will be return through the PumpState field on CommandResult, so it's passed back after every command. --- .../commands/ReadStateCommand.java | 48 ------------------- 1 file changed, 48 deletions(-) delete mode 100644 app/src/main/java/de/jotomo/ruffyscripter/commands/ReadStateCommand.java diff --git a/app/src/main/java/de/jotomo/ruffyscripter/commands/ReadStateCommand.java b/app/src/main/java/de/jotomo/ruffyscripter/commands/ReadStateCommand.java deleted file mode 100644 index 139e727aad..0000000000 --- a/app/src/main/java/de/jotomo/ruffyscripter/commands/ReadStateCommand.java +++ /dev/null @@ -1,48 +0,0 @@ -package de.jotomo.ruffyscripter.commands; - -import org.monkey.d.ruffy.ruffy.driver.display.Menu; -import org.monkey.d.ruffy.ruffy.driver.display.MenuAttribute; -import org.monkey.d.ruffy.ruffy.driver.display.MenuType; -import org.monkey.d.ruffy.ruffy.driver.display.menu.MenuTime; - -import de.jotomo.ruffyscripter.RuffyScripter; - -/** - * Reads the status displayed in the main menu. Usually TBR state or warning/error if any. - * This command is 'read-only', no buttons are pushed and so no vibrations are caused. - */ -public class ReadStateCommand implements Command { - @Override - public CommandResult execute(RuffyScripter scripter) { - try { - PumpState state = new PumpState(); - Menu displayedMenu = scripter.currentMenu; - MenuType displayedMenuType = displayedMenu.getType(); - if (displayedMenuType == MenuType.MAIN_MENU) { - Double tbrPercentage = (Double) displayedMenu.getAttribute(MenuAttribute.TBR); - if (tbrPercentage != 100) { - state.tbrActive = true; - Double displayedTbr = (Double) scripter.currentMenu.getAttribute(MenuAttribute.TBR); - state.tbrPercent = displayedTbr.intValue(); - MenuTime durationMenuTime = ((MenuTime) displayedMenu.getAttribute(MenuAttribute.RUNTIME)); - state.tbrRemainingDuration = durationMenuTime.getHour() * 60 + durationMenuTime.getMinute(); - } - } else if (displayedMenuType == MenuType.WARNING_OR_ERROR) { - state.isErrorOrWarning = true; - state.errorMsg = (String) displayedMenu.getAttribute(MenuAttribute.MESSAGE); - } else { - throw new CommandException().success(false).message("Neither MAIN_MENU nor WARNING_OR_ERROR is displayed, but " + displayedMenuType); - } - - return new CommandResult().success(true).enacted(false).state(state); - } catch (CommandException e) { - return e.toCommandResult(); - } - } - - @Override - public String toString() { - return "ReadStateCommand{}"; - } - -} From 8ecf6922f7b41d3a89e1420566843538505776a0 Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Sat, 15 Jul 2017 18:40:01 +0200 Subject: [PATCH 059/952] Misc improvements: * Make command execution (RuffyScripter/ComoboPlugin.runCommand) more robust (I still suck at threading). * Return all possible states in PumpState * Add absolute TBR to PumpState * Add NoOpCommand to fetch state data from pump * Display returned pump state in Combo fragment/tab. --- .../jotomo/ruffyscripter/RuffyScripter.java | 100 ++++++++++-------- .../ruffyscripter/commands/NoOpCommand.java | 13 ++- .../ruffyscripter/commands/PumpState.java | 7 ++ .../plugins/PumpCombo/ComboFragment.java | 19 +++- .../plugins/PumpCombo/ComboPlugin.java | 61 +++++++---- .../main/res/layout/combopump_fragment.xml | 8 ++ 6 files changed, 142 insertions(+), 66 deletions(-) diff --git a/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java b/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java index f9fe9893ba..7b200221e9 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java @@ -108,17 +108,16 @@ public class RuffyScripter { private volatile Command activeCmd = null; public CommandResult runCommand(final Command cmd) { - try { - if (isPumpBusy()) { - return new CommandResult().message("Pump is busy"); - } - ensureConnected(); + synchronized (this) { + try { + if (isPumpBusy()) { + return new CommandResult().message("Pump is busy"); + } + ensureConnected(); - // TODO reuse thread, scheduler ... - Thread cmdThread; + // TODO reuse thread, scheduler ... + Thread cmdThread; - // TODO make this a safe lock - synchronized (this) { cmdResult = null; activeCmd = cmd; // wait till pump is ready for input @@ -126,7 +125,8 @@ public class RuffyScripter { // check if pump is an an error state if (currentMenu != null && currentMenu.getType() == MenuType.WARNING_OR_ERROR) { try { - return new CommandResult().message("Pump is in an error state: " + currentMenu.getAttribute(MenuAttribute.MESSAGE)); + PumpState pumpState = readPumpState(); + return new CommandResult().message("Pump is in an error state: " + currentMenu.getAttribute(MenuAttribute.MESSAGE)).state(pumpState); } catch (Exception e) { return new CommandResult().message("Pump is in an error state, reading the error state resulted in the attached exception").exception(e); } @@ -147,33 +147,32 @@ public class RuffyScripter { } }); cmdThread.start(); - } - // TODO really? - long timeout = System.currentTimeMillis() + 90 * 1000; - while (activeCmd != null) { - SystemClock.sleep(500); - log.trace("Waiting for running command to complete"); - if (System.currentTimeMillis() > timeout) { - log.error("Running command " + activeCmd + " timed out"); - cmdThread.interrupt(); - activeCmd = null; - cmdResult = null; - return new CommandResult().success(false).enacted(false).message("Command timed out"); + // TODO really? + long timeout = System.currentTimeMillis() + 90 * 1000; + while (activeCmd != null) { + SystemClock.sleep(500); + log.trace("Waiting for running command to complete"); + if (System.currentTimeMillis() > timeout) { + log.error("Running command " + activeCmd + " timed out"); + cmdThread.interrupt(); + activeCmd = null; + return new CommandResult().success(false).enacted(false).message("Command timed out"); + } } - } - if (cmdResult.state == null) { - cmdResult.state = readPumpState(); + if (cmdResult.state == null) { + cmdResult.state = readPumpState(); + } + log.debug("Command result: " + cmdResult); + return cmdResult; + } catch (CommandException e) { + return e.toCommandResult(); + } catch (Exception e) { + return new CommandResult().exception(e).message("Unexpected exception communication with ruffy"); + } finally { + activeCmd = null; } - log.debug("Command result: " + cmdResult); - CommandResult r = cmdResult; - cmdResult = null; - return r; - } catch (CommandException e) { - return e.toCommandResult(); - } catch (Exception e) { - return new CommandResult().exception(e).message("Unexpected exception communication with ruffy"); } } @@ -288,7 +287,7 @@ public class RuffyScripter { if (System.currentTimeMillis() > timeout) { throw new CommandException().message("Timeout waiting for menu " + menuType + " to be left"); } - SystemClock.sleep(50); + SystemClock.sleep(10); } } @@ -312,16 +311,31 @@ public class RuffyScripter { } private PumpState readPumpState() { - verifyMenuIsDisplayed(MenuType.MAIN_MENU); PumpState state = new PumpState(); - Double tbrPercentage = (Double) currentMenu.getAttribute(MenuAttribute.TBR); - if (tbrPercentage != 100) { - state.tbrActive = true; - Double displayedTbr = (Double) currentMenu.getAttribute(MenuAttribute.TBR); - state.tbrPercent = displayedTbr.intValue(); - MenuTime durationMenuTime = ((MenuTime) currentMenu.getAttribute(MenuAttribute.RUNTIME)); - state.tbrRemainingDuration = durationMenuTime.getHour() * 60 + durationMenuTime.getMinute(); - state.tbrRate = ((double) currentMenu.getAttribute(MenuAttribute.BASAL_RATE)); + Menu menu = this.currentMenu; + MenuType menuType = menu.getType(); + if (menuType == MenuType.MAIN_MENU) { + Double tbrPercentage = (Double) menu.getAttribute(MenuAttribute.TBR); + if (tbrPercentage != 100) { + state.tbrActive = true; + Double displayedTbr = (Double) menu.getAttribute(MenuAttribute.TBR); + state.tbrPercent = displayedTbr.intValue(); + MenuTime durationMenuTime = ((MenuTime) menu.getAttribute(MenuAttribute.RUNTIME)); + state.tbrRemainingDuration = durationMenuTime.getHour() * 60 + durationMenuTime.getMinute(); + state.tbrRate = ((double) menu.getAttribute(MenuAttribute.BASAL_RATE)); + } + } else if (menuType == MenuType.WARNING_OR_ERROR) { + state.isErrorOrWarning = true; + state.errorMsg = (String) menu.getAttribute(MenuAttribute.MESSAGE); + } else { + StringBuilder sb = new StringBuilder(); + for (MenuAttribute menuAttribute : menu.attributes()) { + sb.append(menuAttribute); + sb.append(": "); + sb.append(menu.getAttribute(menuAttribute)); + sb.append("\n"); + } + state.errorMsg = "Pump is on menu " + menuType + ", listing attributes: \n" + sb.toString(); } return state; } diff --git a/app/src/main/java/de/jotomo/ruffyscripter/commands/NoOpCommand.java b/app/src/main/java/de/jotomo/ruffyscripter/commands/NoOpCommand.java index 25f3e2127c..9ae5f361c3 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/commands/NoOpCommand.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/commands/NoOpCommand.java @@ -1,4 +1,15 @@ package de.jotomo.ruffyscripter.commands; -public class NoOpCommand { +import de.jotomo.ruffyscripter.RuffyScripter; + +public class NoOpCommand implements Command { + @Override + public CommandResult execute(RuffyScripter ruffyScripter) { + return new CommandResult().success(true).enacted(false).message("Returning pump state only"); + } + + @Override + public String toString() { + return "NoOpCommand{}"; + } } diff --git a/app/src/main/java/de/jotomo/ruffyscripter/commands/PumpState.java b/app/src/main/java/de/jotomo/ruffyscripter/commands/PumpState.java index 95a5aa2bbf..47260dc5f7 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/commands/PumpState.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/commands/PumpState.java @@ -9,6 +9,7 @@ public class PumpState { public Date timestamp = new Date(); public boolean tbrActive = false; public int tbrPercent = -1; + public double tbrRate = -1; public int tbrRemainingDuration = -1; public boolean isErrorOrWarning = false; public String errorMsg; @@ -23,6 +24,11 @@ public class PumpState { return this; } + public PumpState tbrRate(double tbrRate) { + this.tbrRate = tbrRate; + return this; + } + public PumpState tbrRemainingDuration(int tbrRemainingDuration) { this.tbrRemainingDuration = tbrRemainingDuration; return this; @@ -43,6 +49,7 @@ public class PumpState { return "PumpState{" + "tbrActive=" + tbrActive + ", tbrPercent=" + tbrPercent + + ", tbrRate=" + tbrRate + ", tbrRemainingDuration=" + tbrRemainingDuration + ", isErrorOrWarning=" + isErrorOrWarning + ", errorMsg=" + errorMsg + diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboFragment.java index 49fc90c6ae..58367abc37 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboFragment.java @@ -9,6 +9,7 @@ import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.EditText; import android.widget.TextView; import com.squareup.otto.Subscribe; @@ -33,11 +34,15 @@ public class ComboFragment extends Fragment { return comboPlugin; } + private EditText statusText; + @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.combopump_fragment, container, false); + statusText = (EditText) view.findViewById(R.id.comboStatusEditText); + updateGUI(); return view; } @@ -65,9 +70,17 @@ public class ComboFragment extends Fragment { activity.runOnUiThread(new Runnable() { @Override public void run() { - -// your rendering code here - + if (getPlugin() == null) { + statusText.setText("Initializing"); + } else { + StringBuilder sb = new StringBuilder(); + sb.append(getPlugin().statusSummary); + if (getPlugin().pumpState != null) { + sb.append("\n\n"); + sb.append(getPlugin().pumpState.toString().replaceAll(",", "\n")); + } + statusText.setText(sb.toString()); + } } }); } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java index 707cde8764..5baf90ae3d 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java @@ -23,7 +23,7 @@ import de.jotomo.ruffyscripter.commands.BolusCommand; import de.jotomo.ruffyscripter.commands.CancelTbrCommand; import de.jotomo.ruffyscripter.commands.Command; import de.jotomo.ruffyscripter.commands.CommandResult; -import de.jotomo.ruffyscripter.commands.ReadStateCommand; +import de.jotomo.ruffyscripter.commands.NoOpCommand; import de.jotomo.ruffyscripter.commands.SetTbrCommand; import de.jotomo.ruffyscripter.commands.PumpState; import info.nightscout.androidaps.BuildConfig; @@ -36,11 +36,11 @@ import info.nightscout.androidaps.data.PumpEnactResult; import info.nightscout.androidaps.db.Source; import info.nightscout.androidaps.db.TemporaryBasal; import info.nightscout.androidaps.events.EventAppExit; -import info.nightscout.androidaps.events.EventPumpStatusChanged; import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PumpDescription; import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; +import info.nightscout.androidaps.plugins.PumpCombo.events.EventComboPumpUpdateGUI; import info.nightscout.utils.DateUtil; /** @@ -59,7 +59,9 @@ public class ComboPlugin implements PluginBase, PumpInterface { private ServiceConnection mRuffyServiceConnection; @Nullable - private volatile PumpState pumpState; + volatile PumpState pumpState; + + volatile String statusSummary = "Initializing"; private static PumpEnactResult OPERATION_NOT_SUPPORTED = new PumpEnactResult(); @@ -96,6 +98,12 @@ public class ComboPlugin implements PluginBase, PumpInterface { public void onServiceConnected(ComponentName name, IBinder service) { ruffyScripter = new RuffyScripter(IRuffyService.Stub.asInterface(service)); log.debug("ruffy serivce connected"); + new Thread(new Runnable() { + @Override + public void run() { + runCommand(new NoOpCommand()); + } + }).start(); } @Override @@ -299,18 +307,27 @@ public class ComboPlugin implements PluginBase, PumpInterface { } private CommandResult runCommand(Command command) { - // TODO use this to dispatch methods to a service thread, like DanaRs executionService - // will be required when doing multiple commands in sequence. - // Alternatively provide 'composite commands' to return everything needed in one go? - try { - CommandResult commandResult = ruffyScripter.runCommand(command); - if (commandResult.success && commandResult.state != null) { - pumpState = commandResult.state; + synchronized (this) { + // TODO use this to dispatch methods to a service thread, like DanaRs executionService + // will be required when doing multiple commands in sequence. + // Alternatively provide 'composite commands' to return everything needed in one go? + try { + statusSummary = "Busy running " + command; + pumpState = null; + MainApp.bus().post(new EventComboPumpUpdateGUI()); + CommandResult commandResult = ruffyScripter.runCommand(command); + if (commandResult.success && commandResult.state != null) { + pumpState = commandResult.state; + } + return commandResult; + } finally { + lastCmdTime = new Date(); + statusSummary = pumpState != null && !pumpState.isErrorOrWarning + ? "Idle" + : "Error: " + pumpState.errorMsg; + ruffyScripter.disconnect(); + MainApp.bus().post(new EventComboPumpUpdateGUI()); } - return commandResult; - } finally { - lastCmdTime = new Date(); - ruffyScripter.disconnect(); } } @@ -358,7 +375,6 @@ public class ComboPlugin implements PluginBase, PumpInterface { log.debug("Rounded requested percentage from " + percent + " to " + rounded); percent = rounded; } - MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.settingtempbasal))); CommandResult commandResult = runCommand(new SetTbrCommand(percent, durationInMinutes)); if (commandResult.enacted) { TemporaryBasal tempStart = new TemporaryBasal(System.currentTimeMillis()); @@ -387,10 +403,10 @@ public class ComboPlugin implements PluginBase, PumpInterface { return OPERATION_NOT_SUPPORTED; } + // TODO untested, probably not working @Override public PumpEnactResult cancelTempBasal() { log.debug("cancelTempBasal called"); - MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.stoppingtempbasal))); CommandResult commandResult = runCommand(new CancelTbrCommand()); if (commandResult.enacted) { TemporaryBasal tempStop = new TemporaryBasal(System.currentTimeMillis()); @@ -422,13 +438,20 @@ public class ComboPlugin implements PluginBase, PumpInterface { JSONObject status = new JSONObject(); JSONObject extended = new JSONObject(); try { - status.put("status", "normal"); + status.put("status", statusSummary); extended.put("Version", BuildConfig.VERSION_NAME + "-" + BuildConfig.BUILDVERSION); try { extended.put("ActiveProfile", MainApp.getConfigBuilder().getProfileName()); } catch (Exception e) { } - status.put("timestamp", DateUtil.toISOString(new Date())); + status.put("timestamp", lastCmdTime); + + if (pumpState != null) { + extended.put("TempBasalAbsoluteRate", pumpState.tbrRate); + // TODO best guess at this point ... + extended.put("TempBasalStart", DateUtil.dateAndTimeString(System.currentTimeMillis() - (pumpState.tbrRemainingDuration - 15 * 60 * 1000))); + extended.put("TempBasalRemaining", pumpState.tbrRemainingDuration); + } // more info here .... look at dana plugin @@ -454,7 +477,7 @@ public class ComboPlugin implements PluginBase, PumpInterface { @Override public String shortStatus(boolean veryShort) { - return deviceID(); + return statusSummary; } @Override diff --git a/app/src/main/res/layout/combopump_fragment.xml b/app/src/main/res/layout/combopump_fragment.xml index dd0948ef4c..cb3662d56a 100644 --- a/app/src/main/res/layout/combopump_fragment.xml +++ b/app/src/main/res/layout/combopump_fragment.xml @@ -17,4 +17,12 @@ + + From 8dd714b390d7be8c485faeb1c859c626033a01c5 Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Sat, 15 Jul 2017 18:57:22 +0200 Subject: [PATCH 060/952] UI crimes --- .../androidaps/plugins/PumpCombo/ComboFragment.java | 12 +++++++++--- app/src/main/res/layout/combopump_fragment.xml | 4 ++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboFragment.java index 58367abc37..32b034c4a1 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboFragment.java @@ -34,14 +34,14 @@ public class ComboFragment extends Fragment { return comboPlugin; } - private EditText statusText; + private TextView statusText; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.combopump_fragment, container, false); - statusText = (EditText) view.findViewById(R.id.comboStatusEditText); + statusText = (TextView) view.findViewById(R.id.comboStatusEditText); updateGUI(); return view; @@ -64,6 +64,7 @@ public class ComboFragment extends Fragment { updateGUI(); } + // TODO *very* quick hack public void updateGUI() { Activity activity = getActivity(); if (activity != null) @@ -77,7 +78,12 @@ public class ComboFragment extends Fragment { sb.append(getPlugin().statusSummary); if (getPlugin().pumpState != null) { sb.append("\n\n"); - sb.append(getPlugin().pumpState.toString().replaceAll(",", "\n")); + sb.append(getPlugin().pumpState.toString() + // i know ... i need to take a break already + .replaceAll(", ", "\n") + .replaceAll("PumpState\\{", "\n") + .replaceAll("\\}", "\n") + ); } statusText.setText(sb.toString()); } diff --git a/app/src/main/res/layout/combopump_fragment.xml b/app/src/main/res/layout/combopump_fragment.xml index cb3662d56a..eec7a650a5 100644 --- a/app/src/main/res/layout/combopump_fragment.xml +++ b/app/src/main/res/layout/combopump_fragment.xml @@ -21,8 +21,8 @@ android:id="@+id/comboStatusEditText" android:layout_width="match_parent" android:layout_height="match_parent" + android:layout_gravity="center" android:ems="10" - android:textAlignment="center" - android:layout_gravity="center_horizontal"/> + android:padding="10dp" /> From 3aecf0f58b7f7715444851865731323049b3a282 Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Sat, 15 Jul 2017 19:19:04 +0200 Subject: [PATCH 061/952] Be more cautious handling command failures. --- .../plugins/PumpCombo/ComboPlugin.java | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java index 5baf90ae3d..d1c0588db9 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java @@ -61,7 +61,7 @@ public class ComboPlugin implements PluginBase, PumpInterface { @Nullable volatile PumpState pumpState; - volatile String statusSummary = "Initializing"; + volatile String statusSummary = "No state received yet"; private static PumpEnactResult OPERATION_NOT_SUPPORTED = new PumpEnactResult(); @@ -311,21 +311,34 @@ public class ComboPlugin implements PluginBase, PumpInterface { // TODO use this to dispatch methods to a service thread, like DanaRs executionService // will be required when doing multiple commands in sequence. // Alternatively provide 'composite commands' to return everything needed in one go? + CommandResult commandResult = null; try { statusSummary = "Busy running " + command; pumpState = null; MainApp.bus().post(new EventComboPumpUpdateGUI()); - CommandResult commandResult = ruffyScripter.runCommand(command); + commandResult = ruffyScripter.runCommand(command); if (commandResult.success && commandResult.state != null) { pumpState = commandResult.state; } return commandResult; } finally { lastCmdTime = new Date(); - statusSummary = pumpState != null && !pumpState.isErrorOrWarning - ? "Idle" - : "Error: " + pumpState.errorMsg; - ruffyScripter.disconnect(); + statusSummary = "Idle"; + try { + if (pumpState != null) { + if (pumpState.errorMsg != null) { + statusSummary = "Error: " + pumpState.errorMsg; + } else if (pumpState.isErrorOrWarning) { + statusSummary = "Error: pump is in error mode, please check pump display"; + } + } + } catch (Exception e) { + statusSummary = "Error"; + } + if (commandResult != null && commandResult.success) { + // just leave it open, to avoid more errors + ruffyScripter.disconnect(); + } MainApp.bus().post(new EventComboPumpUpdateGUI()); } } From 4c0944b9f89c30f7d315eff90ccbde0c199c629f Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Sat, 15 Jul 2017 21:26:18 +0200 Subject: [PATCH 062/952] Optimize cancelling TBR. --- .../de/jotomo/ruffyscripter/commands/SetTbrCommand.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/de/jotomo/ruffyscripter/commands/SetTbrCommand.java b/app/src/main/java/de/jotomo/ruffyscripter/commands/SetTbrCommand.java index f826f8a753..b5e27576d3 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/commands/SetTbrCommand.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/commands/SetTbrCommand.java @@ -190,8 +190,7 @@ public class SetTbrCommand implements Command { // we could read remaining duration from MAIN_MENU, but but the time we're here, // we could have moved from 0:02 to 0:01, so instead, check if a "TBR CANCELLED alert" // is raised and if so dismiss it - scripter.waitForMenuToBeLeft(MenuType.TBR_SET); - long inTwoSeconds = System.currentTimeMillis() + 2 * 1000; + long inTwoSeconds = System.currentTimeMillis() + 5 * 1000; boolean alertProcessed = false; while (System.currentTimeMillis() < inTwoSeconds && !alertProcessed) { if (scripter.currentMenu.getType() == MenuType.WARNING_OR_ERROR) { @@ -207,13 +206,12 @@ public class SetTbrCommand implements Command { } // confirm "TBR CANCELLED alert" scripter.pressCheckKey(); - SystemClock.sleep(200); // dismiss "TBR CANCELLED alert" scripter.pressCheckKey(); scripter.waitForMenuToBeLeft(MenuType.WARNING_OR_ERROR); alertProcessed = true; } - SystemClock.sleep(50); + SystemClock.sleep(10); } } From 69e560baee805100c2023b94fe3bbb70150490ac Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Sat, 15 Jul 2017 21:26:37 +0200 Subject: [PATCH 063/952] Cleanup. --- .../androidaps/plugins/PumpCombo/ComboPlugin.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java index d1c0588db9..06b8e300a4 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java @@ -264,7 +264,6 @@ public class ComboPlugin implements PluginBase, PumpInterface { // writing carb treatments to the history table. What's PumpEnactResult for again? @Override public PumpEnactResult deliverTreatment(DetailedBolusInfo detailedBolusInfo) { - log.debug("deliver treatment called with dbi: " + detailedBolusInfo); if (detailedBolusInfo.insulin > 0 || detailedBolusInfo.carbs > 0) { PumpEnactResult result = new PumpEnactResult(); if (detailedBolusInfo.insulin > 0) { @@ -335,10 +334,8 @@ public class ComboPlugin implements PluginBase, PumpInterface { } catch (Exception e) { statusSummary = "Error"; } - if (commandResult != null && commandResult.success) { - // just leave it open, to avoid more errors - ruffyScripter.disconnect(); - } + + ruffyScripter.disconnect(); MainApp.bus().post(new EventComboPumpUpdateGUI()); } } From 83e9ec743ec421166c99fc17cebc3754cfdfe586 Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Sat, 15 Jul 2017 21:47:06 +0200 Subject: [PATCH 064/952] Properly accessing volatile field pumpState. --- .../plugins/PumpCombo/ComboFragment.java | 9 +++---- .../plugins/PumpCombo/ComboPlugin.java | 27 +++++++++---------- 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboFragment.java index 32b034c4a1..23b176476b 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboFragment.java @@ -17,13 +17,11 @@ import com.squareup.otto.Subscribe; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.Date; +import de.jotomo.ruffyscripter.commands.PumpState; import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.R; import info.nightscout.androidaps.plugins.PumpCombo.events.EventComboPumpUpdateGUI; -import info.nightscout.androidaps.plugins.PumpVirtual.VirtualPumpPlugin; -import info.nightscout.androidaps.plugins.PumpVirtual.events.EventVirtualPumpUpdateGui; public class ComboFragment extends Fragment { private static Logger log = LoggerFactory.getLogger(ComboFragment.class); @@ -76,9 +74,10 @@ public class ComboFragment extends Fragment { } else { StringBuilder sb = new StringBuilder(); sb.append(getPlugin().statusSummary); - if (getPlugin().pumpState != null) { + PumpState ps = getPlugin().pumpState; + if (ps != null) { sb.append("\n\n"); - sb.append(getPlugin().pumpState.toString() + sb.append(ps.toString() // i know ... i need to take a break already .replaceAll(", ", "\n") .replaceAll("PumpState\\{", "\n") diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java index 06b8e300a4..ebd8b69d3f 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboPlugin.java @@ -323,16 +323,13 @@ public class ComboPlugin implements PluginBase, PumpInterface { } finally { lastCmdTime = new Date(); statusSummary = "Idle"; - try { - if (pumpState != null) { - if (pumpState.errorMsg != null) { - statusSummary = "Error: " + pumpState.errorMsg; - } else if (pumpState.isErrorOrWarning) { - statusSummary = "Error: pump is in error mode, please check pump display"; - } + PumpState ps = pumpState; + if (ps != null) { + if (ps.errorMsg != null) { + statusSummary = "Error: " + ps.errorMsg; + } else if (ps.isErrorOrWarning) { + statusSummary = "Error: pump is in error mode, please check pump display"; } - } catch (Exception e) { - statusSummary = "Error"; } ruffyScripter.disconnect(); @@ -357,7 +354,8 @@ public class ComboPlugin implements PluginBase, PumpInterface { if (unroundedPercentage != roundedPercentage) { log.debug("Rounded requested rate " + unroundedPercentage + "% -> " + roundedPercentage + "%"); } - int activeTbrPercentage = pumpState != null ? pumpState.tbrPercent : 100; + PumpState ps = pumpState; + int activeTbrPercentage = ps != null ? ps.tbrPercent : 100; if (activeTbrPercentage != -1 && Math.abs(activeTbrPercentage - roundedPercentage) <= 20) { log.debug("Not bothering the pump for a small TBR change from " + activeTbrPercentage + "% -> " + roundedPercentage + "%"); PumpEnactResult pumpEnactResult = new PumpEnactResult(); @@ -456,11 +454,12 @@ public class ComboPlugin implements PluginBase, PumpInterface { } status.put("timestamp", lastCmdTime); - if (pumpState != null) { - extended.put("TempBasalAbsoluteRate", pumpState.tbrRate); + PumpState ps = this.pumpState; + if (ps != null) { + extended.put("TempBasalAbsoluteRate", ps.tbrRate); // TODO best guess at this point ... - extended.put("TempBasalStart", DateUtil.dateAndTimeString(System.currentTimeMillis() - (pumpState.tbrRemainingDuration - 15 * 60 * 1000))); - extended.put("TempBasalRemaining", pumpState.tbrRemainingDuration); + extended.put("TempBasalStart", DateUtil.dateAndTimeString(System.currentTimeMillis() - (ps.tbrRemainingDuration - 15 * 60 * 1000))); + extended.put("TempBasalRemaining", ps.tbrRemainingDuration); } // more info here .... look at dana plugin From 2ddccd3c315bb06537808a24dc002dfe9b2931b9 Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Sun, 16 Jul 2017 00:00:34 +0200 Subject: [PATCH 065/952] RuffyScripter.runCommand: Next shot at understanding threading better. --- .../jotomo/ruffyscripter/RuffyScripter.java | 62 +++++++++---------- 1 file changed, 29 insertions(+), 33 deletions(-) diff --git a/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java b/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java index 7b200221e9..96ddae74df 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java @@ -110,68 +110,64 @@ public class RuffyScripter { public CommandResult runCommand(final Command cmd) { synchronized (this) { try { - if (isPumpBusy()) { - return new CommandResult().message("Pump is busy"); - } - ensureConnected(); - - // TODO reuse thread, scheduler ... - Thread cmdThread; - - cmdResult = null; activeCmd = cmd; - // wait till pump is ready for input - waitForMenuUpdate(); - // check if pump is an an error state - if (currentMenu != null && currentMenu.getType() == MenuType.WARNING_OR_ERROR) { - try { - PumpState pumpState = readPumpState(); - return new CommandResult().message("Pump is in an error state: " + currentMenu.getAttribute(MenuAttribute.MESSAGE)).state(pumpState); - } catch (Exception e) { - return new CommandResult().message("Pump is in an error state, reading the error state resulted in the attached exception").exception(e); - } - } - log.debug("Cmd execution: connection ready, executing cmd " + cmd); + cmdResult = null; + Thread cmdThread; final RuffyScripter scripter = this; cmdThread = new Thread(new Runnable() { @Override public void run() { try { + ensureConnected(); + cmdResult = null; + // wait till pump is ready for input + waitForMenuUpdate(); + // check if pump is an an error state + if (currentMenu != null && currentMenu.getType() == MenuType.WARNING_OR_ERROR) { + try { + PumpState pumpState = readPumpState(); + cmdResult = new CommandResult().message("Pump is in an error state: " + currentMenu.getAttribute(MenuAttribute.MESSAGE)).state(pumpState); + return; + } catch (Exception e) { + cmdResult = new CommandResult().message("Pump is in an error state, reading the error state resulted in the attached exception").exception(e); + return; + } + } + log.debug("Cmd execution: connection ready, executing cmd " + cmd); cmdResult = cmd.execute(scripter); + } catch (CommandException e) { + cmdResult = e.toCommandResult(); } catch (Exception e) { cmdResult = new CommandResult().exception(e).message("Unexpected exception running cmd"); - } finally { - activeCmd = null; } - } }); cmdThread.start(); - // TODO really? long timeout = System.currentTimeMillis() + 90 * 1000; - while (activeCmd != null) { - SystemClock.sleep(500); + while (cmdResult == null) { log.trace("Waiting for running command to complete"); + SystemClock.sleep(500); if (System.currentTimeMillis() > timeout) { log.error("Running command " + activeCmd + " timed out"); cmdThread.interrupt(); - activeCmd = null; - return new CommandResult().success(false).enacted(false).message("Command timed out"); + cmdResult = new CommandResult().success(false).enacted(false).message("Command timed out"); } } - if (cmdResult.state == null) { - cmdResult.state = readPumpState(); + CommandResult result = cmdResult; + if (result.state == null) { + result.state = readPumpState(); } - log.debug("Command result: " + cmdResult); - return cmdResult; + log.debug("Command result: " + result); + return result; } catch (CommandException e) { return e.toCommandResult(); } catch (Exception e) { return new CommandResult().exception(e).message("Unexpected exception communication with ruffy"); } finally { activeCmd = null; + cmdResult = null; } } } From ccd81c67fd881d1de18e130fa2ad83a31f2277d7 Mon Sep 17 00:00:00 2001 From: Johannes Mockenhaupt Date: Sun, 16 Jul 2017 03:28:11 +0200 Subject: [PATCH 066/952] UI for pump state. --- .../plugins/PumpCombo/ComboFragment.java | 79 +++-- .../main/res/layout/combopump_fragment.xml | 289 +++++++++++++++++- 2 files changed, 336 insertions(+), 32 deletions(-) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboFragment.java index 23b176476b..e00838fc0e 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpCombo/ComboFragment.java @@ -3,13 +3,11 @@ package info.nightscout.androidaps.plugins.PumpCombo; import android.app.Activity; import android.os.Bundle; -import android.os.Handler; -import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.EditText; +import android.widget.Button; import android.widget.TextView; import com.squareup.otto.Subscribe; @@ -23,7 +21,7 @@ import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.R; import info.nightscout.androidaps.plugins.PumpCombo.events.EventComboPumpUpdateGUI; -public class ComboFragment extends Fragment { +public class ComboFragment extends Fragment implements View.OnClickListener { private static Logger log = LoggerFactory.getLogger(ComboFragment.class); private static ComboPlugin comboPlugin = new ComboPlugin(); @@ -32,14 +30,29 @@ public class ComboFragment extends Fragment { return comboPlugin; } - private TextView statusText; + private Button update; + private TextView status; + private TextView tbrPercentage; + private TextView tbrDurationRemaining; + private TextView tbrRate; + private TextView errorMsg; + private TextView lastUpdate; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.combopump_fragment, container, false); - statusText = (TextView) view.findViewById(R.id.comboStatusEditText); + update = (Button) view.findViewById(R.id.combo_update); + status = (TextView) view.findViewById(R.id.combo_status); + tbrPercentage = (TextView) view.findViewById(R.id.combo_tbr_percentage); + tbrDurationRemaining = (TextView) view.findViewById(R.id.combo_tbr_duration_remaining); + tbrRate = (TextView) view.findViewById(R.id.combo_tbr_rate); + errorMsg = (TextView) view.findViewById(R.id.combo_error_message); + lastUpdate = (TextView) view.findViewById(R.id.combo_last_update); + + update.setOnClickListener(this); + status.setText("Initializing"); updateGUI(); return view; @@ -62,29 +75,51 @@ public class ComboFragment extends Fragment { updateGUI(); } - // TODO *very* quick hack + + @Override + public void onClick(View view) { + switch (view.getId()) { + case R.id.combo_update: + status.setText("Updating"); + Thread thread = new Thread(new Runnable() { + @Override + public void run() { + getPlugin().fetchPumpState(); + updateGUI(); + } + }); + thread.start(); + break; + } + } + public void updateGUI() { Activity activity = getActivity(); if (activity != null) activity.runOnUiThread(new Runnable() { @Override public void run() { - if (getPlugin() == null) { - statusText.setText("Initializing"); - } else { - StringBuilder sb = new StringBuilder(); - sb.append(getPlugin().statusSummary); - PumpState ps = getPlugin().pumpState; - if (ps != null) { - sb.append("\n\n"); - sb.append(ps.toString() - // i know ... i need to take a break already - .replaceAll(", ", "\n") - .replaceAll("PumpState\\{", "\n") - .replaceAll("\\}", "\n") - ); + PumpState ps = getPlugin().pumpState; + status.setText(getPlugin().isBusy() ? "Busy" : "Idle"); + if (getPlugin() != null && ps != null) { + boolean tbrActive = ps.tbrPercent != -1 && ps.tbrPercent != 100; + if (tbrActive) { + tbrPercentage.setText("" + ps.tbrPercent + "%"); + tbrDurationRemaining.setText("" + ps.tbrRemainingDuration + " min"); + tbrRate.setText("" + ps.tbrRate + " U/h"); + } else { + tbrPercentage.setText(""); + tbrDurationRemaining.setText(""); + tbrRate.setText(""); } - statusText.setText(sb.toString()); + errorMsg.setText(ps.errorMsg != null ? ps.errorMsg : ""); + lastUpdate.setText(ps.timestamp.toLocaleString()); + } else { + tbrPercentage.setText(""); + tbrRate.setText(""); + tbrDurationRemaining.setText(""); + errorMsg.setText(""); + lastUpdate.setText(""); } } }); diff --git a/app/src/main/res/layout/combopump_fragment.xml b/app/src/main/res/layout/combopump_fragment.xml index eec7a650a5..4c66106f2a 100644 --- a/app/src/main/res/layout/combopump_fragment.xml +++ b/app/src/main/res/layout/combopump_fragment.xml @@ -5,24 +5,293 @@ tools:context=".plugins.PumpCombo.ComboFragment"> +