This commit is contained in:
Johannes Mockenhaupt 2017-10-21 17:44:16 +02:00
parent cb438934b6
commit fc60edc15a
No known key found for this signature in database
GPG key ID: 9E1EA6AF7BBBB0D1
5 changed files with 168 additions and 57 deletions

View file

@ -161,7 +161,6 @@ public class ComboPlugin implements PluginBase, PumpInterface {
// TODO would it be useful to have a 'last error' field in the ui showing the most recent // TODO would it be useful to have a 'last error' field in the ui showing the most recent
// failed command? the next command that runs successful with will override this error // failed command? the next command that runs successful with will override this error
log.warn("Pump still in error state, but alarm raised recently, so not triggering again: " + localLastCmdResult.message); 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); SystemClock.sleep(5 * 1000);
@ -265,9 +264,8 @@ public class ComboPlugin implements PluginBase, PumpInterface {
return lastCmdResult != null ? new Date(lastCmdResult.completionTime) : new Date(0); return lastCmdResult != null ? new Date(lastCmdResult.completionTime) : new Date(0);
} }
@Override private void initializePump() {
public void initialize() { CommandResult commandResult = runCommand("Checking pump history", false, new CommandExecution() {
CommandResult commandResult = runCommand("Syncing pump state", new CommandExecution() {
@Override @Override
public CommandResult execute() { public CommandResult execute() {
return ruffyScripter.readHistory( return ruffyScripter.readHistory(
@ -279,6 +277,12 @@ public class ComboPlugin implements PluginBase, PumpInterface {
} }
}); });
if (!commandResult.success || commandResult.history == null) {
// TODO error case, command
return;
}
// TODO opt, construct PumpHistoryRequest to requset only what needs updating
boolean syncNeeded = false; boolean syncNeeded = false;
// last bolus // last bolus
@ -340,7 +344,7 @@ public class ComboPlugin implements PluginBase, PumpInterface {
// TODO check this is eithor called regularly even with other commansd being fired; if not, // TODO check this is eithor called regularly even with other commansd being fired; if not,
// request this periodically // request this periodically
@Override @Override
public void refreshDataFromPump(String reason) { public synchronized void refreshDataFromPump(String reason) {
log.debug("RefreshDataFromPump called"); log.debug("RefreshDataFromPump called");
// if Android is sluggish this might get called before ruffy is bound // if Android is sluggish this might get called before ruffy is bound
@ -356,13 +360,17 @@ public class ComboPlugin implements PluginBase, PumpInterface {
// if (notAUserRequest && wasRunAtLeastOnce && ranWithinTheLastMinute) { // if (notAUserRequest && wasRunAtLeastOnce && ranWithinTheLastMinute) {
// log.debug("Not fetching state from pump, since we did already within the last 60 seconds"); // log.debug("Not fetching state from pump, since we did already within the last 60 seconds");
// } else { // } else {
if (pump.lastCmdResult == null) {
initializePump();
} else {
runCommand("Refreshing", new CommandExecution() { runCommand("Refreshing", new CommandExecution() {
@Override @Override
public CommandResult execute() { public CommandResult execute() {
return ruffyScripter.readHistory(new PumpHistoryRequest().reservoirLevel(true).bolusHistory(PumpHistoryRequest.LAST)); return ruffyScripter.readHistory(new PumpHistoryRequest().reservoirLevel(true).bolusHistory(PumpHistoryRequest.LAST));
} }
}); });
// } }
} }
// TODO uses profile values for the time being // TODO uses profile values for the time being
@ -637,6 +645,11 @@ public class ComboPlugin implements PluginBase, PumpInterface {
} }
private CommandResult runCommand(String status, CommandExecution commandExecution) { private CommandResult runCommand(String status, CommandExecution commandExecution) {
return runCommand(status, true, commandExecution);
}
private CommandResult runCommand(String status, boolean checkTbrMisMatch, CommandExecution commandExecution) {
MainApp.bus().post(new EventComboPumpUpdateGUI(status)); MainApp.bus().post(new EventComboPumpUpdateGUI(status));
CommandResult commandResult = commandExecution.execute(); CommandResult commandResult = commandExecution.execute();
@ -654,7 +667,9 @@ public class ComboPlugin implements PluginBase, PumpInterface {
pump.state = commandResult.state; pump.state = commandResult.state;
// TODO are there cases when this check should NOT be performed? perform this explicitly or have a flag to skip this? // TODO are there cases when this check should NOT be performed? perform this explicitly or have a flag to skip this?
if (checkTbrMisMatch) {
checkForTbrMismatch(); checkForTbrMismatch();
}
// TODO not propely set all the time ... // TODO not propely set all the time ...
@ -685,6 +700,10 @@ public class ComboPlugin implements PluginBase, PumpInterface {
// TODO check if this works with pump suspend, esp. around pump suspend there'll be syncing to do; // TODO check if this works with pump suspend, esp. around pump suspend there'll be syncing to do;
TemporaryBasal aapsTbr = MainApp.getConfigBuilder().getTempBasalFromHistory(System.currentTimeMillis()); TemporaryBasal aapsTbr = MainApp.getConfigBuilder().getTempBasalFromHistory(System.currentTimeMillis());
// if (true) {
//
// // not yet
// } else
if (aapsTbr == null && pump.state.tbrActive) { if (aapsTbr == null && pump.state.tbrActive) {
// pump runs TBR AAPS is unaware off // pump runs TBR AAPS is unaware off
// => fetch full history so the full TBR is added to treatments // => fetch full history so the full TBR is added to treatments
@ -723,7 +742,12 @@ public class ComboPlugin implements PluginBase, PumpInterface {
} }
private void runFullSync() { private void runFullSync() {
CommandResult commandResult = runCommand("Syncing full pump history", new CommandExecution() { // TODO separate fetching and comparing
if (1 == 1 ) {
log.error("Skipping full sync - not implemented yet");
return;
}
CommandResult commandResult = runCommand("Syncing full pump history", false, new CommandExecution() {
@Override @Override
public CommandResult execute() { public CommandResult execute() {
return ruffyScripter.readHistory( return ruffyScripter.readHistory(

View file

@ -16,6 +16,8 @@ public interface RuffyCommands {
/** Confirms an active alarm on the pump. The state returned is the state after the alarm /** Confirms an active alarm on the pump. The state returned is the state after the alarm
* has been confirmed. The message field contains the displayed error message that was * has been confirmed. The message field contains the displayed error message that was
* confirmed. */ * confirmed. */
// TODO multiple alarms can occur -> empty battery, stops pump -> tbr cancelled
// return them as history.errors?
CommandResult takeOverAlarm(); CommandResult takeOverAlarm();
boolean isPumpAvailable(); boolean isPumpAvailable();

View file

@ -38,19 +38,19 @@ public class PumpHistory {
return this; return this;
} }
@Override
public String toString() {
return "PumpHistory{" +
"reservoirLevel=" + reservoirLevel +
", bolusHistory=" + bolusHistory +
", tbrHistory=" + tbrHistory +
", errorHistory=" + errorHistory +
", tddHistory=" + tddHistory +
'}';
}
public PumpHistory tddHistory(List<Tdd> tddHistory) { public PumpHistory tddHistory(List<Tdd> tddHistory) {
this.tddHistory = tddHistory; this.tddHistory = tddHistory;
return this; return this;
} }
@Override
public String toString() {
return "PumpHistory{" +
"reservoirLevel=" + reservoirLevel +
", bolusHistory=" + bolusHistory.size() +
", tbrHistory=" + tbrHistory.size() +
", errorHistory=" + errorHistory.size() +
", tddHistory=" + tddHistory.size() +
'}';
}
} }

View file

@ -61,6 +61,7 @@ public class RuffyScripter implements RuffyCommands {
private volatile long lastCmdExecutionTime; private volatile long lastCmdExecutionTime;
private volatile Command activeCmd = null; private volatile Command activeCmd = null;
private volatile int retries = 0;
private boolean started = false; private boolean started = false;
@ -221,14 +222,14 @@ public class RuffyScripter implements RuffyCommands {
public void returnToRootMenu() { public void returnToRootMenu() {
// returning to main menu using the 'back' key does not cause a vibration // returning to main menu using the 'back' key does not cause a vibration
while (getCurrentMenu().getType() != MenuType.MAIN_MENU && getCurrentMenu().getType() != MenuType.STOP) { while (getCurrentMenu().getType() != MenuType.MAIN_MENU && getCurrentMenu().getType() != MenuType.STOP) {
if (getCurrentMenu().getType() == MenuType.WARNING_OR_ERROR) { // if (getCurrentMenu().getType() == MenuType.WARNING_OR_ERROR) {
String errorMsg = (String) getCurrentMenu().getAttribute(MenuAttribute.MESSAGE); // String errorMsg = (String) getCurrentMenu().getAttribute(MenuAttribute.MESSAGE);
confirmAlert(errorMsg, 1000); // confirmAlert(errorMsg, 1000);
// TODO this isn't gonna work out ... this method can't know if something was enacted ... // // TODO this isn't gonna work out ... this method can't know if something was enacted ...
// gotta keep that state in the command instance // // gotta keep that state in the command instance
throw new CommandException().success(false).enacted(false) // throw new CommandException().success(false).enacted(false)
.message("Warning/error " + errorMsg + " raised while returning to main menu"); // .message("Warning/error " + errorMsg + " raised while returning to main menu");
} // }
log.debug("Going back to main menu, currently at " + getCurrentMenu().getType()); log.debug("Going back to main menu, currently at " + getCurrentMenu().getType());
pressBackKey(); pressBackKey();
waitForMenuUpdate(); waitForMenuUpdate();
@ -256,12 +257,12 @@ public class RuffyScripter implements RuffyCommands {
synchronized (RuffyScripter.class) { synchronized (RuffyScripter.class) {
try { try {
activeCmd = cmd; activeCmd = cmd;
retries = 3;
long connectStart = System.currentTimeMillis(); long connectStart = System.currentTimeMillis();
ensureConnected(); ensureConnected();
final RuffyScripter scripter = this; final RuffyScripter scripter = this;
final Returnable returnable = new Returnable(); final Returnable returnable = new Returnable();
Thread cmdThread = new Thread(new Runnable() { class CommandRunner {
@Override
public void run() { public void run() {
try { try {
// check if pump is an an error state // check if pump is an an error state
@ -315,6 +316,12 @@ public class RuffyScripter implements RuffyCommands {
lastCmdExecutionTime = System.currentTimeMillis(); lastCmdExecutionTime = System.currentTimeMillis();
} }
} }
}
Thread cmdThread = new Thread(new Runnable() {
@Override
public void run() {
new CommandRunner().run();
}
}, cmd.toString()); }, cmd.toString());
long executionStart = System.currentTimeMillis(); long executionStart = System.currentTimeMillis();
cmdThread.start(); cmdThread.start();
@ -323,6 +330,7 @@ public class RuffyScripter implements RuffyCommands {
// (to fail before the next loop iteration issues the next command) // (to fail before the next loop iteration issues the next command)
long dynamicTimeout = System.currentTimeMillis() + 90 * 1000; long dynamicTimeout = System.currentTimeMillis() + 90 * 1000;
long overallTimeout = System.currentTimeMillis() + 4 * 60 * 1000; long overallTimeout = System.currentTimeMillis() + 4 * 60 * 1000;
int retries = 3;
while (cmdThread.isAlive()) { while (cmdThread.isAlive()) {
log.trace("Waiting for running command to complete"); log.trace("Waiting for running command to complete");
SystemClock.sleep(500); SystemClock.sleep(500);
@ -341,6 +349,22 @@ public class RuffyScripter implements RuffyCommands {
return new CommandResult().success(false).enacted(false).message("Command stalled, check pump!"); return new CommandResult().success(false).enacted(false).message("Command stalled, check pump!");
} }
} }
if (!ruffyService.isConnected()) {
if (retries > 0) {
retries--;
cmdThread.interrupt();
reconnect();
cmdThread = new Thread(new Runnable() {
@Override
public void run() {
new CommandRunner().run();
}
}, cmd.toString());
cmdThread.start();
dynamicTimeout = System.currentTimeMillis() + 90 * 1000;
overallTimeout = System.currentTimeMillis() + 4 * 60 * 1000;
}
}
if (now > overallTimeout) { if (now > overallTimeout) {
String msg = "Command " + cmd + " timed out after 4 min, check pump!"; String msg = "Command " + cmd + " timed out after 4 min, check pump!";
log.error(msg); log.error(msg);
@ -358,10 +382,21 @@ public class RuffyScripter implements RuffyCommands {
log.debug("Command result: " + returnable.cmdResult); log.debug("Command result: " + returnable.cmdResult);
return returnable.cmdResult; return returnable.cmdResult;
} catch (CommandException e) { } catch (CommandException e) {
return e.toCommandResult(); CommandResult commandResult = e.toCommandResult();
if (commandResult.state == null) commandResult.state = readPumpStateInternal();
return commandResult;
} catch (Exception e) { } catch (Exception e) {
// TODO catching E here AND in CommandRunner?
// TODO detect and report pump warnings/errors differently? // TODO detect and report pump warnings/errors differently?
log.error("Error in ruffyscripter/ruffy", e); log.error("Error in ruffyscripter/ruffy", e);
try {
return new CommandResult()
.exception(e)
.message("Unexpected exception communication with ruffy: " + e.getMessage())
.state(readPumpStateInternal());
} catch (Exception e1) {
// nothing more we can try
}
return new CommandResult().exception(e).message("Unexpected exception communication with ruffy: " + e.getMessage()); return new CommandResult().exception(e).message("Unexpected exception communication with ruffy: " + e.getMessage());
} finally { } finally {
activeCmd = null; activeCmd = null;
@ -369,6 +404,37 @@ public class RuffyScripter implements RuffyCommands {
} }
} }
/** On connection lost the pump raises an error immediately (when setting a TBR or giving a bolus),
* there's no timeout. But: a reconnect is still possible which can then confirm the alarm and
* foward it to an app.*/
public void reconnect() {
// try {
log.debug("Connection was lost, trying to reconnect");
ensureConnected();
if (getCurrentMenu().getType() == MenuType.WARNING_OR_ERROR) {
String message = (String) getCurrentMenu().getAttribute(MenuAttribute.MESSAGE);
if (activeCmd instanceof BolusCommand && message.equals("BOLUS CANCELLED")
|| (activeCmd instanceof CancelTbrCommand || activeCmd instanceof SetTbrCommand)
&& message.equals("TBR CANCELLED")) {
// confirm alert
verifyMenuIsDisplayed(MenuType.WARNING_OR_ERROR);
pressCheckKey();
// dismiss alert
verifyMenuIsDisplayed(MenuType.WARNING_OR_ERROR);
pressCheckKey();
waitForMenuToBeLeft(MenuType.WARNING_OR_ERROR);
// TODO multiple alarms can be raised, e.g. if pump enters STOP mode due
// to battery_empty, that alert is raised and then causes a TBR CANCELLED
// if one was running
// TODO report those errors back!
// ... need a more controlled way to 'assemble' return data
// like adding a CommandResult field to a command and merge stuff into it?
}
}
returnToRootMenu();
}
/** /**
* If there's an issue, this times out eventually and throws a CommandException * If there's an issue, this times out eventually and throws a CommandException
*/ */
@ -405,7 +471,23 @@ public class RuffyScripter implements RuffyCommands {
// if the user just pressed a button on the combo, the screen needs to time first // 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 // before a connection is possible. In that case, it takes 45s before the
// connection comes up. // connection comes up.
waitForMenuUpdate(90, "Timeout connecting to pump"); // waitForMenuUpdate(90, "Timeout connecting to pump");
long timeoutExpired = System.currentTimeMillis() + 90 * 1000;
long initialUpdateTime = menuLastUpdated;
long again = System.currentTimeMillis() + 30 * 1000;
while (initialUpdateTime == menuLastUpdated) {
if (System.currentTimeMillis() > timeoutExpired) {
throw new CommandException().message("Timeout connecting to pump");
}
SystemClock.sleep(50);
if (again < System.currentTimeMillis()) {
// TODO test
ruffyService.doRTDisconnect();
SystemClock.sleep(2000);
ruffyService.doRTConnect();
again = System.currentTimeMillis() + 30 * 1000;
}
}
} catch (CommandException e) { } catch (CommandException e) {
throw e; throw e;
} catch (Exception e) { } catch (Exception e) {
@ -527,7 +609,7 @@ public class RuffyScripter implements RuffyCommands {
// @Override // @Override
// public void doStep() { // public void doStep() {
log.debug("Pressing up key"); log.debug("Pressing up key");
pressKey(Key.UP, 2000); pressKey(Key.UP);
log.debug("Releasing up key"); log.debug("Releasing up key");
// } // }
// }); // });
@ -535,25 +617,25 @@ public class RuffyScripter implements RuffyCommands {
public void pressDownKey() { public void pressDownKey() {
log.debug("Pressing down key"); log.debug("Pressing down key");
pressKey(Key.DOWN, 2000); pressKey(Key.DOWN);
log.debug("Releasing down key"); log.debug("Releasing down key");
} }
public void pressCheckKey() { public void pressCheckKey() {
log.debug("Pressing check key"); log.debug("Pressing check key");
pressKey(Key.CHECK, 2000); pressKey(Key.CHECK);
log.debug("Releasing check key"); log.debug("Releasing check key");
} }
public void pressMenuKey() { public void pressMenuKey() {
log.debug("Pressing menu key"); log.debug("Pressing menu key");
pressKey(Key.MENU, 2000); pressKey(Key.MENU);
log.debug("Releasing menu key"); log.debug("Releasing menu key");
} }
public void pressBackKey() { public void pressBackKey() {
log.debug("Pressing back key"); log.debug("Pressing back key");
pressKey(Key.BACK, 2000); pressKey(Key.BACK);
log.debug("Releasing back key"); log.debug("Releasing back key");
} }
@ -646,38 +728,36 @@ public class RuffyScripter implements RuffyCommands {
} }
} }
private void pressKey(final byte key, long timeout) { private void pressKey(final byte key) {
try { try {
ruffyService.rtSendKey(key, true); ruffyService.rtSendKey(key, true);
SystemClock.sleep(200); SystemClock.sleep(200);
ruffyService.rtSendKey(Key.NO_KEY, true); ruffyService.rtSendKey(Key.NO_KEY, true);
// if (timeout > 0) {
// synchronized (keylock) {
// keylock.wait(timeout);
// }
// } else {
// synchronized (keylock) {
// keynotwait++;
// }
// }
} catch (Exception e) { } catch (Exception e) {
throw new CommandException().exception(e).message("Error while pressing buttons"); throw new CommandException().exception(e).message("Error while pressing buttons");
} }
} }
public void navigateToMenu(MenuType desiredMenu) { public void navigateToMenu(MenuType desiredMenu) {
MenuType startedFrom = getCurrentMenu().getType(); // MenuType startedFrom = getCurrentMenu().getType();
boolean movedOnce = false; // boolean movedOnce = false;
int retries = 20;
while (getCurrentMenu().getType() != desiredMenu) { while (getCurrentMenu().getType() != desiredMenu) {
retries --;
MenuType currentMenuType = getCurrentMenu().getType(); MenuType currentMenuType = getCurrentMenu().getType();
log.debug("Navigating to menu " + desiredMenu + ", current menu: " + currentMenuType); log.debug("Navigating to menu " + desiredMenu + ", current menu: " + currentMenuType);
if (movedOnce && currentMenuType == startedFrom) { // 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.");
// }
if (retries == 0) {
throw new CommandException().message("Menu not found searching for " + desiredMenu throw new CommandException().message("Menu not found searching for " + desiredMenu
+ ". Check menu settings on your pump to ensure it's not hidden."); + ". Check menu settings on your pump to ensure it's not hidden.");
} }
pressMenuKey(); pressMenuKey();
waitForMenuToBeLeft(currentMenuType); // waitForMenuToBeLeft(currentMenuType);
movedOnce = true; SystemClock.sleep(200);
// movedOnce = true;
} }
} }

View file

@ -7,6 +7,7 @@ import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket; import android.bluetooth.BluetoothSocket;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.util.Log;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -94,6 +95,10 @@ public class BTConnection {
public void connect(PumpData pumpData, int retries) public void connect(PumpData pumpData, int retries)
{ {
// if (pumpData == null) {
// Log.e("JOE", "pumpdata null 1");
// return;
// }
this.pumpData = pumpData; this.pumpData = pumpData;
connect(pumpData.getPumpMac(),retries); connect(pumpData.getPumpMac(),retries);
} }