From 1d3fee54e9961f21527daf25776fba38fdc6ec52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sandra=20Ke=C3=9Fler?= Date: Sun, 30 Jul 2017 17:53:37 +0200 Subject: [PATCH 01/18] if umbind fails while service is dead, bind would never be called --- .../androidaps/plugins/PumpCombo/ComboPlugin.java | 6 ++++++ 1 file changed, 6 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 c037b3dc2e..1ee0b085b5 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 @@ -414,6 +414,12 @@ public class ComboPlugin implements PluginBase, PumpInterface { try { unbindRuffyService(); SystemClock.sleep(5000); + } catch (Exception e) { + /*String msg = "No connection to ruffy. Pump control not available."; + statusSummary = msg; + return new CommandResult().message(msg);*/ + } + try { bindRuffyService(); SystemClock.sleep(5000); } catch (Exception e) { From bfb6039c16718da17db240fb85142449cf0f2948 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sandra=20Ke=C3=9Fler?= Date: Sun, 30 Jul 2017 18:01:01 +0200 Subject: [PATCH 02/18] slow pump fix --- .../ruffyscripter/commands/BolusCommand.java | 8 ++++---- .../ruffyscripter/commands/SetTbrCommand.java | 14 +++++++------- 2 files changed, 11 insertions(+), 11 deletions(-) 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 d5197452e3..8f5b728abb 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/commands/BolusCommand.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/commands/BolusCommand.java @@ -58,7 +58,7 @@ public class BolusCommand implements Command { Double bolusRemaining = (Double) scripter.currentMenu.getAttribute(MenuAttribute.BOLUS_REMAINING); while (bolusRemaining != null) { log.debug("Delivering bolus, remaining: " + bolusRemaining); - SystemClock.sleep(200); + SystemClock.sleep(300); bolusRemaining = (Double) scripter.currentMenu.getAttribute(MenuAttribute.BOLUS_REMAINING); } @@ -122,11 +122,11 @@ public class BolusCommand implements Command { for (int i = 0; i < steps; i++) { scripter.verifyMenuIsDisplayed(MenuType.BOLUS_ENTER); scripter.pressUpKey(); - SystemClock.sleep(100); + SystemClock.sleep(400); } // Give the pump time to finish any scrolling that might still be going on, can take // up to 1100ms. Plus some extra time to be sure - SystemClock.sleep(2000); + SystemClock.sleep(750); } private void verifyDisplayedBolusAmount(RuffyScripter scripter) { @@ -138,7 +138,7 @@ public class BolusCommand implements Command { } // check again to ensure the displayed value hasn't change due to due scrolling taking extremely long - SystemClock.sleep(2000); + SystemClock.sleep(750); double refreshedDisplayedBolus = readDisplayedBolusAmount(scripter); if (Math.abs(displayedBolus - refreshedDisplayedBolus) > 0.05) { throw new CommandException().message("Failed to set bolus: bolus changed after input stopped from " 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 4ffd154acf..a1c7a800fb 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/commands/SetTbrCommand.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/commands/SetTbrCommand.java @@ -121,12 +121,12 @@ public class SetTbrCommand implements Command { scripter.verifyMenuIsDisplayed(MenuType.TBR_SET); if (increasePercentage) scripter.pressUpKey(); else scripter.pressDownKey(); - SystemClock.sleep(100); + SystemClock.sleep(400); log.debug("Push #" + (i + 1)); } // Give the pump time to finish any scrolling that might still be going on, can take // up to 1100ms. Plus some extra time to be sure - SystemClock.sleep(2000); + SystemClock.sleep(750); } private void verifyDisplayedTbrPercentage(RuffyScripter scripter) { @@ -138,7 +138,7 @@ public class SetTbrCommand implements Command { } // check again to ensure the displayed value hasn't change due to due scrolling taking extremely long - SystemClock.sleep(2000); + SystemClock.sleep(750); long refreshedDisplayedTbrPecentage = readDisplayedTbrPercentage(scripter); if (displayedPercentage != refreshedDisplayedTbrPecentage) { throw new CommandException().message("Failed to set TBR percentage: " + @@ -186,12 +186,12 @@ public class SetTbrCommand implements Command { scripter.verifyMenuIsDisplayed(MenuType.TBR_DURATION); if (increaseDuration) scripter.pressUpKey(); else scripter.pressDownKey(); - SystemClock.sleep(100); + SystemClock.sleep(400); log.debug("Push #" + (i + 1)); } // Give the pump time to finish any scrolling that might still be going on, can take // up to 1100ms. Plus some extra time to be sure - SystemClock.sleep(2000); + SystemClock.sleep(750); } private void verifyDisplayedTbrDuration(RuffyScripter scripter) { @@ -203,7 +203,7 @@ public class SetTbrCommand implements Command { } // check again to ensure the displayed value hasn't change due to due scrolling taking extremely long - SystemClock.sleep(2000); + SystemClock.sleep(750); long refreshedDisplayedTbrDuration = readDisplayedTbrDuration(scripter); if (displayedDuration != refreshedDisplayedTbrDuration) { throw new CommandException().message("Failed to set TBR duration: " + @@ -261,7 +261,7 @@ public class SetTbrCommand implements Command { scripter.waitForMenuToBeLeft(MenuType.WARNING_OR_ERROR); alertProcessed = true; } - SystemClock.sleep(10); + SystemClock.sleep(20); } } From 7c001e97bf4374e5ac00b1a8626a1ec28a6000e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sandra=20Ke=C3=9Fler?= Date: Sun, 30 Jul 2017 22:22:13 +0200 Subject: [PATCH 03/18] wait till we get something currentDuration % 15 == 0 --- .../java/de/jotomo/ruffyscripter/commands/SetTbrCommand.java | 3 ++- 1 file changed, 2 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 a1c7a800fb..be072e3f20 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/commands/SetTbrCommand.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/commands/SetTbrCommand.java @@ -162,7 +162,8 @@ public class SetTbrCommand implements Command { private void inputTbrDuration(RuffyScripter scripter) { scripter.verifyMenuIsDisplayed(MenuType.TBR_DURATION); long currentDuration = readDisplayedTbrDuration(scripter); - if (currentDuration % 15 != 0) { + while(currentDuration % 15 != 0) + { // The duration displayed is how long an active TBR will still run, // which might be something like 0:13, hence not in 15 minute steps. // Pressing up will go to the next higher 15 minute step. From a7165497ea3221cc7cd82f378c27db20977d826c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sandra=20Ke=C3=9Fler?= Date: Sun, 30 Jul 2017 22:49:52 +0200 Subject: [PATCH 04/18] increase Button Timing to 200ms --- app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java b/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java index 72fe99c75d..69ad56178e 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java @@ -404,7 +404,7 @@ public class RuffyScripter { private void pressKey(final byte key) { try { ruffyService.rtSendKey(key, true); - SystemClock.sleep(100); + SystemClock.sleep(200); ruffyService.rtSendKey(Key.NO_KEY, true); } catch (RemoteException e) { throw new CommandException().exception(e).message("Error while pressing buttons"); From 3497296b6c39eef546322ef93a84df03acab0c5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sandra=20Ke=C3=9Fler?= Date: Mon, 31 Jul 2017 09:08:12 +0200 Subject: [PATCH 05/18] more time --- app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java | 4 ++-- .../java/de/jotomo/ruffyscripter/commands/SetTbrCommand.java | 3 +++ 2 files changed, 5 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 69ad56178e..df32847b59 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java @@ -336,7 +336,7 @@ public class RuffyScripter { // if the user just pressed a button on the combo, the screen needs to time first // before a connection is possible. In that case, it takes 45s before the // connection comes up. - waitForMenuUpdate(90); + waitForMenuUpdate(180); } catch (RemoteException e) { throw new CommandException().exception(e).message("Unexpected exception while initiating/restoring pump connection"); } @@ -387,7 +387,7 @@ public class RuffyScripter { * Wait until the menu update is in */ public void waitForMenuUpdate() { - waitForMenuUpdate(60); + waitForMenuUpdate(120); } public void waitForMenuUpdate(long timeoutInSeconds) { 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 be072e3f20..5815425e51 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/commands/SetTbrCommand.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/commands/SetTbrCommand.java @@ -171,9 +171,12 @@ public class SetTbrCommand implements Command { // Pressing up from 23:59 works to go to 24:00. scripter.verifyMenuIsDisplayed(MenuType.TBR_DURATION); scripter.pressUpKey(); + SystemClock.sleep(300); scripter.waitForMenuUpdate(); currentDuration = readDisplayedTbrDuration(scripter); } + SystemClock.sleep(300); + currentDuration = readDisplayedTbrDuration(scripter); log.debug("Current TBR duration: " + currentDuration); long durationChange = duration - currentDuration; long durationSteps = durationChange / 15; From 58e67914415848b1046e0c73068ca5f3fc970f14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sandra=20Ke=C3=9Fler?= Date: Mon, 31 Jul 2017 11:52:31 +0200 Subject: [PATCH 06/18] alternate setTBR based on StateMachine --- .../ruffyscripter/commands/SetTbrCommand.java | 526 ++++++++++-------- 1 file changed, 291 insertions(+), 235 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 5815425e51..93adbbd8ba 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/commands/SetTbrCommand.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/commands/SetTbrCommand.java @@ -1,7 +1,5 @@ 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; @@ -15,11 +13,21 @@ import java.util.Locale; import de.jotomo.ruffyscripter.PumpState; import de.jotomo.ruffyscripter.RuffyScripter; +import static de.jotomo.ruffyscripter.commands.SetTbrCommand.State.AFTER; +import static de.jotomo.ruffyscripter.commands.SetTbrCommand.State.BEFORE; +import static de.jotomo.ruffyscripter.commands.SetTbrCommand.State.ERROR; +import static de.jotomo.ruffyscripter.commands.SetTbrCommand.State.MAIN; +import static de.jotomo.ruffyscripter.commands.SetTbrCommand.State.SET; +import static de.jotomo.ruffyscripter.commands.SetTbrCommand.State.SET_TBR; +import static de.jotomo.ruffyscripter.commands.SetTbrCommand.State.SET_TIME; +import static de.jotomo.ruffyscripter.commands.SetTbrCommand.State.TBR; + public class SetTbrCommand implements Command { private static final Logger log = LoggerFactory.getLogger(SetTbrCommand.class); private final long percentage; private final long duration; + private RuffyScripter scripter; public SetTbrCommand(long percentage, long duration) { this.percentage = percentage; @@ -53,247 +61,295 @@ public class SetTbrCommand implements Command { return violations; } + enum State { + BEFORE, + MAIN, + TBR, + SET_TBR, + SET_TIME, + SET, + AFTER, + ERROR + }; + private State lastState,state; + private long last; + private long timeout; + private Thread timeoutThread = new Thread() + { + @Override + public void run() { + while(state != ERROR && state!=AFTER) { + if (timeout + last < System.currentTimeMillis()) { + lastState = state; + state = ERROR; + log.debug("timeout reached -> state:ERROR"); + } + tick(); + try { + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + tick(); + } + }; + private void updateState(State newState,long timeoutSec) + { + lastState = state; + state = newState; + last = System.currentTimeMillis(); + timeout = timeoutSec*1000; + } + private MenuType lastMenu; + private void tick() + { + switch (state) + { + case BEFORE: + if(scripter.currentMenu.getType()==MenuType.MAIN_MENU) + { + updateState(MAIN,120); + lastMenu = MenuType.MAIN_MENU; + log.debug("found MAIN_MENU -> state:MAIN"); + } + break; + case MAIN: + if(scripter.currentMenu.getType()==MenuType.TBR_MENU) + { + updateState(TBR,30); + scripter.pressCheckKey(); + log.debug("found TBR_MENU -> state:TBR"); + try { + Thread.sleep(750); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + else if(scripter.currentMenu.getType()!=lastMenu) + { + lastMenu = scripter.currentMenu.getType(); + updateState(MAIN,30); + scripter.pressMenuKey(); + log.debug("found Menu:"+lastMenu+" -> state:MAIN"); + try { + Thread.sleep(750); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + else + { + scripter.pressMenuKey(); + try { + Thread.sleep(750); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + break; + case TBR: + if(scripter.currentMenu.getType()==MenuType.TBR_SET) + { + updateState(SET_TBR,60); + } + else + { + scripter.pressMenuKey(); + try { + Thread.sleep(750); + } catch (InterruptedException e) { + e.printStackTrace(); + } + updateState(TBR,60); + } + break; + case SET_TBR: + if(scripter.currentMenu.getType()==MenuType.TBR_SET) + { + Object percentageObj = scripter.currentMenu.getAttribute(MenuAttribute.BASAL_RATE); + if(percentageObj != null && percentageObj instanceof Double) + { + double currentPercentage = ((Double) percentageObj).doubleValue(); + if(currentPercentage < percentage) + { + scripter.pressUpKey(); + updateState(SET_TBR,30); + try { + Thread.sleep(750); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + else if(currentPercentage > percentage) + { + scripter.pressDownKey(); + updateState(SET_TBR,30); + try { + Thread.sleep(750); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + else + { + if(percentage==100) + { + scripter.pressCheckKey(); + updateState(SET, 30); + } + else { + scripter.pressMenuKey(); + updateState(SET_TIME, 30); + } + } + } + } + else if(scripter.currentMenu.getType()==MenuType.TBR_DURATION) + { + scripter.pressMenuKey(); + updateState(TBR,60); + try { + Thread.sleep(750); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + else + { + updateState(ERROR,30); + } + break; + case SET_TIME: + if(scripter.currentMenu.getType()==MenuType.TBR_DURATION) + { + Object durationObj = scripter.currentMenu.getAttribute(MenuAttribute.RUNTIME); + if(durationObj != null && durationObj instanceof MenuTime) + { + MenuTime time = (MenuTime) durationObj; + double currentDuration = (time.getHour()*60)+time.getMinute(); + if(currentDuration < duration) + { + scripter.pressUpKey(); + updateState(SET_TIME,30); + try { + Thread.sleep(750); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + else if(currentDuration > duration) + { + scripter.pressDownKey(); + updateState(SET_TIME,30); + try { + Thread.sleep(750); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + else + { + scripter.pressCheckKey(); + updateState(SET, 30); + try { + Thread.sleep(750); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + } + else if(scripter.currentMenu.getType()==MenuType.TBR_SET) + { + scripter.pressMenuKey(); + updateState(SET_TIME,60); + try { + Thread.sleep(750); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + else + { + updateState(ERROR,60); + } + break; + case SET: + if(scripter.currentMenu.getType()==MenuType.WARNING_OR_ERROR) + { + lastMenu = scripter.currentMenu.getType(); + scripter.pressCheckKey(); + updateState(SET, 30); + try { + Thread.sleep(750); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + else if(scripter.currentMenu.getType()==MenuType.MAIN_MENU) { + Object setPercentage = scripter.currentMenu.getAttribute(MenuAttribute.TBR); + Object setDuration = scripter.currentMenu.getAttribute(MenuAttribute.RUNTIME); + if (setPercentage== null ||setDuration==null) { + if(percentage!=100) + { + updateState(ERROR,10); + } + else + { + if(lastMenu==MenuType.WARNING_OR_ERROR) + updateState(AFTER,10); + else + updateState(SET,10); + } + } + else { + double mmTbrPercentage = (Double) setPercentage; + MenuTime mmTbrDuration = (MenuTime) setDuration; + // ... 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) { + updateState(AFTER, 10); + } else { + updateState(ERROR, 10); + } + } + } + break; + case ERROR: + case AFTER: + synchronized(SetTbrCommand.this) { + SetTbrCommand.this.notify(); + } + break; + } + } @Override public CommandResult execute(RuffyScripter scripter, PumpState initialPumpState) { - try { - enterTbrMenu(scripter); - inputTbrPercentage(scripter); - verifyDisplayedTbrPercentage(scripter); + state = BEFORE; + this.scripter = scripter; + updateState(BEFORE,120); + timeoutThread.start(); - if (percentage == 100) { - cancelTbrAndConfirmCancellationWarning(scripter); - } else { - // switch to TBR_DURATION menu by pressing menu key - scripter.verifyMenuIsDisplayed(MenuType.TBR_SET); - scripter.pressMenuKey(); - scripter.waitForMenuUpdate(); - scripter.verifyMenuIsDisplayed(MenuType.TBR_DURATION); - - inputTbrDuration(scripter); - verifyDisplayedTbrDuration(scripter); - - // confirm TBR - scripter.pressCheckKey(); - scripter.waitForMenuToBeLeft(MenuType.TBR_DURATION); + try { + synchronized (this) { + this.wait(); + } + } catch (InterruptedException e) { + e.printStackTrace(); + return new CommandResult().success(false).message("failed to wait: "+e.getMessage()); } + if(state==AFTER) + { + if(percentage==100) + return new CommandResult().success(true).enacted(true).message("TBR was cancelled"); - 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.verifyMenuIsDisplayed(MenuType.MAIN_MENU); - scripter.navigateToMenu(MenuType.TBR_MENU); - scripter.verifyMenuIsDisplayed(MenuType.TBR_MENU); - scripter.pressCheckKey(); - scripter.waitForMenuUpdate(); - scripter.verifyMenuIsDisplayed(MenuType.TBR_SET); - } - - private void inputTbrPercentage(RuffyScripter scripter) { - scripter.verifyMenuIsDisplayed(MenuType.TBR_SET); - 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++) { - scripter.verifyMenuIsDisplayed(MenuType.TBR_SET); - if (increasePercentage) scripter.pressUpKey(); - else scripter.pressDownKey(); - SystemClock.sleep(400); - log.debug("Push #" + (i + 1)); - } - // Give the pump time to finish any scrolling that might still be going on, can take - // up to 1100ms. Plus some extra time to be sure - SystemClock.sleep(750); - } - - private void verifyDisplayedTbrPercentage(RuffyScripter scripter) { - scripter.verifyMenuIsDisplayed(MenuType.TBR_SET); - long displayedPercentage = readDisplayedTbrPercentage(scripter); - if (displayedPercentage != percentage) { - log.debug("Final displayed TBR percentage: " + displayedPercentage); - throw new CommandException().message("Failed to set TBR percentage"); - } - - // check again to ensure the displayed value hasn't change due to due scrolling taking extremely long - SystemClock.sleep(750); - long refreshedDisplayedTbrPecentage = readDisplayedTbrPercentage(scripter); - if (displayedPercentage != refreshedDisplayedTbrPecentage) { - throw new CommandException().message("Failed to set TBR percentage: " + - "percentage changed after input stopped from " - + displayedPercentage + " -> " + refreshedDisplayedTbrPecentage); - } - } - - private long readDisplayedTbrPercentage(RuffyScripter scripter) { - // TODO v2 add timeout? Currently the command execution timeout would trigger if exceeded - 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) { - scripter.verifyMenuIsDisplayed(MenuType.TBR_DURATION); - long currentDuration = readDisplayedTbrDuration(scripter); - while(currentDuration % 15 != 0) - { - // The duration displayed is how long an active TBR will still run, - // 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.verifyMenuIsDisplayed(MenuType.TBR_DURATION); - scripter.pressUpKey(); - SystemClock.sleep(300); - scripter.waitForMenuUpdate(); - currentDuration = readDisplayedTbrDuration(scripter); - } - SystemClock.sleep(300); - 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++) { - scripter.verifyMenuIsDisplayed(MenuType.TBR_DURATION); - if (increaseDuration) scripter.pressUpKey(); - else scripter.pressDownKey(); - SystemClock.sleep(400); - log.debug("Push #" + (i + 1)); - } - // Give the pump time to finish any scrolling that might still be going on, can take - // up to 1100ms. Plus some extra time to be sure - SystemClock.sleep(750); - } - - private void verifyDisplayedTbrDuration(RuffyScripter scripter) { - scripter.verifyMenuIsDisplayed(MenuType.TBR_DURATION); - long displayedDuration = readDisplayedTbrDuration(scripter); - if (displayedDuration != duration) { - log.debug("Final displayed TBR duration: " + displayedDuration); - throw new CommandException().message("Failed to set TBR duration"); - } - - // check again to ensure the displayed value hasn't change due to due scrolling taking extremely long - SystemClock.sleep(750); - long refreshedDisplayedTbrDuration = readDisplayedTbrDuration(scripter); - if (displayedDuration != refreshedDisplayedTbrDuration) { - throw new CommandException().message("Failed to set TBR duration: " + - "duration changed after input stopped from " - + displayedDuration + " -> " + refreshedDisplayedTbrDuration); - } - } - - private long readDisplayedTbrDuration(RuffyScripter scripter) { - // TODO v2 add timeout? Currently the command execution timeout would trigger if exceeded - scripter.verifyMenuIsDisplayed(MenuType.TBR_DURATION); - 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) { - // confirm entered TBR - scripter.verifyMenuIsDisplayed(MenuType.TBR_SET); - scripter.pressCheckKey(); - - // A "TBR CANCELLED alert" is only raised by the pump when the remaining time is - // greater than 60s (displayed as 0:01, the pump goes from there to finished. - // We could read the remaining duration from MAIN_MENU, but by the time we're here, - // the pumup could have moved from 0:02 to 0:01, so instead, check if a "TBR CANCELLED" alert - // is raised and if so dismiss it - long inFiveSeconds = System.currentTimeMillis() + 5 * 1000; - boolean alertProcessed = false; - while (System.currentTimeMillis() < inFiveSeconds && !alertProcessed) { - if (scripter.currentMenu.getType() == MenuType.WARNING_OR_ERROR) { - // Check the raised alarm is TBR CANCELLED, so we're not accidentally cancelling - // a different alarm that might be raised at the same time. - // Note that the message is permanently displayed, while the error code is blinking. - // A wait till the error code can be read results in the code hanging, despite - // menu updates coming in, so just check the message. - // TODO v2 this only works when the pump's language is English - 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: " - + errorMsg + ". Please check the pump."); - } - // confirm "TBR CANCELLED" alert - scripter.verifyMenuIsDisplayed(MenuType.WARNING_OR_ERROR); - scripter.pressCheckKey(); - // dismiss "TBR CANCELLED" alert - scripter.verifyMenuIsDisplayed(MenuType.WARNING_OR_ERROR); - scripter.pressCheckKey(); - scripter.waitForMenuToBeLeft(MenuType.WARNING_OR_ERROR); - alertProcessed = true; - } - SystemClock.sleep(20); - } - } - - private void verifyMainMenuShowsNoActiveTbr(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) { - throw new CommandException().message("Cancelling TBR failed, TBR is still set according to MAIN_MENU"); - } - } - - private void verifyMainMenuShowsExpectedTbrActive(RuffyScripter scripter) { - scripter.verifyMenuIsDisplayed(MenuType.MAIN_MENU); - // new TBR set; percentage and duration must be displayed ... - if (!scripter.currentMenu.attributes().contains(MenuAttribute.TBR) || - !scripter.currentMenu.attributes().contains(MenuAttribute.RUNTIME)) { - 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"); - } + return new CommandResult().success(false).message("failed with state: "+state+" from: "+lastState); } @Override From 14fdc14807e73f78487d1463118c99f780f40a56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sandra=20Ke=C3=9Fler?= Date: Mon, 31 Jul 2017 12:59:03 +0200 Subject: [PATCH 07/18] maybe better error recovery? --- .../androidaps/plugins/PumpCombo/ComboPlugin.java | 10 +++++++++- 1 file changed, 9 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 1ee0b085b5..90d8f14e92 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 @@ -158,6 +158,7 @@ public class ComboPlugin implements PluginBase, PumpInterface { lastAlarmTime = now; } else { log.warn("Pump still in error state, but alarm raised recently, so not triggering again: " + localLastCmdResult.message); + refreshDataFromPump("from Error Recovery"); } } SystemClock.sleep(5 * 1000); @@ -166,7 +167,13 @@ public class ComboPlugin implements PluginBase, PumpInterface { }, "combo-alerter").start(); } - private void bindRuffyService() { + private boolean bindRuffyService() { + + if(ruffyScripter != null) + { + log.debug("ruffy service already connected!"); + return false; + } Context context = MainApp.instance().getApplicationContext(); boolean boundSucceeded = false; @@ -207,6 +214,7 @@ public class ComboPlugin implements PluginBase, PumpInterface { if (!boundSucceeded) { statusSummary = "No connection to ruffy. Pump control not available."; } + return true; } private void unbindRuffyService() { From 791d905b141c06857ae0e210681335f84be30ce6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sandra=20Ke=C3=9Fler?= Date: Mon, 31 Jul 2017 13:08:10 +0200 Subject: [PATCH 08/18] exceptions --- .../de/jotomo/ruffyscripter/RuffyScripter.java | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java b/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java index df32847b59..c18e0d01d6 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java @@ -1,6 +1,5 @@ package de.jotomo.ruffyscripter; -import android.os.DeadObjectException; import android.os.RemoteException; import android.os.SystemClock; @@ -59,16 +58,17 @@ public class RuffyScripter { ruffyService.addHandler(mHandler); idleDisconnectMonitorThread.start(); started = true; - } catch (RemoteException e) { + } catch (Exception e) { throw new RuntimeException(e); } } public void stop() { if (started) { + started=false; try { ruffyService.removeHandler(mHandler); - } catch (RemoteException e) { + } catch (Exception e) { log.warn("Removing IRTHandler from Ruffy service failed, ignoring", e); } } @@ -97,14 +97,13 @@ public class RuffyScripter { // don't attempt anything fancy in the next 10s, let the pump settle SystemClock.sleep(10 * 1000); } - } catch (DeadObjectException doe) { + } catch (Exception e) { // TODO do we need to catch this exception somewhere else too? right now it's // converted into a command failure, but it's not classified as unrecoverable; // eventually we might try to recover ... check docs, there's also another // execption we should watch interacting with a remote service. // SecurityException was the other, when there's an AIDL mismatch; - unrecoverableError = "Ruffy service went away"; - } catch (RemoteException e) { + //unrecoverableError = "Ruffy service went away"; log.debug("Exception in idle disconnect monitor thread, carrying on", e); } SystemClock.sleep(1000); @@ -337,7 +336,7 @@ public class RuffyScripter { // before a connection is possible. In that case, it takes 45s before the // connection comes up. waitForMenuUpdate(180); - } catch (RemoteException e) { + } catch (Exception e) { throw new CommandException().exception(e).message("Unexpected exception while initiating/restoring pump connection"); } } @@ -406,7 +405,7 @@ public class RuffyScripter { ruffyService.rtSendKey(key, true); SystemClock.sleep(200); ruffyService.rtSendKey(Key.NO_KEY, true); - } catch (RemoteException e) { + } catch (Exception e) { throw new CommandException().exception(e).message("Error while pressing buttons"); } } From 4147e7f6a1fe980201411c1554867427950e0f0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sandra=20Ke=C3=9Fler?= Date: Mon, 31 Jul 2017 21:45:03 +0200 Subject: [PATCH 09/18] change Version info --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index f800902ecd..f313442ec3 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -44,7 +44,7 @@ android { minSdkVersion 21 targetSdkVersion 23 versionCode 1500 - version "1.5f" + version "1.5f-combo-sandratest" buildConfigField "String", "VERSION", '"' + version + '"' buildConfigField "String", "BUILDVERSION", generateGitBuild() } From 6981276cab7792345872e1bc6b149d293cabd559 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sandra=20Ke=C3=9Fler?= Date: Fri, 4 Aug 2017 11:53:51 +0200 Subject: [PATCH 10/18] - fix Multi connect - add key sent with 2500ms wait on keypress - fix Timing and npes in setTBR - make ruffyScripter not reinit every time - fix menu npe --- .../d/ruffy/ruffy/driver/IRTHandler.aidl | 9 ++- .../d/ruffy/ruffy/driver/IRuffyService.aidl | 4 +- .../jotomo/ruffyscripter/RuffyScripter.java | 71 +++++++++++++---- .../ruffyscripter/commands/SetTbrCommand.java | 77 +++---------------- .../plugins/PumpCombo/ComboPlugin.java | 22 ++++-- .../d/ruffy/ruffy/driver/display/Menu.java | 48 ++++++------ 6 files changed, 113 insertions(+), 118 deletions(-) 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 index 996b10b666..b6a07226b8 100644 --- 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 @@ -10,12 +10,17 @@ interface IRTHandler { void fail(String message); void requestBluetooth(); + boolean canDisconnect(); void rtStopped(); void rtStarted(); void rtClearDisplay(); void rtUpdateDisplay(in byte[] quarter, int which); - void rtDisplayHandleMenu(in Menu menu); - void rtDisplayHandleNoMenu(); + void rtDisplayHandleMenu(in Menu menu, in int sequence); + void rtDisplayHandleNoMenu(in int sequence); + + void keySent(in int sequence); + + String getServiceIdentifier(); } 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 index ded119c7b4..f4879445b7 100644 --- 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 @@ -13,10 +13,10 @@ interface IRuffyService { * * @return 0 if successful, -1 otherwise */ - int doRTConnect(); + int doRTConnect(IRTHandler handler); /** Disconnect from the pump */ - void doRTDisconnect(); + void doRTDisconnect(IRTHandler handler); /*What's the meaning of 'changed'? * changed means if a button state has been changed, like btton pressed is a change and button release another*/ diff --git a/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java b/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java index c18e0d01d6..730e775245 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java @@ -15,11 +15,13 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.List; +import java.util.Objects; import de.jotomo.ruffyscripter.commands.Command; import de.jotomo.ruffyscripter.commands.CommandException; import de.jotomo.ruffyscripter.commands.CommandResult; import de.jotomo.ruffyscripter.commands.ReadPumpStateCommand; +import de.jotomo.ruffyscripter.commands.SetTbrCommand; // 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 @@ -34,7 +36,7 @@ public class RuffyScripter { private static final Logger log = LoggerFactory.getLogger(RuffyScripter.class); - private final IRuffyService ruffyService; + private IRuffyService ruffyService; private final long connectionTimeOutMs = 5000; private String unrecoverableError = null; @@ -49,15 +51,18 @@ public class RuffyScripter { private boolean started = false; - public RuffyScripter(final IRuffyService ruffyService) { - this.ruffyService = ruffyService; + public RuffyScripter() { + } - public void start() { + public void start(IRuffyService newService) { try { - ruffyService.addHandler(mHandler); - idleDisconnectMonitorThread.start(); - started = true; + if(newService!=null) { + this.ruffyService = newService; + idleDisconnectMonitorThread.start(); + started = true; + try{newService.addHandler(mHandler);}catch (Exception e){} + } } catch (Exception e) { throw new RuntimeException(e); } @@ -66,11 +71,6 @@ public class RuffyScripter { public void stop() { if (started) { started=false; - try { - ruffyService.removeHandler(mHandler); - } catch (Exception e) { - log.warn("Removing IRTHandler from Ruffy service failed, ignoring", e); - } } } @@ -78,6 +78,7 @@ public class RuffyScripter { return started; } + private boolean canDisconnect = false; private Thread idleDisconnectMonitorThread = new Thread(new Runnable() { @Override public void run() { @@ -91,12 +92,17 @@ public class RuffyScripter { && now > lastDisconnect + 15 * 1000) { log.debug("Disconnecting after " + (connectionTimeOutMs / 1000) + "s inactivity timeout"); lastDisconnect = now; - ruffyService.doRTDisconnect(); + canDisconnect=true; + ruffyService.doRTDisconnect(mHandler); connected = false; lastDisconnect = System.currentTimeMillis(); // don't attempt anything fancy in the next 10s, let the pump settle SystemClock.sleep(10 * 1000); } + else + { + canDisconnect=false; + } } catch (Exception e) { // TODO do we need to catch this exception somewhere else too? right now it's // converted into a command failure, but it's not classified as unrecoverable; @@ -127,6 +133,11 @@ public class RuffyScripter { log.trace("Ruffy invoked requestBluetooth callback"); } + @Override + public boolean canDisconnect() throws RemoteException { + return canDisconnect; + } + @Override public void rtStopped() throws RemoteException { log.debug("rtStopped callback invoked"); @@ -149,7 +160,7 @@ public class RuffyScripter { } @Override - public void rtDisplayHandleMenu(Menu menu) throws RemoteException { + public void rtDisplayHandleMenu(Menu menu, int sequence) throws RemoteException { // method is called every ~500ms log.debug("rtDisplayHandleMenu: " + menu.getType()); @@ -166,16 +177,37 @@ public class RuffyScripter { } @Override - public void rtDisplayHandleNoMenu() throws RemoteException { + public void rtDisplayHandleNoMenu(int sequence) throws RemoteException { log.debug("rtDisplayHandleNoMenu callback invoked"); } + + @Override + public void keySent(int sequence) throws RemoteException { + synchronized (keylock) + { + keylock.notify(); + } + } + + @Override + public String getServiceIdentifier() throws RemoteException { + return this.toString(); + } + }; + private Object keylock = new Object(); public boolean isPumpBusy() { return activeCmd != null; } + public void unbind() { + if(ruffyService!=null) + try{ruffyService.removeHandler(mHandler);}catch (Exception e){} + this.ruffyService = null; + } + private static class Returnable { CommandResult cmdResult; } @@ -323,7 +355,8 @@ public class RuffyScripter { SystemClock.sleep(10 * 1000); } - boolean connectInitSuccessful = ruffyService.doRTConnect() == 0; + canDisconnect=false; + boolean connectInitSuccessful = ruffyService.doRTConnect(mHandler) == 0; log.debug("Connect init successful: " + connectInitSuccessful); log.debug("Waiting for first menu update to be sent"); // Note: there was an 'if(currentMenu == null)' around the next call, since @@ -403,8 +436,12 @@ public class RuffyScripter { private void pressKey(final byte key) { try { ruffyService.rtSendKey(key, true); - SystemClock.sleep(200); + //SystemClock.sleep(200); ruffyService.rtSendKey(Key.NO_KEY, true); + synchronized (keylock) + { + keylock.wait(2500); + } } catch (Exception e) { throw new CommandException().exception(e).message("Error while pressing buttons"); } 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 93adbbd8ba..f46718864a 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/commands/SetTbrCommand.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/commands/SetTbrCommand.java @@ -107,7 +107,7 @@ public class SetTbrCommand implements Command { switch (state) { case BEFORE: - if(scripter.currentMenu.getType()==MenuType.MAIN_MENU) + if(scripter.currentMenu!=null && scripter.currentMenu.getType()==MenuType.MAIN_MENU) { updateState(MAIN,120); lastMenu = MenuType.MAIN_MENU; @@ -115,7 +115,7 @@ public class SetTbrCommand implements Command { } break; case MAIN: - if(scripter.currentMenu.getType()==MenuType.TBR_MENU) + if(scripter.currentMenu!=null && scripter.currentMenu.getType()==MenuType.TBR_MENU) { updateState(TBR,30); scripter.pressCheckKey(); @@ -126,46 +126,31 @@ public class SetTbrCommand implements Command { e.printStackTrace(); } } - else if(scripter.currentMenu.getType()!=lastMenu) + else if(scripter.currentMenu!=null && scripter.currentMenu.getType()!=lastMenu) { lastMenu = scripter.currentMenu.getType(); updateState(MAIN,30); scripter.pressMenuKey(); log.debug("found Menu:"+lastMenu+" -> state:MAIN"); - try { - Thread.sleep(750); - } catch (InterruptedException e) { - e.printStackTrace(); - } } else { scripter.pressMenuKey(); - try { - Thread.sleep(750); - } catch (InterruptedException e) { - e.printStackTrace(); - } } break; case TBR: - if(scripter.currentMenu.getType()==MenuType.TBR_SET) + if(scripter.currentMenu!=null && scripter.currentMenu.getType()==MenuType.TBR_SET) { updateState(SET_TBR,60); } else { scripter.pressMenuKey(); - try { - Thread.sleep(750); - } catch (InterruptedException e) { - e.printStackTrace(); - } updateState(TBR,60); } break; case SET_TBR: - if(scripter.currentMenu.getType()==MenuType.TBR_SET) + if(scripter.currentMenu!=null && scripter.currentMenu.getType()==MenuType.TBR_SET) { Object percentageObj = scripter.currentMenu.getAttribute(MenuAttribute.BASAL_RATE); if(percentageObj != null && percentageObj instanceof Double) @@ -175,21 +160,11 @@ public class SetTbrCommand implements Command { { scripter.pressUpKey(); updateState(SET_TBR,30); - try { - Thread.sleep(750); - } catch (InterruptedException e) { - e.printStackTrace(); - } } else if(currentPercentage > percentage) { scripter.pressDownKey(); updateState(SET_TBR,30); - try { - Thread.sleep(750); - } catch (InterruptedException e) { - e.printStackTrace(); - } } else { @@ -205,15 +180,10 @@ public class SetTbrCommand implements Command { } } } - else if(scripter.currentMenu.getType()==MenuType.TBR_DURATION) + else if(scripter.currentMenu!=null && scripter.currentMenu.getType()==MenuType.TBR_DURATION) { scripter.pressMenuKey(); - updateState(TBR,60); - try { - Thread.sleep(750); - } catch (InterruptedException e) { - e.printStackTrace(); - } + updateState(SET_TBR,60); } else { @@ -221,7 +191,7 @@ public class SetTbrCommand implements Command { } break; case SET_TIME: - if(scripter.currentMenu.getType()==MenuType.TBR_DURATION) + if(scripter.currentMenu!=null && scripter.currentMenu.getType()==MenuType.TBR_DURATION) { Object durationObj = scripter.currentMenu.getAttribute(MenuAttribute.RUNTIME); if(durationObj != null && durationObj instanceof MenuTime) @@ -232,43 +202,23 @@ public class SetTbrCommand implements Command { { scripter.pressUpKey(); updateState(SET_TIME,30); - try { - Thread.sleep(750); - } catch (InterruptedException e) { - e.printStackTrace(); - } } else if(currentDuration > duration) { scripter.pressDownKey(); updateState(SET_TIME,30); - try { - Thread.sleep(750); - } catch (InterruptedException e) { - e.printStackTrace(); - } } else { scripter.pressCheckKey(); updateState(SET, 30); - try { - Thread.sleep(750); - } catch (InterruptedException e) { - e.printStackTrace(); - } } } } - else if(scripter.currentMenu.getType()==MenuType.TBR_SET) + else if(scripter.currentMenu!=null && scripter.currentMenu.getType()==MenuType.TBR_SET) { scripter.pressMenuKey(); updateState(SET_TIME,60); - try { - Thread.sleep(750); - } catch (InterruptedException e) { - e.printStackTrace(); - } } else { @@ -276,18 +226,13 @@ public class SetTbrCommand implements Command { } break; case SET: - if(scripter.currentMenu.getType()==MenuType.WARNING_OR_ERROR) + if(scripter.currentMenu!=null && scripter.currentMenu.getType()==MenuType.WARNING_OR_ERROR) { lastMenu = scripter.currentMenu.getType(); scripter.pressCheckKey(); updateState(SET, 30); - try { - Thread.sleep(750); - } catch (InterruptedException e) { - e.printStackTrace(); - } } - else if(scripter.currentMenu.getType()==MenuType.MAIN_MENU) { + else if(scripter.currentMenu!=null && scripter.currentMenu.getType()==MenuType.MAIN_MENU) { Object setPercentage = scripter.currentMenu.getAttribute(MenuAttribute.TBR); Object setDuration = scripter.currentMenu.getAttribute(MenuAttribute.RUNTIME); if (setPercentage== null ||setDuration==null) { 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 90d8f14e92..d754cc8785 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 @@ -85,6 +85,7 @@ public class ComboPlugin implements PluginBase, PumpInterface { MainApp.bus().register(this); bindRuffyService(); startAlerter(); + ruffyScripter = new RuffyScripter(); } private void definePumpCapabilities() { @@ -169,11 +170,6 @@ public class ComboPlugin implements PluginBase, PumpInterface { private boolean bindRuffyService() { - if(ruffyScripter != null) - { - log.debug("ruffy service already connected!"); - return false; - } Context context = MainApp.instance().getApplicationContext(); boolean boundSucceeded = false; @@ -186,6 +182,7 @@ public class ComboPlugin implements PluginBase, PumpInterface { // 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 is the base package identifier and /.driver.Ruffy the service within the package "org.monkey.d.ruffy.ruffy.driver.Ruffy" )); context.startService(intent); @@ -194,16 +191,22 @@ public class ComboPlugin implements PluginBase, PumpInterface { @Override public void onServiceConnected(ComponentName name, IBinder service) { - ruffyScripter = new RuffyScripter(IRuffyService.Stub.asInterface(service)); - ruffyScripter.start(); + keepUnbound=false; + ruffyScripter.start(IRuffyService.Stub.asInterface(service)); log.debug("ruffy serivce connected"); } @Override public void onServiceDisconnected(ComponentName name) { ruffyScripter.stop(); - ruffyScripter = null; log.debug("ruffy service disconnected"); + if(!keepUnbound) { + try { + Thread.sleep(250); + } catch (Exception e) { + } + bindRuffyService(); + } } }; boundSucceeded = context.bindService(intent, mRuffyServiceConnection, Context.BIND_AUTO_CREATE); @@ -217,7 +220,10 @@ public class ComboPlugin implements PluginBase, PumpInterface { return true; } + private boolean keepUnbound = false; private void unbindRuffyService() { + keepUnbound = true; + ruffyScripter.unbind(); MainApp.instance().getApplicationContext().unbindService(mRuffyServiceConnection); } 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 index 20e74c7805..87ca44adfc 100644 --- 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 @@ -35,30 +35,32 @@ public class Menu implements Parcelable{ 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(attr!=null && clas!=null && value!=null) { + 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); + if (o != null) { + attributes.put(a, o); + } else { + Log.e("MenuIn", "failed to parse: " + attr + " / " + clas + " / " + value); + } } }catch(Exception e) { From 763cc2393950f926656f3956eb53e34100242cbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sandra=20Ke=C3=9Fler?= Date: Fri, 4 Aug 2017 16:34:25 +0200 Subject: [PATCH 11/18] add type of menu to MenuType (main or sub menu) --- .../ruffy/ruffy/driver/display/MenuType.java | 77 +++++++++++-------- 1 file changed, 43 insertions(+), 34 deletions(-) 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 index 4d00ea9155..2fb7a53f67 100644 --- 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 @@ -5,38 +5,47 @@ package org.monkey.d.ruffy.ruffy.driver.display; */ 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, + MAIN_MENU(true), + STOP_MENU(true), + BOLUS_MENU(true), + BOLUS_ENTER(false), + EXTENDED_BOLUS_MENU(true), + BOLUS_DURATION(false), + MULTIWAVE_BOLUS_MENU(true), + IMMEDIATE_BOLUS(false), + TBR_MENU(true), + MY_DATA_MENU(true), + BASAL_MENU(true), + BASAL_1_MENU(true), + BASAL_2_MENU(true), + BASAL_3_MENU(true), + BASAL_4_MENU(true), + BASAL_5_MENU(true), + DATE_AND_TIME_MENU(true), + ALARM_MENU(true), + MENU_SETTINGS_MENU(true), + BLUETOOTH_MENU(true), + THERAPY_MENU(true), + PUMP_MENU(true), + QUICK_INFO(false), + BOLUS_DATA(false), + DAILY_DATA(false), + TBR_DATA(false), + ERROR_DATA(false), + TBR_SET(false), + TBR_DURATION(false), + STOP(false), + START_MENU(false), + BASAL_TOTAL(false), + BASAL_SET(false), + WARNING_OR_ERROR(false),; + + private boolean maintype = false; + MenuType(boolean b) { + maintype=b; + } + + public boolean isMaintype() { + return maintype; + } } From efb73ba4f25951faa70c1523edf5f5563935797d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sandra=20Ke=C3=9Fler?= Date: Fri, 4 Aug 2017 16:36:12 +0200 Subject: [PATCH 12/18] make keypress wait up to 2000ms for key response --- .../jotomo/ruffyscripter/RuffyScripter.java | 52 +++++++++++++------ 1 file changed, 37 insertions(+), 15 deletions(-) diff --git a/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java b/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java index 730e775245..4514df9fbf 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java @@ -51,6 +51,11 @@ public class RuffyScripter { private boolean started = false; + private Object keylock = new Object(); + private int keynotwait = 0; + + private Object screenlock = new Object(); + public RuffyScripter() { } @@ -167,6 +172,11 @@ public class RuffyScripter { currentMenu = menu; menuLastUpdated = System.currentTimeMillis(); + synchronized (screenlock) + { + screenlock.notifyAll(); + } + connected = true; // note that a WARNING_OR_ERROR menu can be a valid temporary state (cancelling TBR) @@ -186,7 +196,10 @@ public class RuffyScripter { public void keySent(int sequence) throws RemoteException { synchronized (keylock) { - keylock.notify(); + if(keynotwait>0) + keynotwait--; + else + keylock.notify(); } } @@ -197,7 +210,6 @@ public class RuffyScripter { }; - private Object keylock = new Object(); public boolean isPumpBusy() { return activeCmd != null; } @@ -379,35 +391,35 @@ public class RuffyScripter { // so this class can focus on providing a connection to run commands // (or maybe reconsider putting it into a base class) - 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 static class Key { + public static byte NO_KEY = (byte) 0x00; + public static byte MENU = (byte) 0x03; + public static byte CHECK = (byte) 0x0C; + public static byte UP = (byte) 0x30; + public static byte DOWN = (byte) 0xC0; } public void pressUpKey() { log.debug("Pressing up key"); - pressKey(Key.UP); + pressKey(Key.UP,2000); log.debug("Releasing up key"); } public void pressDownKey() { log.debug("Pressing down key"); - pressKey(Key.DOWN); + pressKey(Key.DOWN,2000); log.debug("Releasing down key"); } public void pressCheckKey() { log.debug("Pressing check key"); - pressKey(Key.CHECK); + pressKey(Key.CHECK,2000); log.debug("Releasing check key"); } public void pressMenuKey() { log.debug("Pressing menu key"); - pressKey(Key.MENU); + pressKey(Key.MENU,2000); log.debug("Releasing menu key"); } @@ -433,14 +445,24 @@ public class RuffyScripter { } } - private void pressKey(final byte key) { + private void pressKey(final byte key, long timeout) { try { ruffyService.rtSendKey(key, true); //SystemClock.sleep(200); ruffyService.rtSendKey(Key.NO_KEY, true); - synchronized (keylock) + if(timeout > 0) { - keylock.wait(2500); + synchronized (keylock) + { + keylock.wait(timeout); + } + } + else + { + synchronized (keylock) + { + keynotwait++; + } } } catch (Exception e) { throw new CommandException().exception(e).message("Error while pressing buttons"); From d8ca2771fb528b6570c96d8e6bc24d94cc5006ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sandra=20Ke=C3=9Fler?= Date: Fri, 4 Aug 2017 16:36:25 +0200 Subject: [PATCH 13/18] add back key --- .../main/java/de/jotomo/ruffyscripter/RuffyScripter.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java b/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java index 4514df9fbf..f9d30b5205 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java @@ -397,6 +397,7 @@ public class RuffyScripter { public static byte CHECK = (byte) 0x0C; public static byte UP = (byte) 0x30; public static byte DOWN = (byte) 0xC0; + public static byte BACK = (byte) 0x33; } public void pressUpKey() { @@ -423,6 +424,11 @@ public class RuffyScripter { log.debug("Releasing menu key"); } + public void pressBackKey() { + log.debug("Pressing back key"); + pressKey(Key.BACK,2000); + log.debug("Releasing back key"); + } // TODO v2, rework these two methods: waitForMenuUpdate shoud only be used by commands // then anything longer than a few seconds is an error; // only ensureConnected() uses the method with the timeout parameter; inline that code, From d35283ad74515a2facf49172f74706bb146146c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sandra=20Ke=C3=9Fler?= Date: Fri, 4 Aug 2017 16:38:25 +0200 Subject: [PATCH 14/18] add waitScreen (wait for refresh with timeout), gotToMainMenuScreen (with the help of back and menu navigate to a given main menu), enterMenu (to navigate withhin submenus), and step (send a key repeated) --- .../jotomo/ruffyscripter/RuffyScripter.java | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java b/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java index f9d30b5205..7ae3529ef3 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java @@ -429,6 +429,57 @@ public class RuffyScripter { pressKey(Key.BACK,2000); log.debug("Releasing back key"); } + + private boolean waitScreen(long timeout) + { + synchronized (screenlock) { + try { + screenlock.wait(timeout); + } catch (Exception e) { + return false; + } + } + return true; + } + + public boolean goToMainMenuScreen(MenuType screen, long timeout) + { + long start = System.currentTimeMillis(); + while((currentMenu == null || currentMenu.getType()!=screen) && start+timeout>System.currentTimeMillis()) + { + if(currentMenu!=null && currentMenu.getType()==MenuType.WARNING_OR_ERROR) + { + //FIXME bad thing to do :D + pressCheckKey(); + } + else if(currentMenu!=null && !currentMenu.getType().isMaintype()) + { + pressBackKey(); + } + else + pressMenuKey(); + waitScreen(250); + } + return currentMenu != null && currentMenu.getType()==screen; + } + + public boolean enterMenu(MenuType startType, MenuType targetType, byte key, long timeout) + { + if(currentMenu==null || currentMenu.getType() != startType) + return false; + long start = System.currentTimeMillis(); + pressKey(key,2000); + while((currentMenu == null || currentMenu.getType()!=targetType) && start+timeout>System.currentTimeMillis()) { + waitScreen(100); + } + return currentMenu!=null && currentMenu.getType()==targetType; + } + + public void step(int steps, byte key, long timeout) { + for(int i = 0; i < Math.abs(steps);i++) + pressKey(key,timeout); + } + // TODO v2, rework these two methods: waitForMenuUpdate shoud only be used by commands // then anything longer than a few seconds is an error; // only ensureConnected() uses the method with the timeout parameter; inline that code, From ac3859dcae7bfc0685d8a400759d53a2aed7cd08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sandra=20Ke=C3=9Fler?= Date: Fri, 4 Aug 2017 16:39:03 +0200 Subject: [PATCH 15/18] update setTBRCommand to way faster methods in scripter --- .../ruffyscripter/commands/SetTbrCommand.java | 106 +++++++++--------- 1 file changed, 50 insertions(+), 56 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 f46718864a..8f02a40132 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/commands/SetTbrCommand.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/commands/SetTbrCommand.java @@ -21,6 +21,7 @@ import static de.jotomo.ruffyscripter.commands.SetTbrCommand.State.SET; import static de.jotomo.ruffyscripter.commands.SetTbrCommand.State.SET_TBR; import static de.jotomo.ruffyscripter.commands.SetTbrCommand.State.SET_TIME; import static de.jotomo.ruffyscripter.commands.SetTbrCommand.State.TBR; +import static de.jotomo.ruffyscripter.commands.SetTbrCommand.State.TIME; public class SetTbrCommand implements Command { private static final Logger log = LoggerFactory.getLogger(SetTbrCommand.class); @@ -66,6 +67,7 @@ public class SetTbrCommand implements Command { MAIN, TBR, SET_TBR, + TIME, SET_TIME, SET, AFTER, @@ -102,6 +104,7 @@ public class SetTbrCommand implements Command { timeout = timeoutSec*1000; } private MenuType lastMenu; + private int retries = 0; private void tick() { switch (state) @@ -112,42 +115,29 @@ public class SetTbrCommand implements Command { updateState(MAIN,120); lastMenu = MenuType.MAIN_MENU; log.debug("found MAIN_MENU -> state:MAIN"); + retries=3; } break; case MAIN: - if(scripter.currentMenu!=null && scripter.currentMenu.getType()==MenuType.TBR_MENU) - { - updateState(TBR,30); - scripter.pressCheckKey(); - log.debug("found TBR_MENU -> state:TBR"); - try { - Thread.sleep(750); - } catch (InterruptedException e) { - e.printStackTrace(); + if(retries>0) + if(scripter.goToMainMenuScreen(MenuType.TBR_MENU,30000)) + { + updateState(TBR,30); + retries=0; } - } - else if(scripter.currentMenu!=null && scripter.currentMenu.getType()!=lastMenu) - { - lastMenu = scripter.currentMenu.getType(); - updateState(MAIN,30); - scripter.pressMenuKey(); - log.debug("found Menu:"+lastMenu+" -> state:MAIN"); - } + else + retries--; else - { - scripter.pressMenuKey(); - } + updateState(ERROR,30); break; case TBR: - if(scripter.currentMenu!=null && scripter.currentMenu.getType()==MenuType.TBR_SET) + if(scripter.enterMenu(MenuType.TBR_MENU,MenuType.TBR_SET, RuffyScripter.Key.CHECK,20000)) { updateState(SET_TBR,60); + retries = 10; } else - { - scripter.pressMenuKey(); - updateState(TBR,60); - } + updateState(ERROR,30); break; case SET_TBR: if(scripter.currentMenu!=null && scripter.currentMenu.getType()==MenuType.TBR_SET) @@ -156,40 +146,46 @@ public class SetTbrCommand implements Command { if(percentageObj != null && percentageObj instanceof Double) { double currentPercentage = ((Double) percentageObj).doubleValue(); - if(currentPercentage < percentage) + + if(currentPercentage!=percentage) { - scripter.pressUpKey(); - updateState(SET_TBR,30); - } - else if(currentPercentage > percentage) - { - scripter.pressDownKey(); - updateState(SET_TBR,30); + if(retries>0) { + retries--; + int steps = (int) ((percentage - currentPercentage) / 10.0); + scripter.step(steps,(steps<0? RuffyScripter.Key.DOWN: RuffyScripter.Key.UP), 3000); + } + else + updateState(ERROR,30); } else { if(percentage==100) { scripter.pressCheckKey(); - updateState(SET, 30); + updateState(SET,30); } else { - scripter.pressMenuKey(); - updateState(SET_TIME, 30); + updateState(TIME, 30); } + retries=10; } } } - else if(scripter.currentMenu!=null && scripter.currentMenu.getType()==MenuType.TBR_DURATION) - { - scripter.pressMenuKey(); - updateState(SET_TBR,60); - } else { updateState(ERROR,30); } break; + case TIME: + if((scripter.currentMenu!=null && scripter.currentMenu.getType()==MenuType.TBR_DURATION) || scripter.enterMenu(MenuType.TBR_SET,MenuType.TBR_DURATION, RuffyScripter.Key.MENU,20000)) + { + updateState(SET_TIME,60); + retries = 10; + } + else if(retries==0) + updateState(ERROR,30); + else retries--; + break; case SET_TIME: if(scripter.currentMenu!=null && scripter.currentMenu.getType()==MenuType.TBR_DURATION) { @@ -198,28 +194,26 @@ public class SetTbrCommand implements Command { { MenuTime time = (MenuTime) durationObj; double currentDuration = (time.getHour()*60)+time.getMinute(); - if(currentDuration < duration) + if(currentDuration!=duration) { - scripter.pressUpKey(); - updateState(SET_TIME,30); + if(retries>0) { + retries--; + int steps = (int)((currentDuration - duration)/15.0); + if(currentDuration+(steps*15)duration) + steps--; + scripter.step(steps,(steps>0? RuffyScripter.Key.UP: RuffyScripter.Key.DOWN), 3000); + } + else + updateState(ERROR,30); } - else if(currentDuration > duration) - { - scripter.pressDownKey(); - updateState(SET_TIME,30); - } - else - { + else { scripter.pressCheckKey(); updateState(SET, 30); } } } - else if(scripter.currentMenu!=null && scripter.currentMenu.getType()==MenuType.TBR_SET) - { - scripter.pressMenuKey(); - updateState(SET_TIME,60); - } else { updateState(ERROR,60); From f790ce6f20c36366d297f92573f459388ba71056 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sandra=20Ke=C3=9Fler?= Date: Fri, 4 Aug 2017 17:57:34 +0200 Subject: [PATCH 16/18] add unused (but tested) command to get basal rate from Profile 1 --- .../jotomo/ruffyscripter/RuffyScripter.java | 2 +- .../commands/GetBasalCommand.java | 301 ++++++++++++++++++ 2 files changed, 302 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/de/jotomo/ruffyscripter/commands/GetBasalCommand.java diff --git a/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java b/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java index 7ae3529ef3..9fabaac5ab 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/RuffyScripter.java @@ -430,7 +430,7 @@ public class RuffyScripter { log.debug("Releasing back key"); } - private boolean waitScreen(long timeout) + public boolean waitScreen(long timeout) { synchronized (screenlock) { try { diff --git a/app/src/main/java/de/jotomo/ruffyscripter/commands/GetBasalCommand.java b/app/src/main/java/de/jotomo/ruffyscripter/commands/GetBasalCommand.java new file mode 100644 index 0000000000..8f02a40132 --- /dev/null +++ b/app/src/main/java/de/jotomo/ruffyscripter/commands/GetBasalCommand.java @@ -0,0 +1,301 @@ +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.monkey.d.ruffy.ruffy.driver.display.menu.MenuTime; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +import de.jotomo.ruffyscripter.PumpState; +import de.jotomo.ruffyscripter.RuffyScripter; + +import static de.jotomo.ruffyscripter.commands.SetTbrCommand.State.AFTER; +import static de.jotomo.ruffyscripter.commands.SetTbrCommand.State.BEFORE; +import static de.jotomo.ruffyscripter.commands.SetTbrCommand.State.ERROR; +import static de.jotomo.ruffyscripter.commands.SetTbrCommand.State.MAIN; +import static de.jotomo.ruffyscripter.commands.SetTbrCommand.State.SET; +import static de.jotomo.ruffyscripter.commands.SetTbrCommand.State.SET_TBR; +import static de.jotomo.ruffyscripter.commands.SetTbrCommand.State.SET_TIME; +import static de.jotomo.ruffyscripter.commands.SetTbrCommand.State.TBR; +import static de.jotomo.ruffyscripter.commands.SetTbrCommand.State.TIME; + +public class SetTbrCommand implements Command { + private static final Logger log = LoggerFactory.getLogger(SetTbrCommand.class); + + private final long percentage; + private final long duration; + private RuffyScripter scripter; + + public SetTbrCommand(long percentage, long duration) { + this.percentage = percentage; + this.duration = duration; + } + + @Override + public List validateArguments() { + List violations = new ArrayList<>(); + + if (percentage % 10 != 0) { + violations.add("TBR percentage must be set in 10% steps"); + } + if (percentage < 0 || percentage > 500) { + violations.add("TBR percentage must be within 0-500%"); + } + + if (percentage != 100) { + if (duration % 15 != 0) { + violations.add("TBR duration can only be set in 15 minute steps"); + } + if (duration > 60 * 24) { + violations.add("Maximum TBR duration is 24 hours"); + } + } + + if (percentage == 0 && duration > 120) { + violations.add("Max allowed zero-temp duration is 2h"); + } + + return violations; + } + + enum State { + BEFORE, + MAIN, + TBR, + SET_TBR, + TIME, + SET_TIME, + SET, + AFTER, + ERROR + }; + private State lastState,state; + private long last; + private long timeout; + private Thread timeoutThread = new Thread() + { + @Override + public void run() { + while(state != ERROR && state!=AFTER) { + if (timeout + last < System.currentTimeMillis()) { + lastState = state; + state = ERROR; + log.debug("timeout reached -> state:ERROR"); + } + tick(); + try { + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + tick(); + } + }; + private void updateState(State newState,long timeoutSec) + { + lastState = state; + state = newState; + last = System.currentTimeMillis(); + timeout = timeoutSec*1000; + } + private MenuType lastMenu; + private int retries = 0; + private void tick() + { + switch (state) + { + case BEFORE: + if(scripter.currentMenu!=null && scripter.currentMenu.getType()==MenuType.MAIN_MENU) + { + updateState(MAIN,120); + lastMenu = MenuType.MAIN_MENU; + log.debug("found MAIN_MENU -> state:MAIN"); + retries=3; + } + break; + case MAIN: + if(retries>0) + if(scripter.goToMainMenuScreen(MenuType.TBR_MENU,30000)) + { + updateState(TBR,30); + retries=0; + } + else + retries--; + else + updateState(ERROR,30); + break; + case TBR: + if(scripter.enterMenu(MenuType.TBR_MENU,MenuType.TBR_SET, RuffyScripter.Key.CHECK,20000)) + { + updateState(SET_TBR,60); + retries = 10; + } + else + updateState(ERROR,30); + break; + case SET_TBR: + if(scripter.currentMenu!=null && scripter.currentMenu.getType()==MenuType.TBR_SET) + { + Object percentageObj = scripter.currentMenu.getAttribute(MenuAttribute.BASAL_RATE); + if(percentageObj != null && percentageObj instanceof Double) + { + double currentPercentage = ((Double) percentageObj).doubleValue(); + + if(currentPercentage!=percentage) + { + if(retries>0) { + retries--; + int steps = (int) ((percentage - currentPercentage) / 10.0); + scripter.step(steps,(steps<0? RuffyScripter.Key.DOWN: RuffyScripter.Key.UP), 3000); + } + else + updateState(ERROR,30); + } + else + { + if(percentage==100) + { + scripter.pressCheckKey(); + updateState(SET,30); + } + else { + updateState(TIME, 30); + } + retries=10; + } + } + } + else + { + updateState(ERROR,30); + } + break; + case TIME: + if((scripter.currentMenu!=null && scripter.currentMenu.getType()==MenuType.TBR_DURATION) || scripter.enterMenu(MenuType.TBR_SET,MenuType.TBR_DURATION, RuffyScripter.Key.MENU,20000)) + { + updateState(SET_TIME,60); + retries = 10; + } + else if(retries==0) + updateState(ERROR,30); + else retries--; + break; + case SET_TIME: + if(scripter.currentMenu!=null && scripter.currentMenu.getType()==MenuType.TBR_DURATION) + { + Object durationObj = scripter.currentMenu.getAttribute(MenuAttribute.RUNTIME); + if(durationObj != null && durationObj instanceof MenuTime) + { + MenuTime time = (MenuTime) durationObj; + double currentDuration = (time.getHour()*60)+time.getMinute(); + if(currentDuration!=duration) + { + if(retries>0) { + retries--; + int steps = (int)((currentDuration - duration)/15.0); + if(currentDuration+(steps*15)duration) + steps--; + scripter.step(steps,(steps>0? RuffyScripter.Key.UP: RuffyScripter.Key.DOWN), 3000); + } + else + updateState(ERROR,30); + } + else { + scripter.pressCheckKey(); + updateState(SET, 30); + } + } + } + else + { + updateState(ERROR,60); + } + break; + case SET: + if(scripter.currentMenu!=null && scripter.currentMenu.getType()==MenuType.WARNING_OR_ERROR) + { + lastMenu = scripter.currentMenu.getType(); + scripter.pressCheckKey(); + updateState(SET, 30); + } + else if(scripter.currentMenu!=null && scripter.currentMenu.getType()==MenuType.MAIN_MENU) { + Object setPercentage = scripter.currentMenu.getAttribute(MenuAttribute.TBR); + Object setDuration = scripter.currentMenu.getAttribute(MenuAttribute.RUNTIME); + if (setPercentage== null ||setDuration==null) { + if(percentage!=100) + { + updateState(ERROR,10); + } + else + { + if(lastMenu==MenuType.WARNING_OR_ERROR) + updateState(AFTER,10); + else + updateState(SET,10); + } + } + else { + double mmTbrPercentage = (Double) setPercentage; + MenuTime mmTbrDuration = (MenuTime) setDuration; + // ... 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) { + updateState(AFTER, 10); + } else { + updateState(ERROR, 10); + } + } + } + break; + case ERROR: + case AFTER: + synchronized(SetTbrCommand.this) { + SetTbrCommand.this.notify(); + } + break; + } + } + @Override + public CommandResult execute(RuffyScripter scripter, PumpState initialPumpState) { + state = BEFORE; + this.scripter = scripter; + updateState(BEFORE,120); + timeoutThread.start(); + + try { + synchronized (this) { + this.wait(); + } + } catch (InterruptedException e) { + e.printStackTrace(); + return new CommandResult().success(false).message("failed to wait: "+e.getMessage()); + } + if(state==AFTER) + { + if(percentage==100) + return new CommandResult().success(true).enacted(true).message("TBR was cancelled"); + + return new CommandResult().success(true).enacted(true).message( + String.format(Locale.US, "TBR set to %d%% for %d min", percentage, duration)); + } + return new CommandResult().success(false).message("failed with state: "+state+" from: "+lastState); + } + + @Override + public String toString() { + return "SetTbrCommand{" + + "percentage=" + percentage + + ", duration=" + duration + + '}'; + } +} From 37a3270a16f1252a41510412d7c24da7c3a91894 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sandra=20Ke=C3=9Fler?= Date: Fri, 4 Aug 2017 17:58:28 +0200 Subject: [PATCH 17/18] missing stuf :/ --- .../commands/GetBasalCommand.java | 234 +++++------------- 1 file changed, 62 insertions(+), 172 deletions(-) diff --git a/app/src/main/java/de/jotomo/ruffyscripter/commands/GetBasalCommand.java b/app/src/main/java/de/jotomo/ruffyscripter/commands/GetBasalCommand.java index 8f02a40132..ea78d0e536 100644 --- a/app/src/main/java/de/jotomo/ruffyscripter/commands/GetBasalCommand.java +++ b/app/src/main/java/de/jotomo/ruffyscripter/commands/GetBasalCommand.java @@ -1,5 +1,7 @@ package de.jotomo.ruffyscripter.commands; +import android.util.Log; + 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; @@ -7,71 +9,45 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Locale; +import java.util.Map; +import java.util.Objects; import de.jotomo.ruffyscripter.PumpState; import de.jotomo.ruffyscripter.RuffyScripter; -import static de.jotomo.ruffyscripter.commands.SetTbrCommand.State.AFTER; -import static de.jotomo.ruffyscripter.commands.SetTbrCommand.State.BEFORE; -import static de.jotomo.ruffyscripter.commands.SetTbrCommand.State.ERROR; -import static de.jotomo.ruffyscripter.commands.SetTbrCommand.State.MAIN; -import static de.jotomo.ruffyscripter.commands.SetTbrCommand.State.SET; -import static de.jotomo.ruffyscripter.commands.SetTbrCommand.State.SET_TBR; -import static de.jotomo.ruffyscripter.commands.SetTbrCommand.State.SET_TIME; -import static de.jotomo.ruffyscripter.commands.SetTbrCommand.State.TBR; -import static de.jotomo.ruffyscripter.commands.SetTbrCommand.State.TIME; +import static de.jotomo.ruffyscripter.commands.GetBasalCommand.State.BEFORE; +import static de.jotomo.ruffyscripter.commands.GetBasalCommand.State.MAIN; +import static de.jotomo.ruffyscripter.commands.GetBasalCommand.State.BASAL_1_MENU; +import static de.jotomo.ruffyscripter.commands.GetBasalCommand.State.BASAL_OVERVIEW; +import static de.jotomo.ruffyscripter.commands.GetBasalCommand.State.READ_BASAL; +import static de.jotomo.ruffyscripter.commands.GetBasalCommand.State.ERROR; +import static de.jotomo.ruffyscripter.commands.GetBasalCommand.State.AFTER; -public class SetTbrCommand implements Command { - private static final Logger log = LoggerFactory.getLogger(SetTbrCommand.class); +public class GetBasalCommand implements Command { + private static final Logger log = LoggerFactory.getLogger(GetBasalCommand.class); - private final long percentage; - private final long duration; private RuffyScripter scripter; - public SetTbrCommand(long percentage, long duration) { - this.percentage = percentage; - this.duration = duration; - } + public GetBasalCommand() {} @Override public List validateArguments() { List violations = new ArrayList<>(); - if (percentage % 10 != 0) { - violations.add("TBR percentage must be set in 10% steps"); - } - if (percentage < 0 || percentage > 500) { - violations.add("TBR percentage must be within 0-500%"); - } - - if (percentage != 100) { - if (duration % 15 != 0) { - violations.add("TBR duration can only be set in 15 minute steps"); - } - if (duration > 60 * 24) { - violations.add("Maximum TBR duration is 24 hours"); - } - } - - if (percentage == 0 && duration > 120) { - violations.add("Max allowed zero-temp duration is 2h"); - } - return violations; } enum State { BEFORE, MAIN, - TBR, - SET_TBR, - TIME, - SET_TIME, - SET, + BASAL_1_MENU, + BASAL_OVERVIEW, + READ_BASAL, + ERROR, AFTER, - ERROR }; private State lastState,state; private long last; @@ -105,6 +81,9 @@ public class SetTbrCommand implements Command { } private MenuType lastMenu; private int retries = 0; + private double basalTotal = 0; + private Map rate = new HashMap<>(); + private void tick() { switch (state) @@ -120,147 +99,61 @@ public class SetTbrCommand implements Command { break; case MAIN: if(retries>0) - if(scripter.goToMainMenuScreen(MenuType.TBR_MENU,30000)) + if(scripter.goToMainMenuScreen(MenuType.BASAL_1_MENU,30000)) { - updateState(TBR,30); - retries=0; + if(scripter.enterMenu(MenuType.BASAL_1_MENU,MenuType.BASAL_TOTAL, RuffyScripter.Key.CHECK,2000)); + { + updateState(BASAL_OVERVIEW, 30); + retries=0; + } } else retries--; else updateState(ERROR,30); break; - case TBR: - if(scripter.enterMenu(MenuType.TBR_MENU,MenuType.TBR_SET, RuffyScripter.Key.CHECK,20000)) + case BASAL_OVERVIEW: + if(scripter.currentMenu.getType()==MenuType.BASAL_TOTAL && scripter.currentMenu.getAttribute(MenuAttribute.BASAL_TOTAL)!=null && (Integer)scripter.currentMenu.getAttribute(MenuAttribute.BASAL_SELECTED)==1) { - updateState(SET_TBR,60); - retries = 10; - } - else - updateState(ERROR,30); - break; - case SET_TBR: - if(scripter.currentMenu!=null && scripter.currentMenu.getType()==MenuType.TBR_SET) - { - Object percentageObj = scripter.currentMenu.getAttribute(MenuAttribute.BASAL_RATE); - if(percentageObj != null && percentageObj instanceof Double) + basalTotal = (Double)scripter.currentMenu.getAttribute(MenuAttribute.BASAL_TOTAL); + if(scripter.enterMenu(MenuType.BASAL_TOTAL,MenuType.BASAL_SET, RuffyScripter.Key.MENU,3000)) { - double currentPercentage = ((Double) percentageObj).doubleValue(); - - if(currentPercentage!=percentage) - { - if(retries>0) { - retries--; - int steps = (int) ((percentage - currentPercentage) / 10.0); - scripter.step(steps,(steps<0? RuffyScripter.Key.DOWN: RuffyScripter.Key.UP), 3000); - } - else - updateState(ERROR,30); - } - else - { - if(percentage==100) - { - scripter.pressCheckKey(); - updateState(SET,30); - } - else { - updateState(TIME, 30); - } - retries=10; - } + updateState(READ_BASAL,30); + retries = 96; } } - else - { - updateState(ERROR,30); - } break; - case TIME: - if((scripter.currentMenu!=null && scripter.currentMenu.getType()==MenuType.TBR_DURATION) || scripter.enterMenu(MenuType.TBR_SET,MenuType.TBR_DURATION, RuffyScripter.Key.MENU,20000)) - { - updateState(SET_TIME,60); - retries = 10; - } - else if(retries==0) - updateState(ERROR,30); - else retries--; - break; - case SET_TIME: - if(scripter.currentMenu!=null && scripter.currentMenu.getType()==MenuType.TBR_DURATION) - { - Object durationObj = scripter.currentMenu.getAttribute(MenuAttribute.RUNTIME); - if(durationObj != null && durationObj instanceof MenuTime) - { - MenuTime time = (MenuTime) durationObj; - double currentDuration = (time.getHour()*60)+time.getMinute(); - if(currentDuration!=duration) - { - if(retries>0) { - retries--; - int steps = (int)((currentDuration - duration)/15.0); - if(currentDuration+(steps*15)duration) - steps--; - scripter.step(steps,(steps>0? RuffyScripter.Key.UP: RuffyScripter.Key.DOWN), 3000); - } - else - updateState(ERROR,30); - } - else { - scripter.pressCheckKey(); - updateState(SET, 30); - } + case READ_BASAL: + if(scripter.currentMenu.getType()==MenuType.BASAL_SET && scripter.currentMenu.getAttribute(MenuAttribute.BASAL_START)!=null) { + Object rateObj = scripter.currentMenu.getAttribute(MenuAttribute.BASAL_RATE); + MenuTime time = (MenuTime) scripter.currentMenu.getAttribute(MenuAttribute.BASAL_START); + if (rateObj instanceof Double) { + rate.put(time.getHour(), (Double) rateObj); } - } - else - { - updateState(ERROR,60); - } - break; - case SET: - if(scripter.currentMenu!=null && scripter.currentMenu.getType()==MenuType.WARNING_OR_ERROR) - { - lastMenu = scripter.currentMenu.getType(); - scripter.pressCheckKey(); - updateState(SET, 30); - } - else if(scripter.currentMenu!=null && scripter.currentMenu.getType()==MenuType.MAIN_MENU) { - Object setPercentage = scripter.currentMenu.getAttribute(MenuAttribute.TBR); - Object setDuration = scripter.currentMenu.getAttribute(MenuAttribute.RUNTIME); - if (setPercentage== null ||setDuration==null) { - if(percentage!=100) - { - updateState(ERROR,10); - } - else - { - if(lastMenu==MenuType.WARNING_OR_ERROR) - updateState(AFTER,10); - else - updateState(SET,10); - } + boolean complete = true; + for (int t = 0; t < 24; t++) { + if (rate.get(t) == null) + complete = false; } - else { - double mmTbrPercentage = (Double) setPercentage; - MenuTime mmTbrDuration = (MenuTime) setDuration; - // ... 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) { - updateState(AFTER, 10); + if (retries > 0) { + if (complete) { + scripter.pressBackKey(); + updateState(AFTER, 30); } else { - updateState(ERROR, 10); + retries--; + scripter.pressMenuKey(); + scripter.waitScreen(250); } + } else { + updateState(ERROR, 30); } } break; case ERROR: case AFTER: - synchronized(SetTbrCommand.this) { - SetTbrCommand.this.notify(); + scripter.goToMainMenuScreen(MenuType.MAIN_MENU,2000); + synchronized(GetBasalCommand.this) { + GetBasalCommand.this.notify(); } break; } @@ -282,20 +175,17 @@ public class SetTbrCommand implements Command { } if(state==AFTER) { - if(percentage==100) - return new CommandResult().success(true).enacted(true).message("TBR was cancelled"); - - return new CommandResult().success(true).enacted(true).message( - String.format(Locale.US, "TBR set to %d%% for %d min", percentage, duration)); + for(int i = 0; i < 24;i++) + { + Log.v("BASAL_RATE","BASAL_RATE from "+String.format("%02d",i)+":00 = "+rate.get(i)); + } + return new CommandResult().success(true).enacted(true).message("Basal Rate was read"); } return new CommandResult().success(false).message("failed with state: "+state+" from: "+lastState); } @Override public String toString() { - return "SetTbrCommand{" + - "percentage=" + percentage + - ", duration=" + duration + - '}'; + return "GetTbrCommand{}"; } } From f22f96c1385a32c1a1f4d006624e7211e86a118d Mon Sep 17 00:00:00 2001 From: Timm Korte Date: Fri, 4 Aug 2017 22:39:15 +0200 Subject: [PATCH 18/18] change ComboPlugin to change basal to 90 or 110 percent instead of cancel - depending on previous tbr --- .../plugins/PumpCombo/ComboPlugin.java | 55 +++++++++++++++---- 1 file changed, 43 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 d754cc8785..b3a010414e 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 @@ -547,20 +547,51 @@ public class ComboPlugin implements PluginBase, PumpInterface { @Override public PumpEnactResult cancelTempBasal() { log.debug("cancelTempBasal called"); - CommandResult commandResult = runCommand(new CancelTbrCommand()); - if (commandResult.enacted) { - TemporaryBasal tempStop = new TemporaryBasal(commandResult.completionTime); - tempStop.durationInMinutes = 0; // ending temp basal - tempStop.source = Source.USER; - ConfigBuilderPlugin treatmentsInterface = MainApp.getConfigBuilder(); - treatmentsInterface.addToHistoryTempBasal(tempStop); + + CommandResult commandResult = null; + TemporaryBasal tempBasal = null; + PumpEnactResult pumpEnactResult = new PumpEnactResult(); + + final TemporaryBasal activeTemp = MainApp.getConfigBuilder().getTempBasalFromHistory(System.currentTimeMillis()); + + if (activeTemp == null) { + log.debug("cancelTempBasal really cancelling tbr."); + commandResult = runCommand(new CancelTbrCommand()); + if (commandResult.enacted) { + tempBasal = new TemporaryBasal(commandResult.completionTime); + tempBasal.durationInMinutes = 0; + tempBasal.source = Source.USER; + pumpEnactResult.isTempCancel = true; + } + } else if ((activeTemp.percentRate >= 90 && activeTemp.percentRate <= 110) && activeTemp.getPlannedRemainingMinutes() <= 15 ) { + // do nothing. + log.debug("cancelTempBasal skipping changing tbr since it already is at " + activeTemp.percentRate + "% and running for another " + activeTemp.getPlannedRemainingMinutes() + " mins."); + pumpEnactResult.comment = "cancelTempBasal skipping changing tbr since it already is at " + activeTemp.percentRate + "% and running for another " + activeTemp.getPlannedRemainingMinutes() + " mins."; + pumpEnactResult.enacted = true; // all fine though... + pumpEnactResult.success = true; // just roll with it... + } else { + long percentage = (activeTemp.percentRate > 100) ? 110:90; + log.debug("cancelTempBasal changing tbr to " + percentage + "% for 15 mins."); + commandResult = runCommand(new SetTbrCommand(percentage, 15)); + if (commandResult.enacted) { + tempBasal = new TemporaryBasal(commandResult.completionTime); + tempBasal.durationInMinutes = 15; + tempBasal.source = Source.USER; + tempBasal.percentRate = (int) percentage; + tempBasal.isAbsolute = false; + } } - PumpEnactResult pumpEnactResult = new PumpEnactResult(); - pumpEnactResult.success = commandResult.success; - pumpEnactResult.enacted = commandResult.enacted; - pumpEnactResult.comment = commandResult.message; - pumpEnactResult.isTempCancel = true; + if (tempBasal != null) { + ConfigBuilderPlugin treatmentsInterface = MainApp.getConfigBuilder(); + treatmentsInterface.addToHistoryTempBasal(tempBasal); + } + + if (commandResult != null) { + pumpEnactResult.success = commandResult.success; + pumpEnactResult.enacted = commandResult.enacted; + pumpEnactResult.comment = commandResult.message; + } return pumpEnactResult; }