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) {