diff --git a/ch.psi.fda/pom.xml b/ch.psi.fda/pom.xml index e6acca9..24d7835 100644 --- a/ch.psi.fda/pom.xml +++ b/ch.psi.fda/pom.xml @@ -9,7 +9,7 @@ ch.psi jcae - 2.1.9 + 2.1.10 diff --git a/ch.psi.fda/src/main/java/ch/psi/fda/aq/AcquisitionEngineNG.java b/ch.psi.fda/src/main/java/ch/psi/fda/aq/AcquisitionEngineNG.java index 682a67a..07abcf4 100644 --- a/ch.psi.fda/src/main/java/ch/psi/fda/aq/AcquisitionEngineNG.java +++ b/ch.psi.fda/src/main/java/ch/psi/fda/aq/AcquisitionEngineNG.java @@ -18,30 +18,65 @@ */ package ch.psi.fda.aq; +import java.util.Map; +import java.util.concurrent.TimeoutException; +import java.util.logging.Logger; + import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; +import ch.psi.jcae.ChannelDescriptor; +import ch.psi.jcae.ChannelException; +import ch.psi.jcae.ChannelService; + /** * @author ebner * */ public class AcquisitionEngineNG { - - private ScriptEngine engine; - - public AcquisitionEngineNG() { + + private static final Logger logger = Logger.getLogger(AcquisitionEngineNG.class.getName()); + + private ChannelService cservice; + + public AcquisitionEngineNG(ChannelService cservice) { + this.cservice = cservice; + // Workaround for Jython memory leak // http://blog.hillbrecht.de/2009/07/11/jython-memory-leakout-of-memory-problem/ System.setProperty("python.options.internalTablesImpl", "weak"); - - // Create new script engine - this.engine = new ScriptEngineManager().getEngineByName("python"); } - public void execute(String script){ + public void execute(Map resourceDescriptors, String script){ try { + ScriptEngine engine = new ScriptEngineManager().getEngineByName("python"); + + // Set logger + engine.put("logger", logger); + + // Retrieve and set resources + for(String k: resourceDescriptors.keySet()){ + if(resourceDescriptors.get(k) instanceof ChannelDescriptor){ + ChannelDescriptor descriptor = (ChannelDescriptor)resourceDescriptors.get(k); + try { + engine.put(k, cservice.createChannel(descriptor)); + } catch (ChannelException | InterruptedException | TimeoutException e) { + throw new RuntimeException("Unable to create resource for channel: "+descriptor.getName(),e); + } + } + else if(resourceDescriptors.get(k) instanceof ShellDescriptor){ + engine.put(k, new ShellResource()); + } + else{ + throw new RuntimeException("Resource type not supported: "+resourceDescriptors.get(k).getClass().getName()); + } + } + + // Execute script engine.eval(script); + + } catch (ScriptException e) { throw new RuntimeException("Action failed while executing the Jython script",e); } diff --git a/ch.psi.fda/src/main/java/ch/psi/fda/aq/ScanMapperNG.java b/ch.psi.fda/src/main/java/ch/psi/fda/aq/ScanMapperNG.java index eeb63da..d573afc 100644 --- a/ch.psi.fda/src/main/java/ch/psi/fda/aq/ScanMapperNG.java +++ b/ch.psi.fda/src/main/java/ch/psi/fda/aq/ScanMapperNG.java @@ -19,100 +19,100 @@ package ch.psi.fda.aq; import java.util.ArrayList; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.UUID; +import java.util.logging.Logger; -import ch.psi.fda.core.Actor; -import ch.psi.fda.core.actions.ChannelAccessCondition; -import ch.psi.fda.core.actions.ChannelAccessConditionAnd; -import ch.psi.fda.core.actions.ChannelAccessConditionOr; -import ch.psi.fda.core.actions.ChannelAccessConditionRegex; -import ch.psi.fda.core.actions.ChannelAccessPut; -import ch.psi.fda.core.actions.Delay; -import ch.psi.fda.core.actors.ChannelAccessFunctionActuator; -import ch.psi.fda.core.actors.ChannelAccessLinearActuator; -import ch.psi.fda.core.actors.ChannelAccessTableActuator; -import ch.psi.fda.core.actors.ComplexActuator; -import ch.psi.fda.core.actors.JythonFunction; -import ch.psi.fda.core.actors.PseudoActuatorSensor; -import ch.psi.fda.core.scripting.JythonParameterMappingChannel; -import ch.psi.fda.core.sensors.ChannelAccessDoubleSensor; import ch.psi.fda.model.v1.Action; -import ch.psi.fda.model.v1.ArrayPositioner; import ch.psi.fda.model.v1.ChannelAction; -import ch.psi.fda.model.v1.ChannelParameterMapping; import ch.psi.fda.model.v1.Configuration; import ch.psi.fda.model.v1.ContinuousDimension; import ch.psi.fda.model.v1.Dimension; import ch.psi.fda.model.v1.DiscreteStepDimension; import ch.psi.fda.model.v1.DiscreteStepPositioner; -import ch.psi.fda.model.v1.FunctionPositioner; -import ch.psi.fda.model.v1.LinearPositioner; -import ch.psi.fda.model.v1.PseudoPositioner; -import ch.psi.fda.model.v1.Region; -import ch.psi.fda.model.v1.RegionPositioner; import ch.psi.fda.model.v1.Scan; import ch.psi.fda.model.v1.ScriptAction; import ch.psi.fda.model.v1.ShellAction; +import ch.psi.jcae.ChannelDescriptor; +import ch.psi.jcae.util.ComparatorAND; +import ch.psi.jcae.util.ComparatorOR; +import ch.psi.jcae.util.ComparatorREGEX; /** * @author ebner - * + * */ public class ScanMapperNG { + private static final Logger logger = Logger.getLogger(ScanMapperNG.class.getName()); + private static final String INDENT = " "; private StringBuilder script = new StringBuilder(); private Set imports = new HashSet<>(); - private String indentation=""; - - - - public void map(Configuration configuration){ - + private Map resourceDescriptors = new HashMap<>(); + + private String indentation = ""; + + public void map(Configuration configuration) { + Scan scan = configuration.getScan(); mapActions(scan.getPreAction()); - - // Bring the dimensions into the correct order and then map them + // Bring the dimensions into the correct order and then map them // to the script List dimensions = new ArrayList<>(); int size = scan.getDimension().size(); - for(int i=size-1; i>=0; i--){ + for (int i = size - 1; i >= 0; i--) { dimensions.add(scan.getDimension().get(i)); } // Continuous dimensions are always at the very end - if(scan.getCdimension()!=null){ + if (scan.getCdimension() != null) { dimensions.add(scan.getCdimension()); } mapDimensions(dimensions, 0); - - - // map + + // map mapActions(scan.getPostAction()); - - // TODO CONSIDER TO PROVIDE RESOURCE MAP AND SCRIPT IN ONE OBJECT AS RETURN TYPE + + // TODO CONSIDER TO PROVIDE RESOURCE MAP AND SCRIPT IN ONE OBJECT AS + // RETURN TYPE // WOULD MAKE MORE SENSE } - - + /** * Get the generated script + * * @return */ - public String getScript(){ - StringBuilder scriptlines= new StringBuilder(); - for(String s: imports){ - scriptlines.append("import "+s+"\n"); + public String getScript() { + StringBuilder scriptlines = new StringBuilder(); + for (String s : imports) { + scriptlines.append(s + "\n"); } scriptlines.append(script); return scriptlines.toString(); } + /** + * Get map of required resources + * @return + */ + public Map getResourceDescriptors(){ + return resourceDescriptors; + } + private void mapDimensions(List dimensions, int index) { + + if(dimensions.size()<1){ + logger.info("There are no dimensions to map"); + return; + } + Dimension dimension = dimensions.get(index); if (dimension instanceof DiscreteStepDimension) { DiscreteStepDimension d = (DiscreteStepDimension) dimension; @@ -125,12 +125,12 @@ public class ScanMapperNG { mapActions(d.getAction()); // TODO map guard and sensors - + // Next dimension - if((index+1) actions){ - for(Action action: actions){ - if(action instanceof ChannelAction){ + + private void mapActions(List actions) { + for (Action action : actions) { + if (action instanceof ChannelAction) { ChannelAction ca = (ChannelAction) action; + Class type = String.class; + long waitTimeout=1800000; // Max wait timeout is 30 minutes + if(ca.getTimeout()!=null){ + waitTimeout = ca.getTimeout().longValue()*1000; // wait timeout is currently in seconds + } + ca.getTimeout(); + switch (ca.getType()) { + case "Integer": + type = Integer.class; + break; + case "Double": + type = Double.class; + break; + } + String var = getChannelResourceVariable(ca.getChannel(), type, false); switch (ca.getOperation()) { case "put": + if(ca.getTimeout()==null){ + script.append(var+".setValue("+getPythonValue(ca.getValue(), type)+")\n"); + } else { + imports.add("from java.util.concurrent import TimeUnit"); + script.append(var+".setValueAsync("+getPythonValue(ca.getValue(), type)+").get("+ca.getTimeout()+", TimeUnit.MILLISECONDS)\n"); + } break; case "putq": + script.append(var+".setValueAsync("+getPythonValue(ca.getValue(), type)+")\n"); break; case "wait": + script.append(var+".waitForValue("+getPythonValue(ca.getValue(), type)+", "+waitTimeout+")\n"); break; case "waitREGEX": + imports.add("from"+ComparatorREGEX.class.getPackage().getName()+" import "+ComparatorREGEX.class.getName()); + script.append(var+".waitForValue("+getPythonValue(ca.getValue(), type)+", "+ComparatorREGEX.class.getName()+"() "+waitTimeout+")\n"); break; case "waitOR": + imports.add("from"+ComparatorOR.class.getPackage().getName()+" import "+ComparatorOR.class.getName()); + script.append(var+".waitForValue("+getPythonValue(ca.getValue(), type)+", "+ComparatorOR.class.getName()+"() "+waitTimeout+")\n"); break; case "waitAND": + imports.add("from"+ComparatorAND.class.getPackage().getName()+" import "+ComparatorAND.class.getName()); + script.append(var+".waitForValue("+getPythonValue(ca.getValue(), type)+", "+ComparatorAND.class.getName()+"() "+waitTimeout+")\n"); + break; + default: + logger.warning("Operation - "+ca.getOperation()+" - is not supported"); + // TODO Eventually throw exception - have two modes one logging, one exception? break; } - } - else if(action instanceof ShellAction){ - ShellAction saction = (ShellAction) action; - // TODO Need to indicate that shell resource is required - script.append(indentation+String.format("shell.execute('%s', %d, %s)\n", saction.getCommand(), saction.getExitValue(), saction.isCheckExitValue())); - } - else if(action instanceof ScriptAction){ - ScriptAction saction = (ScriptAction) action; - - // TODO Need to indicate that that mapped resources are required - // Read script line by line and prepend the current indentation level - String[] lines = saction.getScript().split(System.getProperty("line.separator")); - for(String s:lines){ - script.append(indentation+s); + + // If delay is specified wait specified time + if (ca.getDelay() != null) { + imports.add("import time"); + script.append("time.sleep(" + (ca.getDelay()) + ")\n"); } - script.append(indentation+"\n"); + + } else if (action instanceof ShellAction) { + ShellAction saction = (ShellAction) action; + resourceDescriptors.put("shell", new ShellDescriptor()); + // TODO Need to indicate that shell resource is required + script.append(indentation + String.format("shell.execute('%s', %d, %s)\n", saction.getCommand(), saction.getExitValue(), saction.isCheckExitValue()?"True":"False")); + } else if (action instanceof ScriptAction) { + ScriptAction saction = (ScriptAction) action; + + // TODO Need to indicate that that mapped resources are required + // Read script line by line and prepend the current indentation + // level + String[] lines = saction.getScript().split(System.getProperty("line.separator")); + for (String s : lines) { + script.append(indentation + s); + } + script.append(indentation + "\n"); } } } - + public void mapPositioners(List positioners) { -// for (DiscreteStepPositioner p : positioners) { -// -// if (p.getSettlingTime() > stime) { -// stime = p.getSettlingTime(); -// } -// -// if (p instanceof LinearPositioner) { -// LinearPositioner lp = (LinearPositioner) p; -// ChannelAccessLinearActuator a; -// if (lp.getType().equals("String")) { -// a = new ChannelAccessLinearActuator(cservice, lp.getName(), lp.getDone(), lp.getDoneValue(), lp.getDoneDelay(), lp.getStart(), lp.getEnd(), lp.getStepSize(), moveTimeout); -// } else if (lp.getType().equals("Double")) { -// a = new ChannelAccessLinearActuator(cservice, lp.getName(), lp.getDone(), Double.parseDouble(lp.getDoneValue()), lp.getDoneDelay(), lp.getStart(), lp.getEnd(), -// lp.getStepSize(), moveTimeout); -// } else { -// // Default -// a = new ChannelAccessLinearActuator(cservice, lp.getName(), lp.getDone(), Integer.parseInt(lp.getDoneValue()), lp.getDoneDelay(), lp.getStart(), lp.getEnd(), -// lp.getStepSize(), moveTimeout); -// } -// -// a.setAsynchronous(lp.isAsynchronous()); -// Actor actuator = a; -// -// aLoop.getActors().add(actuator); -// -// // Add a sensor for the readback -// String name = lp.getReadback(); -// if (name == null) { -// name = lp.getName(); -// } -// ChannelAccessDoubleSensor sensor = new ChannelAccessDoubleSensor(cservice, lp.getId(), name); -// aLoop.getSensors().add(sensor); -// } else if (p instanceof FunctionPositioner) { -// FunctionPositioner lp = (FunctionPositioner) p; -// -// // Create function object -// JythonFunction function = mapFunction(lp.getFunction()); -// -// // Create actuator -// ChannelAccessFunctionActuator a; -// if (lp.getType().equals("String")) { -// a = new ChannelAccessFunctionActuator(cservice, lp.getName(), lp.getDone(), lp.getDoneValue(), lp.getDoneDelay(), function, lp.getStart(), lp.getEnd(), lp.getStepSize(), -// moveTimeout); -// } else if (lp.getType().equals("Double")) { -// a = new ChannelAccessFunctionActuator(cservice, lp.getName(), lp.getDone(), Double.parseDouble(lp.getDoneValue()), lp.getDoneDelay(), function, lp.getStart(), lp.getEnd(), -// lp.getStepSize(), moveTimeout); -// } else { -// // Default -// a = new ChannelAccessFunctionActuator(cservice, lp.getName(), lp.getDone(), Integer.parseInt(lp.getDoneValue()), lp.getDoneDelay(), function, lp.getStart(), lp.getEnd(), -// lp.getStepSize(), moveTimeout); -// } -// -// a.setAsynchronous(lp.isAsynchronous()); -// Actor actuator = a; -// -// aLoop.getActors().add(actuator); -// -// // Add a sensor for the readback -// String name = lp.getReadback(); -// if (name == null) { -// name = lp.getName(); -// } -// ChannelAccessDoubleSensor sensor = new ChannelAccessDoubleSensor(cservice, lp.getId(), name); -// aLoop.getSensors().add(sensor); -// } else if (p instanceof ArrayPositioner) { -// ArrayPositioner ap = (ArrayPositioner) p; -// String[] positions = (ap.getPositions().trim()).split(" +"); -// double[] table = new double[positions.length]; -// for (int i = 0; i < positions.length; i++) { -// table[i] = Double.parseDouble(positions[i]); -// } -// -// ChannelAccessTableActuator a; -// if (p.getType().equals("String")) { -// a = new ChannelAccessTableActuator(cservice, p.getName(), p.getDone(), p.getDoneValue(), p.getDoneDelay(), table, moveTimeout); -// } else if (p.getType().equals("Double")) { -// a = new ChannelAccessTableActuator(cservice, p.getName(), p.getDone(), Double.parseDouble(p.getDoneValue()), p.getDoneDelay(), table, moveTimeout); -// } else { -// // Default -// a = new ChannelAccessTableActuator(cservice, p.getName(), p.getDone(), Integer.parseInt(p.getDoneValue()), p.getDoneDelay(), table, moveTimeout); -// } -// -// a.setAsynchronous(p.isAsynchronous()); -// Actor actuator = a; -// -// aLoop.getActors().add(actuator); -// -// // Add a sensor for the readback -// String name = ap.getReadback(); -// if (name == null) { -// name = ap.getName(); -// } -// ChannelAccessDoubleSensor sensor = new ChannelAccessDoubleSensor(cservice, ap.getId(), name); -// aLoop.getSensors().add(sensor); -// } else if (p instanceof RegionPositioner) { -// RegionPositioner rp = (RegionPositioner) p; -// -// ComplexActuator actuator = new ComplexActuator(); -// /* -// * Regions are translated into a complex actor consisting of a -// * LinearActuator If consecutive regions are overlapping, i.e. -// * end point of region a equals the start point of region b then -// * the start point for the LinearActuator of region b is changes -// * to its next step (start+/-stepSize depending on whether end -// * position of the region is > or < start of the region) -// */ -// Region lastRegion = null; -// for (Region r : rp.getRegion()) { -// // Normal region -// if (r.getFunction() == null) { -// -// // Check whether regions are consecutive -// double start = r.getStart(); -// if (lastRegion != null && start == lastRegion.getEnd()) { // TODO -// // verify -// // whether -// // double -// // comparison -// // is -// // ok -// if (r.getStart() < r.getEnd()) { -// start = start + r.getStepSize(); -// } else { -// start = start - r.getStepSize(); -// } -// } -// -// // Create actuator -// ChannelAccessLinearActuator act; -// if (rp.getType().equals("String")) { -// act = new ChannelAccessLinearActuator(cservice, rp.getName(), rp.getDone(), rp.getDoneValue(), rp.getDoneDelay(), start, r.getEnd(), r.getStepSize(), moveTimeout); -// } else if (rp.getType().equals("Double")) { -// act = new ChannelAccessLinearActuator(cservice, rp.getName(), rp.getDone(), Double.parseDouble(rp.getDoneValue()), rp.getDoneDelay(), start, r.getEnd(), -// r.getStepSize(), moveTimeout); -// } else { -// // Default -// act = new ChannelAccessLinearActuator(cservice, rp.getName(), rp.getDone(), Integer.parseInt(rp.getDoneValue()), rp.getDoneDelay(), start, r.getEnd(), -// r.getStepSize(), moveTimeout); -// } -// -// act.setAsynchronous(rp.isAsynchronous()); -// Actor a = act; -// -// ComplexActuator ca = new ComplexActuator(); -// ca.getActors().add(a); -// ca.getPreActions().addAll(mapActions(r.getPreAction())); -// actuator.getActors().add(ca); -// lastRegion = r; -// } else { -// // Function based region -// -// // Cannot check whether the regions are consecutive as -// // the function -// // used might change the start value to something else -// // [THIS LIMITATION NEEDS TO BE SOMEHOW RESOLVED IN THE -// // NEXT VERSIONS] -// JythonFunction function = mapFunction(r.getFunction()); -// ChannelAccessFunctionActuator act; -// if (rp.getType().equals("String")) { -// act = new ChannelAccessFunctionActuator(cservice, rp.getName(), rp.getDone(), rp.getDoneValue(), rp.getDoneDelay(), function, r.getStart(), r.getEnd(), -// r.getStepSize(), moveTimeout); -// } else if (rp.getType().equals("Double")) { -// act = new ChannelAccessFunctionActuator(cservice, rp.getName(), rp.getDone(), Double.parseDouble(rp.getDoneValue()), rp.getDoneDelay(), function, r.getStart(), -// r.getEnd(), r.getStepSize(), moveTimeout); -// } else { -// // Default -// act = new ChannelAccessFunctionActuator(cservice, rp.getName(), rp.getDone(), Integer.parseInt(rp.getDoneValue()), rp.getDoneDelay(), function, r.getStart(), -// r.getEnd(), r.getStepSize(), moveTimeout); -// } -// -// act.setAsynchronous(rp.isAsynchronous()); -// Actor a = act; -// -// ComplexActuator ca = new ComplexActuator(); -// ca.getActors().add(a); -// ca.getPreActions().addAll(mapActions(r.getPreAction())); -// actuator.getActors().add(ca); -// lastRegion = r; -// } -// } -// aLoop.getActors().add(actuator); -// -// // Add a sensor for the readback -// String name = rp.getReadback(); -// if (name == null) { -// name = rp.getName(); -// } -// ChannelAccessDoubleSensor sensor = new ChannelAccessDoubleSensor(cservice, rp.getId(), name); -// aLoop.getSensors().add(sensor); -// } else if (p instanceof PseudoPositioner) { -// PseudoPositioner pp = (PseudoPositioner) p; -// PseudoActuatorSensor actorSensor = new PseudoActuatorSensor(pp.getId(), pp.getCounts()); -// -// // Register as actor -// aLoop.getActors().add(actorSensor); -// -// // Register as sensor -// aLoop.getSensors().add(actorSensor); -// } else { -// // Not supported -// logger.warning("Mapping for " + p.getClass().getName() + " not available"); -// } -// } + // for (DiscreteStepPositioner p : positioners) { + // + // if (p.getSettlingTime() > stime) { + // stime = p.getSettlingTime(); + // } + // + // if (p instanceof LinearPositioner) { + // LinearPositioner lp = (LinearPositioner) p; + // ChannelAccessLinearActuator a; + // if (lp.getType().equals("String")) { + // a = new ChannelAccessLinearActuator(cservice, lp.getName(), + // lp.getDone(), lp.getDoneValue(), lp.getDoneDelay(), lp.getStart(), + // lp.getEnd(), lp.getStepSize(), moveTimeout); + // } else if (lp.getType().equals("Double")) { + // a = new ChannelAccessLinearActuator(cservice, lp.getName(), + // lp.getDone(), Double.parseDouble(lp.getDoneValue()), + // lp.getDoneDelay(), lp.getStart(), lp.getEnd(), + // lp.getStepSize(), moveTimeout); + // } else { + // // Default + // a = new ChannelAccessLinearActuator(cservice, lp.getName(), + // lp.getDone(), Integer.parseInt(lp.getDoneValue()), lp.getDoneDelay(), + // lp.getStart(), lp.getEnd(), + // lp.getStepSize(), moveTimeout); + // } + // + // a.setAsynchronous(lp.isAsynchronous()); + // Actor actuator = a; + // + // aLoop.getActors().add(actuator); + // + // // Add a sensor for the readback + // String name = lp.getReadback(); + // if (name == null) { + // name = lp.getName(); + // } + // ChannelAccessDoubleSensor sensor = new + // ChannelAccessDoubleSensor(cservice, lp.getId(), name); + // aLoop.getSensors().add(sensor); + // } else if (p instanceof FunctionPositioner) { + // FunctionPositioner lp = (FunctionPositioner) p; + // + // // Create function object + // JythonFunction function = mapFunction(lp.getFunction()); + // + // // Create actuator + // ChannelAccessFunctionActuator a; + // if (lp.getType().equals("String")) { + // a = new ChannelAccessFunctionActuator(cservice, lp.getName(), + // lp.getDone(), lp.getDoneValue(), lp.getDoneDelay(), function, + // lp.getStart(), lp.getEnd(), lp.getStepSize(), + // moveTimeout); + // } else if (lp.getType().equals("Double")) { + // a = new ChannelAccessFunctionActuator(cservice, lp.getName(), + // lp.getDone(), Double.parseDouble(lp.getDoneValue()), + // lp.getDoneDelay(), function, lp.getStart(), lp.getEnd(), + // lp.getStepSize(), moveTimeout); + // } else { + // // Default + // a = new ChannelAccessFunctionActuator(cservice, + // lp.getName(), lp.getDone(), Integer.parseInt(lp.getDoneValue()), + // lp.getDoneDelay(), function, lp.getStart(), lp.getEnd(), + // lp.getStepSize(), moveTimeout); + // } + // + // a.setAsynchronous(lp.isAsynchronous()); + // Actor actuator = a; + // + // aLoop.getActors().add(actuator); + // + // // Add a sensor for the readback + // String name = lp.getReadback(); + // if (name == null) { + // name = lp.getName(); + // } + // ChannelAccessDoubleSensor sensor = new + // ChannelAccessDoubleSensor(cservice, lp.getId(), name); + // aLoop.getSensors().add(sensor); + // } else if (p instanceof ArrayPositioner) { + // ArrayPositioner ap = (ArrayPositioner) p; + // String[] positions = (ap.getPositions().trim()).split(" +"); + // double[] table = new double[positions.length]; + // for (int i = 0; i < positions.length; i++) { + // table[i] = Double.parseDouble(positions[i]); + // } + // + // ChannelAccessTableActuator a; + // if (p.getType().equals("String")) { + // a = new ChannelAccessTableActuator(cservice, p.getName(), + // p.getDone(), p.getDoneValue(), p.getDoneDelay(), table, moveTimeout); + // } else if (p.getType().equals("Double")) { + // a = new ChannelAccessTableActuator(cservice, p.getName(), + // p.getDone(), Double.parseDouble(p.getDoneValue()), p.getDoneDelay(), + // table, moveTimeout); + // } else { + // // Default + // a = new ChannelAccessTableActuator(cservice, p.getName(), + // p.getDone(), Integer.parseInt(p.getDoneValue()), p.getDoneDelay(), + // table, moveTimeout); + // } + // + // a.setAsynchronous(p.isAsynchronous()); + // Actor actuator = a; + // + // aLoop.getActors().add(actuator); + // + // // Add a sensor for the readback + // String name = ap.getReadback(); + // if (name == null) { + // name = ap.getName(); + // } + // ChannelAccessDoubleSensor sensor = new + // ChannelAccessDoubleSensor(cservice, ap.getId(), name); + // aLoop.getSensors().add(sensor); + // } else if (p instanceof RegionPositioner) { + // RegionPositioner rp = (RegionPositioner) p; + // + // ComplexActuator actuator = new ComplexActuator(); + // /* + // * Regions are translated into a complex actor consisting of a + // * LinearActuator If consecutive regions are overlapping, i.e. + // * end point of region a equals the start point of region b then + // * the start point for the LinearActuator of region b is changes + // * to its next step (start+/-stepSize depending on whether end + // * position of the region is > or < start of the region) + // */ + // Region lastRegion = null; + // for (Region r : rp.getRegion()) { + // // Normal region + // if (r.getFunction() == null) { + // + // // Check whether regions are consecutive + // double start = r.getStart(); + // if (lastRegion != null && start == lastRegion.getEnd()) { // TODO + // // verify + // // whether + // // double + // // comparison + // // is + // // ok + // if (r.getStart() < r.getEnd()) { + // start = start + r.getStepSize(); + // } else { + // start = start - r.getStepSize(); + // } + // } + // + // // Create actuator + // ChannelAccessLinearActuator act; + // if (rp.getType().equals("String")) { + // act = new ChannelAccessLinearActuator(cservice, rp.getName(), + // rp.getDone(), rp.getDoneValue(), rp.getDoneDelay(), start, + // r.getEnd(), r.getStepSize(), moveTimeout); + // } else if (rp.getType().equals("Double")) { + // act = new ChannelAccessLinearActuator(cservice, rp.getName(), + // rp.getDone(), Double.parseDouble(rp.getDoneValue()), + // rp.getDoneDelay(), start, r.getEnd(), + // r.getStepSize(), moveTimeout); + // } else { + // // Default + // act = new ChannelAccessLinearActuator(cservice, + // rp.getName(), rp.getDone(), Integer.parseInt(rp.getDoneValue()), + // rp.getDoneDelay(), start, r.getEnd(), + // r.getStepSize(), moveTimeout); + // } + // + // act.setAsynchronous(rp.isAsynchronous()); + // Actor a = act; + // + // ComplexActuator ca = new ComplexActuator(); + // ca.getActors().add(a); + // ca.getPreActions().addAll(mapActions(r.getPreAction())); + // actuator.getActors().add(ca); + // lastRegion = r; + // } else { + // // Function based region + // + // // Cannot check whether the regions are consecutive as + // // the function + // // used might change the start value to something else + // // [THIS LIMITATION NEEDS TO BE SOMEHOW RESOLVED IN THE + // // NEXT VERSIONS] + // JythonFunction function = mapFunction(r.getFunction()); + // ChannelAccessFunctionActuator act; + // if (rp.getType().equals("String")) { + // act = new ChannelAccessFunctionActuator(cservice, + // rp.getName(), rp.getDone(), rp.getDoneValue(), rp.getDoneDelay(), + // function, r.getStart(), r.getEnd(), + // r.getStepSize(), moveTimeout); + // } else if (rp.getType().equals("Double")) { + // act = new ChannelAccessFunctionActuator(cservice, + // rp.getName(), rp.getDone(), Double.parseDouble(rp.getDoneValue()), + // rp.getDoneDelay(), function, r.getStart(), + // r.getEnd(), r.getStepSize(), moveTimeout); + // } else { + // // Default + // act = new ChannelAccessFunctionActuator(cservice, + // rp.getName(), rp.getDone(), Integer.parseInt(rp.getDoneValue()), + // rp.getDoneDelay(), function, r.getStart(), + // r.getEnd(), r.getStepSize(), moveTimeout); + // } + // + // act.setAsynchronous(rp.isAsynchronous()); + // Actor a = act; + // + // ComplexActuator ca = new ComplexActuator(); + // ca.getActors().add(a); + // ca.getPreActions().addAll(mapActions(r.getPreAction())); + // actuator.getActors().add(ca); + // lastRegion = r; + // } + // } + // aLoop.getActors().add(actuator); + // + // // Add a sensor for the readback + // String name = rp.getReadback(); + // if (name == null) { + // name = rp.getName(); + // } + // ChannelAccessDoubleSensor sensor = new + // ChannelAccessDoubleSensor(cservice, rp.getId(), name); + // aLoop.getSensors().add(sensor); + // } else if (p instanceof PseudoPositioner) { + // PseudoPositioner pp = (PseudoPositioner) p; + // PseudoActuatorSensor actorSensor = new + // PseudoActuatorSensor(pp.getId(), pp.getCounts()); + // + // // Register as actor + // aLoop.getActors().add(actorSensor); + // + // // Register as sensor + // aLoop.getSensors().add(actorSensor); + // } else { + // // Not supported + // logger.warning("Mapping for " + p.getClass().getName() + + // " not available"); + // } + // } + } + + /** + * Get unique variable names that do not collide with others. (at least have + * an extreme unlikeness to do so) + * + * @return + */ + private String getUniqueVariableName() { + return "v" + UUID.randomUUID().toString().replaceAll("-", ""); } /** - * Get unique variable names that do not collide with others. (at least have an extreme unlikeness to do so) + * Get the string representation for a variable in python + * i.e. surrounds String with '', ensures that double has a . in the value, ... + * @param value + * @param type * @return */ - private String getUniqueVariableName(){ - return "v"+UUID.randomUUID().toString().replaceAll("-", ""); + private String getPythonValue(String value, Class type){ + if(type.equals(String.class)){ + return "'"+value+"'"; + } + else if(type.equals(Double.class)){ + return String.format("%f", new Double(value)); + } + else if(type.equals(Integer.class)){ + return String.format("%d", new Integer(value)); + } + return value.toString(); + } + + /** + * Request resource + * + * @param resourceId + * @return variable name for resource + * + * TODO Eventually we need to add type of resource here to be able + * to generate the resource before the script is executed. + */ + private String getChannelResourceVariable(String channelName, Class type, boolean monitor) { + // Right now each a new channel object will be created for each requirested channel resource (even it is the same channel) + // TODO Optimize the resource consumption by checking whether the resource already exists and return only one reference. + String varname = getUniqueVariableName(); + resourceDescriptors.put(varname, new ChannelDescriptor<>(type, channelName, monitor)); + return varname; } -// -// String operation = ca.getOperation(); // Default = put -// String type=ca.getType(); // Default = String -// -// if(operation.equals("put")){ -// Long timeout = null; -// if(ca.getTimeout()!=null){ -// timeout = Math.round(ca.getTimeout()*1000); -// } -// if(type.equals("String")){ -// alist.add(new ChannelAccessPut(cservice, ca.getChannel(), ca.getValue(), false, timeout)); -// } -// else if(type.equals("Integer")){ -// alist.add(new ChannelAccessPut(cservice, ca.getChannel(), new Integer(ca.getValue()), false, timeout)); -// } -// else if(type.equals("Double")){ -// alist.add(new ChannelAccessPut(cservice, ca.getChannel(), new Double(ca.getValue()), false, timeout)); -// } -// } -// else if(operation.equals("putq")){ -// if(type.equals("String")){ -// alist.add(new ChannelAccessPut(cservice, ca.getChannel(), ca.getValue(), true, null)); -// } -// else if(type.equals("Integer")){ -// alist.add(new ChannelAccessPut(cservice, ca.getChannel(), new Integer(ca.getValue()), true, null)); -// } -// else if(type.equals("Double")){ -// alist.add(new ChannelAccessPut(cservice, ca.getChannel(), new Double(ca.getValue()), true, null)); -// } -// } -// else if(operation.equals("wait")){ -// Long timeout = null ; // Default timeout = wait forever -// if(ca.getTimeout()!=null){ -// timeout = Math.round(ca.getTimeout()*1000); -// } -// if(type.equals("String")){ -// alist.add(new ChannelAccessCondition(cservice, ca.getChannel(), ca.getValue(), timeout)); -// } -// else if(type.equals("Integer")){ -// alist.add(new ChannelAccessCondition(cservice, ca.getChannel(), new Integer(ca.getValue()), timeout)); -// } -// else if(type.equals("Double")){ -// alist.add(new ChannelAccessCondition(cservice, ca.getChannel(), new Double(ca.getValue()), timeout)); -// } -// } -// else if(operation.equals("waitREGEX")){ -// Long timeout = null ; // Default timeout = wait forever -// if(ca.getTimeout()!=null){ -// timeout = Math.round(ca.getTimeout()*1000); -// } -// if(type.equals("String")){ -// alist.add(new ChannelAccessConditionRegex(cservice, ca.getChannel(), ca.getValue(), timeout)); -// } -// else{ -// logger.warning("Operation "+operation+" wity type "+type+" for action is not supported"); -// } -// } -// else if(operation.equals("waitOR")){ -// Long timeout = null ; // Default timeout = wait forever -// if(ca.getTimeout()!=null){ -// timeout = Math.round(ca.getTimeout()*1000); -// } -// -// if(type.equals("Integer")){ -// alist.add(new ChannelAccessConditionOr(cservice, ca.getChannel(), new Integer(ca.getValue()), timeout)); -// } -// else{ -// logger.warning("Operation "+operation+" wity type "+type+" for action is not supported"); -// } -// } -// else if(operation.equals("waitAND")){ -// Long timeout = null ; // Default timeout = wait forever -// if(ca.getTimeout()!=null){ -// timeout = Math.round(ca.getTimeout()*1000); -// } -// if(type.equals("Integer")){ -// alist.add(new ChannelAccessConditionAnd(cservice, ca.getChannel(), new Integer(ca.getValue()), timeout)); -// } -// else { -// logger.warning("Operation "+operation+" wity type "+type+" for action is not supported"); -// } -// } -// else{ -// // Operation not supported -// logger.warning("Operation "+operation+" for action is not supported"); -// } -// -// // Translate delay attribute to delay action -// if(ca.getDelay()!=null){ -// Double x = ca.getDelay()*1000; -// alist.add(new Delay(x.longValue())); -// } -// -//} - } diff --git a/ch.psi.fda/src/main/java/ch/psi/fda/aq/ShellDescriptor.java b/ch.psi.fda/src/main/java/ch/psi/fda/aq/ShellDescriptor.java new file mode 100644 index 0000000..a1f8e0a --- /dev/null +++ b/ch.psi.fda/src/main/java/ch/psi/fda/aq/ShellDescriptor.java @@ -0,0 +1,28 @@ +/** + * + * Copyright 2013 Paul Scherrer Institute. All rights reserved. + * + * This code is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * This code is distributed in the hope that it will be useful, but without any + * warranty; without even the implied warranty of merchantability or fitness for + * a particular purpose. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this code. If not, see . + * + */ +package ch.psi.fda.aq; + +/** + * Resource descriptor of an operating system shell. + * @author ebner + * + */ +public class ShellDescriptor { + +} diff --git a/ch.psi.fda/src/main/java/ch/psi/fda/aq/ShellResource.java b/ch.psi.fda/src/main/java/ch/psi/fda/aq/ShellResource.java new file mode 100644 index 0000000..14f15ca --- /dev/null +++ b/ch.psi.fda/src/main/java/ch/psi/fda/aq/ShellResource.java @@ -0,0 +1,59 @@ +/** + * + * Copyright 2013 Paul Scherrer Institute. All rights reserved. + * + * This code is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * This code is distributed in the hope that it will be useful, but without any + * warranty; without even the implied warranty of merchantability or fitness for + * a particular purpose. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this code. If not, see . + * + */ +package ch.psi.fda.aq; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.logging.Logger; + +/** + * @author ebner + * + */ +public class ShellResource { + + private static final Logger logger = Logger.getLogger(ShellResource.class.getName()); + + public void execute(String script, int returnValue, boolean checkReturnValue){ + ProcessBuilder pb = new ProcessBuilder(new String[]{"/bin/bash","-c",script}); + pb.redirectErrorStream(true); + + try { + Process p = pb.start(); + int rvalue = p.waitFor(); + + BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream())); + String line = null; + while((line=reader.readLine()) != null){ + logger.info(line); + } + + // Check return value if need to be checked + if(checkReturnValue){ + if(rvalue != returnValue){ + throw new RuntimeException("Executing script "+script+" failed"); + } + } + } catch (IOException | InterruptedException e) { + throw new RuntimeException("Unable to execute script", e); + } + } + +} diff --git a/ch.psi.fda/src/test/java/ch/psi/fda/aq/AcquisitionEngineNGTest.java b/ch.psi.fda/src/test/java/ch/psi/fda/aq/AcquisitionEngineNGTest.java index ba5387a..b13aad0 100644 --- a/ch.psi.fda/src/test/java/ch/psi/fda/aq/AcquisitionEngineNGTest.java +++ b/ch.psi.fda/src/test/java/ch/psi/fda/aq/AcquisitionEngineNGTest.java @@ -18,17 +18,27 @@ */ package ch.psi.fda.aq; -import static org.junit.Assert.*; +import java.util.logging.Logger; import org.junit.After; import org.junit.Before; import org.junit.Test; +import ch.psi.fda.TestChannels; +import ch.psi.fda.model.v1.ChannelAction; +import ch.psi.fda.model.v1.Configuration; +import ch.psi.fda.model.v1.Scan; +import ch.psi.fda.model.v1.ScriptAction; +import ch.psi.fda.model.v1.ShellAction; +import ch.psi.jcae.impl.DefaultChannelService; + /** * @author ebner * */ public class AcquisitionEngineNGTest { + + private static final Logger logger = Logger.getLogger(AcquisitionEngineNGTest.class.getName()); private AcquisitionEngineNG engine; @@ -37,7 +47,7 @@ public class AcquisitionEngineNGTest { */ @Before public void setUp() throws Exception { - engine = new AcquisitionEngineNG(); + engine = new AcquisitionEngineNG(new DefaultChannelService()); } /** @@ -51,10 +61,50 @@ public class AcquisitionEngineNGTest { * Test method for {@link ch.psi.fda.aq.AcquisitionEngineNG#execute(java.lang.String)}. */ @Test - public void testExecute() { -// engine.execute("import os"); - engine.execute("print 'hello'"); -// engine.execute("os.system('echo hello world this is a test')"); + public void testExecuteChannelAction() { + + Configuration config = new Configuration(); + config.setScan(new Scan()); + + // Set value + ChannelAction ca = new ChannelAction(); + ca.setChannel(TestChannels.ANALOG_OUT); + ca.setValue("12"); + ca.setType("Double"); + ca.setDelay(1.2); + + config.getScan().getPreAction().add(ca); + + // Wait for value + ca = new ChannelAction(); + ca.setChannel(TestChannels.ANALOG_OUT); + ca.setValue("13"); + ca.setOperation("wait"); + ca.setTimeout(10.0); + ca.setType("Double"); + + config.getScan().getPreAction().add(ca); + + + ScriptAction sa = new ScriptAction(); + sa.setScript("for i in range(0, 3):\n logger.info('hello %d' %i)\n"); + + ShellAction a = new ShellAction(); + a.setCommand("echo hello world this is a test"); +// a.setExitValue(1); + + config.getScan().getPostAction().add(sa); + config.getScan().getPostAction().add(a); + + + ScanMapperNG mapper = new ScanMapperNG(); + mapper.map(config); + + logger.info("Resources to create: "+mapper.getResourceDescriptors()); + logger.info("Script to execute: "+mapper.getScript()); + + + engine.execute(mapper.getResourceDescriptors(), mapper.getScript()); } } diff --git a/ch.psi.fda/src/test/java/ch/psi/fda/aq/ScanMapperNGTest.java b/ch.psi.fda/src/test/java/ch/psi/fda/aq/ScanMapperNGTest.java index 29ed1af..a123b4a 100644 --- a/ch.psi.fda/src/test/java/ch/psi/fda/aq/ScanMapperNGTest.java +++ b/ch.psi.fda/src/test/java/ch/psi/fda/aq/ScanMapperNGTest.java @@ -27,6 +27,7 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; +import ch.psi.fda.model.v1.ChannelAction; import ch.psi.fda.model.v1.Configuration; import ch.psi.fda.model.v1.DiscreteStepDimension; import ch.psi.fda.model.v1.Scan; @@ -62,17 +63,19 @@ public class ScanMapperNGTest { */ @Test public void testMap() { - System.out.println("juhu"+("This is a Java string".hashCode())); - Configuration config = new Configuration(); config.setScan(new Scan()); ShellAction a = new ShellAction(); a.setCommand("echo hello world this is a test"); + + ChannelAction ca = new ChannelAction(); + ca.setValue("hossa"); + ca.setDelay(1.2); config.getScan().getPreAction().add(a); - + config.getScan().getPreAction().add(ca); ScriptAction sa = new ScriptAction(); sa.setScript("print 'hello'"); @@ -80,6 +83,7 @@ public class ScanMapperNGTest { config.getScan().getPostAction().add(sa); config.getScan().getPostAction().add(a); + DiscreteStepDimension d = new DiscreteStepDimension(); d.getPreAction().add(a); d.getAction().add(sa);