62 Commits

Author SHA1 Message Date
a40573d320 Cleaned up injects, added ZMQ streaming and viewer 2013-11-27 09:55:14 +01:00
70089581c4 First version with asynchronous execution 2013-10-24 10:03:23 +02:00
08cbd0bad0 got first working version of REST server 2013-10-24 08:38:33 +02:00
f4d5102ea3 Implemented REST API and server for executing scans 2013-10-23 15:16:49 +02:00
e483f90837 remove comments 2013-10-23 11:55:41 +02:00
795b269bd0 minor changes 2013-10-21 13:21:01 +02:00
3cb7458e64 removed comment 2013-10-21 12:40:04 +02:00
51d7b36219 Probably fixed CRLOGIC thing as such ... 2013-10-21 11:49:29 +02:00
67e7f9a6c8 fixed scrlogic 2013-10-21 10:59:11 +02:00
491812ddeb fixed otf code 2013-10-21 09:45:06 +02:00
40cc7f6a31 fixed stuff for the new data transfer format 2013-10-21 08:41:22 +02:00
9386f42d06 Somehow works better than before 2013-10-17 08:59:33 +02:00
855535134e Got Visualization work 2013-10-17 07:55:49 +02:00
e2921ff1f4 fixed lots of stuff regarding new message format ... 2013-10-17 07:35:28 +02:00
36cd4335ab Preparation for reworking messaging format 2013-10-16 11:30:38 +02:00
d92534ec37 Removed unnecessary function parameter 2013-10-16 10:54:47 +02:00
ca871ad478 some cleanup in CRLOGIC 2013-10-15 16:13:08 +02:00
b65764ac57 removed injection classes/libraries as not needed 2013-10-15 15:55:47 +02:00
63e681c3bb update version and added configuration for single jar 2013-10-15 15:53:41 +02:00
48cda75405 removed unecessary JythonGlobalVariableDictionary class 2013-10-15 09:40:14 +02:00
4b615d29a6 Cleanup and restructuring notification agent 2013-10-15 08:44:18 +02:00
d8f1e2d8f1 see commit before 2013-10-15 08:26:03 +02:00
768ea9f254 Cleanup Crlogic code 2013-10-14 16:42:00 +02:00
2cba6e7991 Cleanup OTF scan 2013-10-14 16:10:54 +02:00
cb6ec74859 cleanup ... 2013-10-14 13:21:25 +02:00
36f717c8bf more cleanup 2013-10-14 13:06:50 +02:00
716eeba98b cleanup comments 2013-10-14 12:57:21 +02:00
c1c8170f36 Restructuring code 2013-10-14 12:54:57 +02:00
c8031db1fd Cleanup ChannelAccessCondition* classes 2013-10-14 11:31:29 +02:00
a2d9216e84 Removed destroy() method from actuator and action interface 2013-10-14 11:06:55 +02:00
57eca36d27 Cleaned up code
Removed lots of duplicated code, merged classes, etc.
2013-10-14 10:34:40 +02:00
809caa3ed1 Fixed tests 2013-10-09 11:23:34 +02:00
3532f95acb Renamed template files 2013-10-09 09:23:37 +02:00
5d2c2b94d6 Fixed remaining broken tests 2013-10-09 09:15:59 +02:00
2520573d12 Exchanged Channel Access library with latest version
Fixing of the code is still going on!
2013-10-08 16:36:17 +02:00
97ab9fa5b2 Removed unnecessary dependency 2013-10-04 14:39:15 +02:00
debc54a28a do not execute the test case 2013-10-04 14:12:52 +02:00
55ed5ac764 Upgraded mail libraries to latest version 2013-10-04 14:12:18 +02:00
84c86b8d9f cleanup comments 2013-10-04 13:37:03 +02:00
b38654056b minor comments cleanup 2013-10-04 13:22:38 +02:00
5660fafe25 Fixed bug regarding the execution of manipulations 2013-10-04 13:03:34 +02:00
bf3535a9b5 optimized data flow for scans without manipulations 2013-10-04 11:27:40 +02:00
b9c15b0fc8 Added EventBus to collector 2013-10-04 11:16:08 +02:00
83dd7654ed small changes before messingup with guice 2013-10-03 16:19:09 +02:00
e723f66df3 More cleanup 2013-10-03 14:24:17 +02:00
1574dcc7bb Cleanup 2013-10-03 14:20:24 +02:00
1de3b6c14e Cleanup 2013-10-03 13:55:34 +02:00
2a6018c4f5 Fixed all compile problems and migrated all serializers and
deserializers to Guava EventBus.
2013-10-03 13:44:08 +02:00
c3238e4d22 Unfinished removal of the dispatcher class. tested the migration of the
serializer to EventBus.
Test is/was successfull but things now need to be cleaned up properly!
There are various compilation errors in the code
2013-10-03 10:57:20 +02:00
4045873135 Moved on to google guava EventBus for visualizer ... 2013-10-03 10:30:29 +02:00
3e38e4002d Experiment with zmq pub/sub for visualization.
- after the scan somehow the zmq library still takes 100% CPU time -
very strange
2013-10-03 09:30:36 +02:00
0958b76bb0 cleanup conversion class 2013-10-02 13:52:44 +02:00
eaffe7ff91 Fixed compiler warnings 2013-10-02 13:49:29 +02:00
70cb7a8939 removed obsolete functionality
upgraded to java 1.7 and set project encoding to UTF-8
2013-10-02 13:30:50 +02:00
0b9ee77f76 Merge branch 'master' into 1.0.0 2013-10-02 13:05:36 +02:00
81af4449dc FDA-81
Reverted change that filename inside xml always matches that actual
filename.
2013-09-30 08:38:12 +02:00
858d8dbd45 New version 2013-09-25 09:02:41 +02:00
879ec1d657 FDA-27
added datafile and filename to script actions
2013-09-23 15:34:31 +02:00
3025f597c0 FDA-27
Have filename available for manipulations
2013-09-23 13:18:29 +02:00
73107a4799 Always ensure that filename and name of the file inside the xml are
consistent!
Issue FDA-35
2013-09-23 10:56:20 +02:00
a5da9a2527 Issue FDA-35
Now the (file)name inside the xml file is always the same as the
filename of the xml file
2013-09-23 10:49:09 +02:00
21d935e35e Issue FDA-79
Removed restriction for manipulation
2013-09-23 09:55:41 +02:00
157 changed files with 5362 additions and 10767 deletions

View File

@@ -0,0 +1,3 @@
eclipse.preferences.version=1
encoding//src/main/java=UTF-8
encoding//src/test/java=UTF-8

View File

@@ -3,9 +3,41 @@
<modelVersion>4.0.0</modelVersion>
<groupId>ch.psi</groupId>
<artifactId>fda</artifactId>
<version>2.0.0</version>
<version>1.1.41</version>
<dependencies>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-grizzly2-http</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-sse</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>org.jeromq</groupId>
<artifactId>jeromq</artifactId>
<version>0.2.0</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>15.0</version>
</dependency>
<dependency>
<groupId>ch.psi</groupId>
<artifactId>jcae</artifactId>
@@ -15,7 +47,7 @@
<dependency>
<groupId>ch.psi</groupId>
<artifactId>plot</artifactId>
<version>1.1.30</version>
<version>1.1.31</version>
</dependency>
<!-- Java SMB/CIFS library -->
<dependency>
@@ -32,7 +64,6 @@
<dependency>
<groupId>org.python</groupId>
<artifactId>jython</artifactId>
<!-- <artifactId>jython-standalone</artifactId> -->
<version>2.5.3</version>
</dependency>
<!-- CLI Libraries -->
@@ -49,9 +80,9 @@
</dependency>
<!-- Mail Libraries -->
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4.1</version>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
<version>1.5.0</version>
</dependency>
<!-- Library for reading/writing XDR Format (MDA) -->
<dependency>
@@ -59,51 +90,13 @@
<artifactId>freehep-xdr</artifactId>
<version>2.0.4</version>
</dependency>
<!-- JUnit test library -->
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<version>3.0</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>14.0.1</version>
</dependency>
<dependency>
<scope>test</scope>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<version>4.8.2</version>
<scope>test</scope>
</dependency>
<!-- For Testing NG functionality purposes -->
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-grizzly2-http</artifactId>
<version>2.0</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-sse</artifactId>
<version>2.0</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>2.0</version>
</dependency>
<dependency>
<groupId>commons-cli</groupId>
<artifactId>commons-cli</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
<build>
@@ -112,6 +105,7 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<encoding>UTF-8</encoding>
<source>1.7</source>
<target>1.7</target>
</configuration>
@@ -225,6 +219,23 @@
</lifecycleMappingMetadata>
</configuration>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<finalName>${project.name}-${project.version}</finalName>
<appendAssemblyId>false</appendAssemblyId>
<archive>
<!-- <manifest>
<mainClass>ch.psi.fda.AcquisitionMain</mainClass>
</manifest> -->
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>

View File

@@ -17,7 +17,7 @@
*
*/
package ch.psi.fda.aq;
package ch.psi.fda;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
@@ -27,6 +27,7 @@ import java.awt.event.WindowEvent;
import java.io.File;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -47,10 +48,14 @@ import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import com.google.common.eventbus.AsyncEventBus;
import com.google.common.eventbus.EventBus;
import sun.misc.Signal;
import sun.misc.SignalHandler;
import ch.psi.fda.core.messages.DataQueue;
import ch.psi.fda.aq.Acquisition;
import ch.psi.fda.aq.AcquisitionConfiguration;
import ch.psi.fda.aq.VisualizationMapper;
import ch.psi.fda.gui.ProgressPanel;
import ch.psi.fda.gui.ScrollableFlowPanel;
import ch.psi.fda.install.ApplicationConfigurator;
@@ -58,16 +63,14 @@ import ch.psi.fda.model.ModelManager;
import ch.psi.fda.model.v1.Configuration;
import ch.psi.fda.model.v1.Data;
import ch.psi.fda.visualizer.Visualizer;
import ch.psi.jcae.impl.DefaultChannelService;
/**
* Main class for data acquisition
* @author ebner
*
* Entry class for command line based data acquisition
*/
@SuppressWarnings("restriction")
public class AcquisitionMain {
// Get Logger
private static Logger logger = Logger.getLogger(AcquisitionMain.class.getName());
private static boolean abortedViaSignal = false;
@@ -128,10 +131,6 @@ public class AcquisitionMain {
System.exit(0);
}
// Check whether exactly one file is specified
// if(line.getArgs().length>1){
// throw new ParseException("Only up to one argument is supported");
// }
if(line.getArgs().length<1){
throw new ParseException("One argument is required");
}
@@ -207,22 +206,13 @@ public class AcquisitionMain {
ApplicationConfigurator ac = new ApplicationConfigurator();
ac.initializeApplication();
// Read in base configuration
// AcquisitionEngineConfiguration configuration = AcquisitionEngineConfiguration.getInstance();
if(!file.exists()){
throw new RuntimeException("File "+file.getAbsolutePath()+" does not exist");
}
Configuration c;
try {
if(file.getName().endsWith(".xsl")){
c = ModelManager.unmarshall(file, variables);
}
else{
c = ModelManager.unmarshall(file);
}
c = ModelManager.unmarshall(file);
} catch (Exception e) {
throw new RuntimeException("Unable to deserialize configuration: "+e.getMessage(), e);
}
@@ -256,7 +246,7 @@ public class AcquisitionMain {
}
// Create/get acquisition engine
final Acquisition acquisition = new Acquisition();
final Acquisition acquisition = new Acquisition(new DefaultChannelService(), new AcquisitionConfiguration());
boolean vis = false;
// Only register data visualization task/processor if there are visualizations
@@ -264,12 +254,20 @@ public class AcquisitionMain {
vis=true;
}
DataQueue vdq = acquisition.initalize(c, vis);
EventBus b = new AsyncEventBus(Executors.newSingleThreadExecutor());
acquisition.initalize(b, c);
Visualizer visualizer = null;
// Only register data visualization task/processor if there are visualizations
if(vis){
visualizer = new Visualizer(vdq, c.getVisualization());
visualizer = new Visualizer(VisualizationMapper.mapVisualizations(c.getVisualization()));
b.register(visualizer);
// TODO eventually set update on delimiter/dim boundary here
// If there is a continous dimension only update plot at the end of a line
if(c.getScan() != null && c.getScan().getCdimension()!=null){
visualizer.setUpdateAtStreamElement(false);
@@ -317,7 +315,6 @@ public class AcquisitionMain {
splitPane.setRightComponent(tpane);
frame.add(splitPane);
// frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.addWindowListener(new WindowAdapter(){
@Override
public void windowClosing(WindowEvent we){
@@ -403,16 +400,11 @@ public class AcquisitionMain {
try {
if(visualizer != null){
// Start visualization
visualizer.startVisualization();
visualizer.configure();
}
acquisition.execute();
if(visualizer != null){
// Stop visualization
visualizer.stopVisualization();
}
} catch (InterruptedException e1) {
throw new RuntimeException("Acquisition was interrupted",e1);
}

View File

@@ -17,7 +17,7 @@
*
*/
package ch.psi.fda.co;
package ch.psi.fda;
import java.io.File;
import java.io.PrintWriter;
@@ -33,6 +33,8 @@ import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import com.google.common.eventbus.EventBus;
import ch.psi.fda.deserializer.DataDeserializer;
import ch.psi.fda.deserializer.DataDeserializerMDA;
import ch.psi.fda.deserializer.DataDeserializerTXT;
@@ -46,24 +48,15 @@ import ch.psi.fda.serializer.DataSerializerTXT2D;
import ch.psi.fda.serializer.DataSerializerTXTSplit;
/**
* Visualize data according to the scan description
*
* @author ebner
*
* Converter to convert the format of datafiles
*/
public class ConversionEngine {
public class ConversionMain {
// Get Logger
private static Logger logger = Logger.getLogger(ConversionEngine.class.getName());
private static Logger logger = Logger.getLogger(ConversionMain.class.getName());
public enum Writer {TXT, TXT_2D, TXT_SPLIT, MAT, MAT_2D, MDA, MAT_2D_Z};
public enum Reader {TXT, MDA};
/**
* Default constructor
*/
public ConversionEngine(){
}
/**
* Visualize data
@@ -89,14 +82,17 @@ public class ConversionEngine {
else if(output.exists()){
throw new IllegalArgumentException("Output file ["+output.getAbsolutePath()+"] already exists");
}
EventBus bus = new EventBus();
// Create deserializer
DataDeserializer deserializer;
if(reader.equals(Reader.TXT)){
deserializer = new DataDeserializerTXT(input);
deserializer = new DataDeserializerTXT(bus, input);
}
else if(reader.equals(Reader.MDA)){
deserializer = new DataDeserializerMDA(input);
deserializer = new DataDeserializerMDA(bus, input);
}
else{
throw new IllegalArgumentException("Reader of type "+reader+" not supported.");
@@ -104,39 +100,33 @@ public class ConversionEngine {
DataSerializer serializer;
if(writer.equals(Writer.MAT)){
serializer = new DataSerializerMAT(deserializer.getQueue(), output);
serializer = new DataSerializerMAT(output);
}
else if(writer.equals(Writer.MAT_2D)){
serializer = new DataSerializerMAT2D(deserializer.getQueue(), output);
serializer = new DataSerializerMAT2D(output);
}
else if(writer.equals(Writer.TXT)){
serializer = new DataSerializerTXT(deserializer.getQueue(), output, false);
serializer = new DataSerializerTXT(output, false);
}
else if(writer.equals(Writer.TXT_2D)){
serializer = new DataSerializerTXT2D(deserializer.getQueue(), output);
serializer = new DataSerializerTXT2D(output);
}
else if(writer.equals(Writer.TXT_SPLIT)){
serializer = new DataSerializerTXTSplit(deserializer.getQueue(), output);
serializer = new DataSerializerTXTSplit(output);
}
else if(writer.equals(Writer.MDA)){
serializer = new DataSerializerMDA(deserializer.getQueue(), output);
serializer = new DataSerializerMDA(output);
}
else if(writer.equals(Writer.MAT_2D_Z)){
serializer = new DataSerializerMAT2DZigZag(deserializer.getQueue(), output);
serializer = new DataSerializerMAT2DZigZag(output);
}
else{
throw new IllegalArgumentException("Writer of type "+writer+" not supported.");
}
// Start deserializer and serializer
Thread td = new Thread(deserializer);
Thread ts = new Thread(serializer);
td.start();
ts.start();
td.join();
ts.join();
// Start conversion
bus.register(serializer);
deserializer.read();
}
/**
@@ -243,7 +233,7 @@ public class ConversionEngine {
System.exit(-1);
}
ConversionEngine e = new ConversionEngine();
ConversionMain e = new ConversionMain();
try{
e.convert(infile, outfile, reader, writer);
}

View File

@@ -0,0 +1,162 @@
/**
*
* Copyright 2010 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 <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda;
import java.awt.FlowLayout;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.ScrollPaneLayout;
import org.jeromq.ZMQ;
import com.google.common.eventbus.EventBus;
import ch.psi.fda.gui.ScrollableFlowPanel;
import ch.psi.fda.visualizer.SeriesDataFilter;
import ch.psi.fda.visualizer.Visualizer;
import ch.psi.fda.visualizer.XYSeriesDataFilter;
import ch.psi.plot.xy.LinePlot;
/**
* Visualize data according to the scan description
*/
public class ViewerMain {
private static Logger logger = Logger.getLogger(ViewerMain.class.getName());
/**
* Visualize data
* @param configuration
* @param data
* @throws InterruptedException
*/
public void visualize() throws InterruptedException{
List<SeriesDataFilter> filters = new ArrayList<>();
filters.add(new XYSeriesDataFilter("id0", "timestamp", new LinePlot("One")));
Visualizer visualizer = new Visualizer(filters);
// visualizer.setTerminateAtEOS(true);
// Adapt default visualizer behavior to optimize performance for visualization
visualizer.setUpdateAtStreamElement(true);
visualizer.setUpdateAtStreamDelimiter(true);
visualizer.setUpdateAtEndOfStream(true);
JPanel opanel = new ScrollableFlowPanel();
opanel.setLayout(new FlowLayout());
JScrollPane spane = new JScrollPane(opanel, ScrollPaneLayout.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneLayout.HORIZONTAL_SCROLLBAR_NEVER);
JTabbedPane tpane = new JTabbedPane();
tpane.addTab("Overview", spane);
for (JPanel p : visualizer.getPlotPanels()) {
opanel.add(p);
}
final JFrame frame = new JFrame();
frame.setSize(1200,800);
frame.add(tpane);
// frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.addWindowListener(new WindowAdapter(){
@Override
public void windowClosing(WindowEvent we){
System.exit(0);
}
});
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);//.DO_NOTHING_ON_CLOSE);
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
frame.setVisible(true);
}
});
// Start receiving messages
EventBus bus = new EventBus();
bus.register(visualizer);
visualizer.configure();
ZMQ.Context context = ZMQ.context();
zmq.ZError.clear(); // Clear error code
ZMQ.Socket socket = context.socket(ZMQ.SUB);
socket.connect("tcp://emac:10000");
socket.subscribe(""); // SUBSCRIBE !
while(true){
byte[] content = null;
// String header = socket.recvStr(); // header
socket.recvStr(); // header
while(socket.hasReceiveMore()){
content = socket.recv();
}
if(content==null){ // we lost something discard read messages
logger.warning("Lost some message - discard and continue");
continue;
}
try (
ByteArrayInputStream bis = new ByteArrayInputStream(content);
ObjectInput in = new ObjectInputStream(bis);
) {
Object o = in.readObject();
bus.post(o);
} catch (IOException | ClassNotFoundException e) {
logger.log(Level.WARNING,"Unable to deserialize message",e);
}
}
}
/**
* This method accepts a data file and an option (-file) specifying the scan configuration file
* used for creating the data file. If no option is specified the configuration file is derived by the
* data file name.
*
* @param args Command line arguments
*/
public static void main(String[] args) {
try{
ViewerMain e = new ViewerMain();
e.visualize();
}
catch(Exception ee){
System.out.println("Visualization failed due to: "+ee.getMessage());
logger.log(Level.WARNING, "Visualization failed due to Exception:", ee);
System.exit(-1);
}
}
}

View File

@@ -17,13 +17,14 @@
*
*/
package ch.psi.fda.vis;
package ch.psi.fda;
import java.awt.FlowLayout;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.PrintWriter;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -44,6 +45,10 @@ import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.xml.sax.SAXException;
import com.google.common.eventbus.AsyncEventBus;
import com.google.common.eventbus.EventBus;
import ch.psi.fda.aq.VisualizationMapper;
import ch.psi.fda.deserializer.DataDeserializer;
import ch.psi.fda.deserializer.DataDeserializerTXT;
import ch.psi.fda.gui.ScrollableFlowPanel;
@@ -53,19 +58,15 @@ import ch.psi.fda.visualizer.Visualizer;
/**
* Visualize data according to the scan description
*
* @author ebner
*
*/
public class VisualizationEngine {
public class VisualizationMain {
// Get Logger
private static Logger logger = Logger.getLogger(VisualizationEngine.class.getName());
private static Logger logger = Logger.getLogger(VisualizationMain.class.getName());
/**
* Default constructor
*/
public VisualizationEngine(){
public VisualizationMain(){
}
/**
@@ -112,13 +113,14 @@ public class VisualizationEngine {
throw new IllegalArgumentException("Data file ["+data.getAbsolutePath()+"] does not exist");
}
EventBus bus = new AsyncEventBus(Executors.newCachedThreadPool());
// Create deserializer
DataDeserializer deserializer = new DataDeserializerTXT(data);
DataDeserializer deserializer = new DataDeserializerTXT(bus, data);
// Create Visualizer
Visualizer visualizer = new Visualizer(deserializer.getQueue(), configuration.getVisualization());
Visualizer visualizer = new Visualizer(VisualizationMapper.mapVisualizations(configuration.getVisualization()));
visualizer.setTerminateAtEOS(true);
// visualizer.setTerminateAtEOS(true);
// Adapt default visualizer behavior to optimize performance for visualization
visualizer.setUpdateAtStreamElement(false);
visualizer.setUpdateAtStreamDelimiter(false);
@@ -155,12 +157,10 @@ public class VisualizationEngine {
// Start deserializer and visualizer
Thread td = new Thread(deserializer);
bus.register(visualizer);
visualizer.configure();
deserializer.read();
td.start();
visualizer.startVisualization();
td.join();
logger.info("Deserializer finished");
// visualizer.stopVisualization();
}
@@ -215,7 +215,7 @@ public class VisualizationEngine {
System.exit(-1);
}
VisualizationEngine e = new VisualizationEngine();
VisualizationMain e = new VisualizationMain();
try{
e.visualize(cfile, dfile);
}

View File

@@ -24,27 +24,26 @@ import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeoutException;
import java.util.logging.FileHandler;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;
import ch.psi.fda.aq.ng.AcquisitionEngineNG;
import ch.psi.fda.aq.ng.ScanMapperNG;
import com.google.common.eventbus.AsyncEventBus;
import com.google.common.eventbus.EventBus;
import ch.psi.fda.core.ActionLoop;
import ch.psi.fda.core.Actor;
import ch.psi.fda.core.EngineConfiguration;
import ch.psi.fda.core.Manipulation;
import ch.psi.fda.core.Sensor;
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;
@@ -52,35 +51,26 @@ 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.OTFActuator;
import ch.psi.fda.core.actors.PseudoActuatorSensor;
import ch.psi.fda.core.collector.Collector;
import ch.psi.fda.core.collector.DataDispatcher;
import ch.psi.fda.core.guard.ChannelAccessGuard;
import ch.psi.fda.core.guard.ChannelAccessGuardCondition;
import ch.psi.fda.core.loops.ActorSensorLoop;
import ch.psi.fda.core.loops.OTFLoop;
import ch.psi.fda.core.loops.cr.CrlogicLoop;
import ch.psi.fda.core.loops.cr.CrlogicResource;
import ch.psi.fda.core.loops.cr.ParallelCrlogic;
import ch.psi.fda.core.loops.cr.ScrlogicLoop;
import ch.psi.fda.core.loops.otf.OTFLoop;
import ch.psi.fda.core.loops.otf.OTFNamedChannelSensor;
import ch.psi.fda.core.loops.otf.OTFScalerChannelSensor;
import ch.psi.fda.core.loops.otf.TemplateOTF;
import ch.psi.fda.core.manipulator.JythonManipulation;
import ch.psi.fda.core.manipulator.Manipulation;
import ch.psi.fda.core.manipulator.Manipulator;
import ch.psi.fda.core.messages.DataQueue;
import ch.psi.fda.core.messages.Message;
import ch.psi.fda.core.scripting.JythonGlobalVariable;
import ch.psi.fda.core.scripting.JythonGlobalVariableDictionary;
import ch.psi.fda.core.scripting.JythonParameterMapping;
import ch.psi.fda.core.scripting.JythonParameterMappingChannel;
import ch.psi.fda.core.scripting.JythonParameterMappingGlobalVariable;
import ch.psi.fda.core.scripting.JythonParameterMappingID;
import ch.psi.fda.core.sensors.ChannelAccessDoubleArraySensor;
import ch.psi.fda.core.sensors.ChannelAccessDoubleSensor;
import ch.psi.fda.core.sensors.ChannelAccessStringSensor;
import ch.psi.fda.core.sensors.MillisecondTimestampSensor;
import ch.psi.fda.core.sensors.OTFNamedChannelSensor;
import ch.psi.fda.core.sensors.OTFReadbackSensor;
import ch.psi.fda.core.sensors.OTFScalerChannelSensor;
import ch.psi.fda.core.sensors.ChannelAccessSensor;
import ch.psi.fda.core.sensors.TimestampSensor;
import ch.psi.fda.model.ModelManager;
import ch.psi.fda.model.v1.Action;
import ch.psi.fda.model.v1.ArrayDetector;
@@ -116,10 +106,15 @@ import ch.psi.fda.model.v1.SimpleScalarDetector;
import ch.psi.fda.model.v1.Timestamp;
import ch.psi.fda.model.v1.Variable;
import ch.psi.fda.model.v1.VariableParameterMapping;
import ch.psi.fda.notification.NotificationAgent;
import ch.psi.fda.serializer.DataSerializerTXT;
import ch.psi.jcae.Channel;
import ch.psi.jcae.ChannelDescriptor;
import ch.psi.jcae.ChannelException;
import ch.psi.jcae.ChannelService;
import ch.psi.jcae.impl.DefaultChannelService;
import ch.psi.jcae.impl.type.DoubleTimestamp;
import ch.psi.jcae.util.ComparatorAND;
import ch.psi.jcae.util.ComparatorOR;
import ch.psi.jcae.util.ComparatorREGEX;
/**
* Data acquisition engine for performing scans
@@ -129,18 +124,11 @@ import ch.psi.jcae.impl.DefaultChannelService;
*/
public class Acquisition {
private static boolean NEW_ENGINE = true;
// Get Logger
private static Logger logger = Logger.getLogger(Acquisition.class.getName());
private AcquisitionEngineConfiguration configuration;
private final AcquisitionConfiguration configuration;
private ActionLoop actionLoop;
private Collector collector;
private ScanMapperNG mapper;
private AcquisitionEngineNG acquisitionEngine;
private DataDispatcher dispatcher;
private Manipulator manipulator;
private DataSerializerTXT serializer;
@@ -151,21 +139,23 @@ public class Acquisition {
private Handler logHandler = null;
private ChannelService cservice;
/**
* Name of the datafile
*/
private File datafile;
// private Thread acquisitionThread = null;
public Acquisition(){
configuration = AcquisitionEngineConfiguration.getInstance();
actionLoop = null;
collector = new Collector();
manipulations = new ArrayList<Manipulation>();
private ChannelService cservice;
private List<Channel<?>> channels = new ArrayList<>();
private List<Object> templates = new ArrayList<>();
private Configuration configModel;
private HashMap<String, JythonGlobalVariable> jVariableDictionary = new HashMap<String, JythonGlobalVariable>();
public Acquisition(ChannelService cservice, AcquisitionConfiguration configuration){
this.cservice = cservice;
this.configuration = configuration;
this.actionLoop = null;
this.manipulations = new ArrayList<Manipulation>();
}
@@ -187,10 +177,8 @@ public class Acquisition {
* @param getQueue Flag whether to return a queue or not. If false the return value of the function will be null.
* @throws InterruptedException
*/
public DataQueue initalize(Configuration smodel, boolean getQueue) {
cservice = new DefaultChannelService();
public void initalize(EventBus bus, Configuration smodel) {
// Create notification agent with globally configured recipients
notificationAgent = new NotificationAgent(configuration.getSmptServer(), "fda.notification@psi.ch");
@@ -243,52 +231,37 @@ public class Acquisition {
throw new RuntimeException("Unable to serialize scan",e);
}
// Configure core engine
EngineConfiguration.getInstance().setFailOnSensorError(smodel.isFailOnSensorError());
if(NEW_ENGINE){
acquisitionEngine = new AcquisitionEngineNG(cservice);
mapper = new ScanMapperNG();
mapper.map(smodel);
this.manipulator = new Manipulator(new DataQueue( acquisitionEngine.getOutQueue(), mapper.getDataMessageMetadata()), this.manipulations);
}
else{
logger.fine("Map Model to internal logic");
logger.fine("Map Model to internal logic");
if(smodel.getScan().getManipulation()!= null && smodel.getScan().getManipulation().size()>0){
// Setup optimized with manipulations
EventBus b = new AsyncEventBus(Executors.newCachedThreadPool());
// Map scan to base model
// After this call actionLoop and collector will be initialized
mapScan(smodel);
Collector collector = new Collector(b);
mapScan(collector, smodel);
// col = collector;
logger.fine("ActionLoop and Collector initialized");
// TODO Remove this workaround
Collections.reverse(collector.getQueues());
// Add manipulator into processing chain
this.manipulator = new Manipulator(collector.getOutQueue(), this.manipulations);
this.manipulator = new Manipulator(bus, this.manipulations);
b.register(this.manipulator);
this.serializer = new DataSerializerTXT(datafile, true);
bus.register(serializer);
}
// // Insert dispatcher into processing chain
this.dispatcher = new DataDispatcher(manipulator.getOutQueue());
DataQueue dq = new DataQueue(new LinkedBlockingQueue<Message>(1000), manipulator.getOutQueue().getDataMessageMetadata()); // Create bounded queue to
// prevent running out of
// memory ...
this.serializer = new DataSerializerTXT(dq, datafile, true);
DataQueue vdq = null;
if (getQueue) {
vdq = new DataQueue(new LinkedBlockingQueue<Message>(1000), manipulator.getOutQueue().getDataMessageMetadata()); // Create bounded queue to prevent
// running out of memory ...
dispatcher.getOutQueues().add(vdq);
else{
// Setup optimized without manipulations
Collector collector = new Collector(bus);
mapScan(collector, smodel);
// col = collector;
this.serializer = new DataSerializerTXT(datafile, true);
bus.register(serializer);
}
// Add queue for serializer to dispatcher
dispatcher.getOutQueues().add(dq);
return (vdq);
}
/**
@@ -297,48 +270,12 @@ public class Acquisition {
*/
public void execute() throws InterruptedException {
// acquisitionThread = Thread.currentThread();
try{
active = true;
Thread tc = null;
if(!NEW_ENGINE){
tc = new Thread(collector);
tc.start();
}
Thread tm = new Thread(manipulator);
tm.start();
Thread td = new Thread(dispatcher);
td.start();
Thread t = new Thread(serializer);
t.start();
if(NEW_ENGINE){
acquisitionEngine.execute(mapper.getResourceDescriptors(), mapper.getScript(), new ArrayList<String>());
}
else {
actionLoop.prepare();
actionLoop.execute();
actionLoop.cleanup();
}
// Wait for data collector threads
// Do this with a Latch or something like that
// Give the threads 1 minute to catch up
if(!NEW_ENGINE){
tc.join(60000);
}
tm.join(60000);
td.join(60000);
t.join(60000);
actionLoop.prepare();
actionLoop.execute();
actionLoop.cleanup();
// Send notifications out to all recipients that want to have success notifications
try {
@@ -347,8 +284,6 @@ public class Acquisition {
} catch (UnknownHostException e1) {
logger.log(Level.WARNING, "Unable to send notification", e1);
}
// active = false;
}
catch(RuntimeException e){
logger.log(Level.WARNING, "Execution failed: ", e);
@@ -383,26 +318,31 @@ public class Acquisition {
public void destroy(){
if(actionLoop != null){
logger.finest("Destroy action loop");
try{
actionLoop.destroy();
logger.finest("Destroy managed resources");
for(Channel<?> c: channels){
try {
c.destroy();
} catch (ChannelException e) {
throw new RuntimeException("Unable to destroy channel "+c.getName(),e);
}
}
catch(Exception e){
logger.log(Level.SEVERE, "Unable to destroy action loop", e);
for(Object o: templates){
try {
cservice.destroyAnnotatedChannels(o);
} catch (ChannelException e) {
throw new RuntimeException("Unable to destroy channels of template: "+o.getClass().getName(), e);
}
}
}
// Clear global variables Jython
JythonGlobalVariableDictionary.getInstance().clear();
jVariableDictionary.clear();
// Destroy the CA context
try {
logger.fine("Destroy Channel Access context");
cservice.destroy();
} catch (IllegalStateException e) {
logger.log(Level.SEVERE, "Unable to destroy channel access context", e);
}
logger.fine("Context destroyed");
// // Destroy the CA context
// cservice.destroy();
// logger.fine("ChannelService destroyed");
// Remove log handler
if(logHandler!=null){
@@ -455,20 +395,21 @@ public class Acquisition {
* Map scan to base model
* @param scan
*/
private void mapScan(Configuration configuration){
private void mapScan(Collector collector, Configuration configuration){
this.configModel = configuration;
Scan scan = configuration.getScan();
// Map continuous dimension
if(scan.getCdimension() != null){
ActionLoop aLoop = mapContinuousDimension(scan.getCdimension());
actionLoop = aLoop;
collector.getQueues().add(aLoop.getDataQueue());
collector.addEventBus(aLoop.getEventBus());
}
// Map discrete step dimensions
for(DiscreteStepDimension d: scan.getDimension()){
ActorSensorLoop l = mapDiscreteStepDimension(d);
collector.getQueues().add(l.getDataQueue());
collector.addEventBus(l.getEventBus());
if(actionLoop != null){
l.getActionLoops().add(actionLoop);
}
@@ -487,6 +428,7 @@ public class Acquisition {
actionLoop.getPostActions().addAll(mapActions(scan.getPostAction()));
// TODO need to be removed! and done differently !!!!
// Handle iterations by adding a pseudo dimension and setting the
// datagroup flag in the main loop
if(configuration.getNumberOfExecution()>1){
@@ -499,11 +441,10 @@ public class Acquisition {
// Set toplevel action loop
actionLoop = l;
collector.getQueues().add(l.getDataQueue());
collector.addEventBus(l.getEventBus());
}
JythonGlobalVariableDictionary dict = JythonGlobalVariableDictionary.getInstance();
// handling manipulations
for(ch.psi.fda.model.v1.Manipulation m : scan.getManipulation()){
if(m instanceof ScriptManipulation){
ScriptManipulation sm = (ScriptManipulation) m;
@@ -517,13 +458,13 @@ public class Acquisition {
else if(pm instanceof ChannelParameterMapping){
ChannelParameterMapping cpm = (ChannelParameterMapping) pm;
if(cpm.getType().equals("String")){
mapping.add( new JythonParameterMappingChannel(cpm.getVariable(), cpm.getChannel(), String.class));
mapping.add( new JythonParameterMappingChannel<String>(cpm.getVariable(), createChannel(String.class, cpm.getChannel())));
}
else if(cpm.getType().equals("Integer")){
mapping.add( new JythonParameterMappingChannel(cpm.getVariable(), cpm.getChannel(), Integer.class));
mapping.add( new JythonParameterMappingChannel<Integer>(cpm.getVariable(), createChannel(Integer.class, cpm.getChannel())));
}
else if(cpm.getType().equals("Double")){
mapping.add( new JythonParameterMappingChannel(cpm.getVariable(), cpm.getChannel(), Double.class));
mapping.add( new JythonParameterMappingChannel<Double>(cpm.getVariable(), createChannel(Double.class, cpm.getChannel())));
}
else{
logger.warning("Channel type ["+cpm.getType()+"] is not supported for mapping");
@@ -532,13 +473,19 @@ public class Acquisition {
else if(pm instanceof VariableParameterMapping){
VariableParameterMapping vp = (VariableParameterMapping) pm;
Variable v = (Variable)vp.getName();
JythonGlobalVariable var = dict.getVariable(v.getName());
JythonGlobalVariable var = jVariableDictionary.get(v.getName());
var.setValue(v.getValue());
mapping.add(new JythonParameterMappingGlobalVariable(vp.getVariable(), var));
}
}
JythonManipulation manipulation = new JythonManipulation(cservice, sm.getId(), sm.getScript(), mapping, sm.isReturnArray());
JythonManipulation manipulation = new JythonManipulation(sm.getId(), sm.getScript(), mapping, sm.isReturnArray());
if(configuration.getData()!=null){ // Safety
manipulation.setVariable("FILENAME", configuration.getData().getFileName());
manipulation.setVariable("DATAFILE", datafile.getAbsoluteFile());
}
this.manipulations.add(manipulation);
}
}
@@ -564,24 +511,24 @@ public class Acquisition {
timeout = Math.round(ca.getTimeout()*1000);
}
if(type.equals("String")){
alist.add(new ChannelAccessPut<String>(cservice, ca.getChannel(), ca.getValue(), false, timeout));
alist.add(new ChannelAccessPut<String>(createChannel(String.class, ca.getChannel()), ca.getValue(), false, timeout));
}
else if(type.equals("Integer")){
alist.add(new ChannelAccessPut<Integer>(cservice, ca.getChannel(), new Integer(ca.getValue()), false, timeout));
alist.add(new ChannelAccessPut<Integer>(createChannel(Integer.class, ca.getChannel()), new Integer(ca.getValue()), false, timeout));
}
else if(type.equals("Double")){
alist.add(new ChannelAccessPut<Double>(cservice, ca.getChannel(), new Double(ca.getValue()), false, timeout));
alist.add(new ChannelAccessPut<Double>(createChannel(Double.class,ca.getChannel()), new Double(ca.getValue()), false, timeout));
}
}
else if(operation.equals("putq")){
if(type.equals("String")){
alist.add(new ChannelAccessPut<String>(cservice, ca.getChannel(), ca.getValue(), true, null));
alist.add(new ChannelAccessPut<String>(createChannel(String.class,ca.getChannel()), ca.getValue(), true, null));
}
else if(type.equals("Integer")){
alist.add(new ChannelAccessPut<Integer>(cservice, ca.getChannel(), new Integer(ca.getValue()), true, null));
alist.add(new ChannelAccessPut<Integer>(createChannel(Integer.class,ca.getChannel()), new Integer(ca.getValue()), true, null));
}
else if(type.equals("Double")){
alist.add(new ChannelAccessPut<Double>(cservice, ca.getChannel(), new Double(ca.getValue()), true, null));
alist.add(new ChannelAccessPut<Double>(createChannel(Double.class,ca.getChannel()), new Double(ca.getValue()), true, null));
}
}
else if(operation.equals("wait")){
@@ -590,13 +537,13 @@ public class Acquisition {
timeout = Math.round(ca.getTimeout()*1000);
}
if(type.equals("String")){
alist.add(new ChannelAccessCondition<String>(cservice, ca.getChannel(), ca.getValue(), timeout));
alist.add(new ChannelAccessCondition<String>(createChannel(String.class,ca.getChannel()), ca.getValue(), timeout));
}
else if(type.equals("Integer")){
alist.add(new ChannelAccessCondition<Integer>(cservice, ca.getChannel(), new Integer(ca.getValue()), timeout));
alist.add(new ChannelAccessCondition<Integer>(createChannel(Integer.class,ca.getChannel()), new Integer(ca.getValue()), timeout));
}
else if(type.equals("Double")){
alist.add(new ChannelAccessCondition<Double>(cservice, ca.getChannel(), new Double(ca.getValue()), timeout));
alist.add(new ChannelAccessCondition<Double>(createChannel(Double.class,ca.getChannel()), new Double(ca.getValue()), timeout));
}
}
else if(operation.equals("waitREGEX")){
@@ -605,7 +552,7 @@ public class Acquisition {
timeout = Math.round(ca.getTimeout()*1000);
}
if(type.equals("String")){
alist.add(new ChannelAccessConditionRegex<String>(cservice, ca.getChannel(), ca.getValue(), timeout));
alist.add(new ChannelAccessCondition<>(createChannel(String.class, ca.getChannel()), ca.getValue(), new ComparatorREGEX(), timeout));
}
else{
logger.warning("Operation "+operation+" wity type "+type+" for action is not supported");
@@ -618,7 +565,7 @@ public class Acquisition {
}
if(type.equals("Integer")){
alist.add(new ChannelAccessConditionOr<Integer>(cservice, ca.getChannel(), new Integer(ca.getValue()), timeout));
alist.add(new ChannelAccessCondition<>(createChannel(Integer.class,ca.getChannel()), new Integer(ca.getValue()), new ComparatorOR(), timeout));
}
else{
logger.warning("Operation "+operation+" wity type "+type+" for action is not supported");
@@ -630,7 +577,7 @@ public class Acquisition {
timeout = Math.round(ca.getTimeout()*1000);
}
if(type.equals("Integer")){
alist.add(new ChannelAccessConditionAnd<Integer>(cservice, ca.getChannel(), new Integer(ca.getValue()), timeout));
alist.add(new ChannelAccessCondition<>(createChannel(Integer.class,ca.getChannel()), new Integer(ca.getValue()), new ComparatorAND(), timeout));
}
else {
logger.warning("Operation "+operation+" wity type "+type+" for action is not supported");
@@ -650,7 +597,9 @@ public class Acquisition {
}
else if(a instanceof ShellAction){
ShellAction sa = (ShellAction) a;
ch.psi.fda.core.actions.ShellAction action = new ch.psi.fda.core.actions.ShellAction(sa.getCommand());
String com = sa.getCommand().replaceAll("\\$\\{DATAFILE\\}", datafile.getAbsolutePath());
com = com.replaceAll("\\$\\{FILENAME\\}", datafile.getName().replaceAll("\\.\\w*$", ""));
ch.psi.fda.core.actions.ShellAction action = new ch.psi.fda.core.actions.ShellAction(com);
action.setCheckExitValue(sa.isCheckExitValue());
action.setExitValue(sa.getExitValue());
alist.add(action);
@@ -658,23 +607,32 @@ public class Acquisition {
else if(a instanceof ScriptAction){
ScriptAction sa = (ScriptAction) a;
// TODO set global variables DATAFILE and FILENAME
// TODO create Jython Action
List<JythonParameterMappingChannel> mapping = new ArrayList<JythonParameterMappingChannel>();
Map<String, Channel<?>> mapping = new HashMap<>();
for(ChannelParameterMapping ma: sa.getMapping()){
if(ma.getType().equals("String")){
mapping.add(new JythonParameterMappingChannel(ma.getVariable(), ma.getChannel(), String.class));
mapping.put(ma.getVariable(), createChannel(String.class, ma.getChannel()));
}
else if(ma.getType().equals("Integer")){
mapping.add(new JythonParameterMappingChannel(ma.getVariable(), ma.getChannel(), Integer.class));
mapping.put(ma.getVariable(), createChannel(Integer.class, ma.getChannel()));
}
else if(ma.getType().equals("Double")){
mapping.add(new JythonParameterMappingChannel(ma.getVariable(), ma.getChannel(), Double.class));
mapping.put(ma.getVariable(), createChannel(Double.class, ma.getChannel()));
}
else{
logger.warning("Channel type ["+ma.getType()+"] is not supported for mapping");
}
}
alist.add(new ch.psi.fda.core.actions.JythonAction(cservice, sa.getScript(), mapping));
Map<String,Object> gobjects = new HashMap<>();
gobjects.put("FILENAME", datafile.getName().replaceAll("\\.\\w*$", ""));
gobjects.put("DATAFILE", datafile.getAbsoluteFile());
ch.psi.fda.core.actions.JythonAction ja = new ch.psi.fda.core.actions.JythonAction(sa.getScript(), mapping, gobjects);
alist.add(ja);
}
}
return(alist);
@@ -693,7 +651,7 @@ public class Acquisition {
// Mapping dimension pre-actions
aLoop.getPreActions().addAll(mapActions(dimension.getPreAction()));
Long moveTimeout = AcquisitionEngineConfiguration.getInstance().getActorMoveTimeout();
Long moveTimeout = this.configuration.getActorMoveTimeout();
// Mapping positioners
Double stime = 0d;
@@ -707,14 +665,14 @@ public class Acquisition {
LinearPositioner lp =(LinearPositioner) p;
ChannelAccessLinearActuator<?> a;
if(lp.getType().equals("String")){
a = new ChannelAccessLinearActuator<String>(cservice, lp.getName(), lp.getDone(), lp.getDoneValue(), lp.getDoneDelay(), lp.getStart(), lp.getEnd(), lp.getStepSize(), moveTimeout);
a = new ChannelAccessLinearActuator<String>(createChannel(Double.class, lp.getName()), createChannel(String.class, lp.getDone()), lp.getDoneValue(), lp.getDoneDelay(), lp.getStart(), lp.getEnd(), lp.getStepSize(), moveTimeout);
}
else if(lp.getType().equals("Double")){
a = new ChannelAccessLinearActuator<Double>(cservice, lp.getName(), lp.getDone(), Double.parseDouble(lp.getDoneValue()), lp.getDoneDelay(), lp.getStart(), lp.getEnd(), lp.getStepSize(), moveTimeout);
a = new ChannelAccessLinearActuator<Double>(createChannel(Double.class, lp.getName()), createChannel(Double.class,lp.getDone()), Double.parseDouble(lp.getDoneValue()), lp.getDoneDelay(), lp.getStart(), lp.getEnd(), lp.getStepSize(), moveTimeout);
}
else{
// Default
a = new ChannelAccessLinearActuator<Integer>(cservice, lp.getName(), lp.getDone(), Integer.parseInt(lp.getDoneValue()), lp.getDoneDelay(), lp.getStart(), lp.getEnd(), lp.getStepSize(), moveTimeout);
a = new ChannelAccessLinearActuator<Integer>(createChannel(Double.class, lp.getName()), createChannel(Integer.class,lp.getDone()), Integer.parseInt(lp.getDoneValue()), lp.getDoneDelay(), lp.getStart(), lp.getEnd(), lp.getStepSize(), moveTimeout);
}
a.setAsynchronous(lp.isAsynchronous());
@@ -727,7 +685,7 @@ public class Acquisition {
if(name==null){
name = lp.getName();
}
ChannelAccessDoubleSensor sensor = new ChannelAccessDoubleSensor(cservice, lp.getId(), name);
ChannelAccessSensor<Double> sensor = new ChannelAccessSensor<Double>(lp.getId(), createChannel(Double.class, name), configModel.isFailOnSensorError());
aLoop.getSensors().add(sensor);
}
else if(p instanceof FunctionPositioner){
@@ -740,14 +698,14 @@ public class Acquisition {
// Create actuator
ChannelAccessFunctionActuator<?> a;
if(lp.getType().equals("String")){
a = new ChannelAccessFunctionActuator<String>(cservice, lp.getName(), lp.getDone(), lp.getDoneValue(), lp.getDoneDelay(), function, lp.getStart(), lp.getEnd(), lp.getStepSize(), moveTimeout);
a = new ChannelAccessFunctionActuator<String>(createChannel(Double.class,lp.getName()), createChannel(String.class,lp.getDone()), lp.getDoneValue(), lp.getDoneDelay(), function, lp.getStart(), lp.getEnd(), lp.getStepSize(), moveTimeout);
}
else if(lp.getType().equals("Double")){
a = new ChannelAccessFunctionActuator<Double>(cservice, lp.getName(), lp.getDone(), Double.parseDouble(lp.getDoneValue()), lp.getDoneDelay(), function, lp.getStart(), lp.getEnd(), lp.getStepSize(), moveTimeout);
a = new ChannelAccessFunctionActuator<Double>(createChannel(Double.class, lp.getName()), createChannel(Double.class, lp.getDone()), Double.parseDouble(lp.getDoneValue()), lp.getDoneDelay(), function, lp.getStart(), lp.getEnd(), lp.getStepSize(), moveTimeout);
}
else{
// Default
a = new ChannelAccessFunctionActuator<Integer>(cservice, lp.getName(), lp.getDone(), Integer.parseInt(lp.getDoneValue()), lp.getDoneDelay(), function, lp.getStart(), lp.getEnd(), lp.getStepSize(), moveTimeout);
a = new ChannelAccessFunctionActuator<Integer>(createChannel(Double.class, lp.getName()), createChannel(Integer.class, lp.getDone()), Integer.parseInt(lp.getDoneValue()), lp.getDoneDelay(), function, lp.getStart(), lp.getEnd(), lp.getStepSize(), moveTimeout);
}
a.setAsynchronous(lp.isAsynchronous());
@@ -760,7 +718,7 @@ public class Acquisition {
if(name==null){
name = lp.getName();
}
ChannelAccessDoubleSensor sensor = new ChannelAccessDoubleSensor(cservice, lp.getId(), name);
ChannelAccessSensor<Double> sensor = new ChannelAccessSensor<Double>(lp.getId(), createChannel(Double.class, name), configModel.isFailOnSensorError());
aLoop.getSensors().add(sensor);
}
else if (p instanceof ArrayPositioner){
@@ -773,14 +731,14 @@ public class Acquisition {
ChannelAccessTableActuator<?> a;
if(p.getType().equals("String")){
a = new ChannelAccessTableActuator<String>(cservice, p.getName(), p.getDone(), p.getDoneValue(), p.getDoneDelay(), table, moveTimeout);
a = new ChannelAccessTableActuator<String>(createChannel(Double.class, p.getName()), createChannel(String.class, p.getDone()), p.getDoneValue(), p.getDoneDelay(), table, moveTimeout);
}
else if(p.getType().equals("Double")){
a = new ChannelAccessTableActuator<Double>(cservice, p.getName(), p.getDone(), Double.parseDouble(p.getDoneValue()), p.getDoneDelay(), table, moveTimeout);
a = new ChannelAccessTableActuator<Double>(createChannel(Double.class, p.getName()), createChannel(Double.class, p.getDone()), Double.parseDouble(p.getDoneValue()), p.getDoneDelay(), table, moveTimeout);
}
else{
// Default
a = new ChannelAccessTableActuator<Integer>(cservice, p.getName(), p.getDone(), Integer.parseInt(p.getDoneValue()), p.getDoneDelay(), table, moveTimeout);
a = new ChannelAccessTableActuator<Integer>(createChannel(Double.class, p.getName()), createChannel(Integer.class, p.getDone()), Integer.parseInt(p.getDoneValue()), p.getDoneDelay(), table, moveTimeout);
}
a.setAsynchronous(p.isAsynchronous());
@@ -793,7 +751,7 @@ public class Acquisition {
if(name==null){
name = ap.getName();
}
ChannelAccessDoubleSensor sensor = new ChannelAccessDoubleSensor(cservice, ap.getId(), name);
ChannelAccessSensor<Double> sensor = new ChannelAccessSensor<Double>(ap.getId(), createChannel(Double.class, name), configModel.isFailOnSensorError());
aLoop.getSensors().add(sensor);
}
else if (p instanceof RegionPositioner){
@@ -826,14 +784,13 @@ public class Acquisition {
// Create actuator
ChannelAccessLinearActuator<?> act;
if(rp.getType().equals("String")){
act = new ChannelAccessLinearActuator<String>(cservice, rp.getName(), rp.getDone(), rp.getDoneValue(), rp.getDoneDelay(), start, r.getEnd(), r.getStepSize(), moveTimeout);
act = new ChannelAccessLinearActuator<String>(createChannel(Double.class, rp.getName()), createChannel(String.class, rp.getDone()), rp.getDoneValue(), rp.getDoneDelay(), start, r.getEnd(), r.getStepSize(), moveTimeout);
}
else if(rp.getType().equals("Double")){
act = new ChannelAccessLinearActuator<Double>(cservice, rp.getName(), rp.getDone(), Double.parseDouble(rp.getDoneValue()), rp.getDoneDelay(), start, r.getEnd(), r.getStepSize(), moveTimeout);
act = new ChannelAccessLinearActuator<Double>(createChannel(Double.class, rp.getName()), createChannel(Double.class, rp.getDone()), Double.parseDouble(rp.getDoneValue()), rp.getDoneDelay(), start, r.getEnd(), r.getStepSize(), moveTimeout);
}
else{
// Default
act = new ChannelAccessLinearActuator<Integer>(cservice, rp.getName(), rp.getDone(), Integer.parseInt(rp.getDoneValue()), rp.getDoneDelay(), start, r.getEnd(), r.getStepSize(), moveTimeout);
act = new ChannelAccessLinearActuator<Integer>(createChannel(Double.class, rp.getName()), createChannel(Integer.class, rp.getDone()), Integer.parseInt(rp.getDoneValue()), rp.getDoneDelay(), start, r.getEnd(), r.getStepSize(), moveTimeout);
}
act.setAsynchronous(rp.isAsynchronous());
@@ -854,14 +811,14 @@ public class Acquisition {
JythonFunction function = mapFunction(r.getFunction());
ChannelAccessFunctionActuator<?> act;
if(rp.getType().equals("String")){
act = new ChannelAccessFunctionActuator<String>(cservice, rp.getName(), rp.getDone(), rp.getDoneValue(), rp.getDoneDelay(), function, r.getStart(), r.getEnd(), r.getStepSize(), moveTimeout);
act = new ChannelAccessFunctionActuator<String>(createChannel(Double.class,rp.getName()), createChannel(String.class,rp.getDone()), rp.getDoneValue(), rp.getDoneDelay(), function, r.getStart(), r.getEnd(), r.getStepSize(), moveTimeout);
}
else if(rp.getType().equals("Double")){
act = new ChannelAccessFunctionActuator<Double>(cservice, rp.getName(), rp.getDone(), Double.parseDouble(rp.getDoneValue()), rp.getDoneDelay(), function, r.getStart(), r.getEnd(), r.getStepSize(), moveTimeout);
act = new ChannelAccessFunctionActuator<Double>(createChannel(Double.class, rp.getName()), createChannel(Double.class, rp.getDone()), Double.parseDouble(rp.getDoneValue()), rp.getDoneDelay(), function, r.getStart(), r.getEnd(), r.getStepSize(), moveTimeout);
}
else{
// Default
act = new ChannelAccessFunctionActuator<Integer>(cservice, rp.getName(), rp.getDone(), Integer.parseInt(rp.getDoneValue()), rp.getDoneDelay(), function, r.getStart(), r.getEnd(), r.getStepSize(), moveTimeout);
act = new ChannelAccessFunctionActuator<Integer>(createChannel(Double.class, rp.getName()), createChannel(Integer.class, rp.getDone()), Integer.parseInt(rp.getDoneValue()), rp.getDoneDelay(), function, r.getStart(), r.getEnd(), r.getStepSize(), moveTimeout);
}
act.setAsynchronous(rp.isAsynchronous());
@@ -881,7 +838,7 @@ public class Acquisition {
if(name==null){
name = rp.getName();
}
ChannelAccessDoubleSensor sensor = new ChannelAccessDoubleSensor(cservice, rp.getId(), name);
ChannelAccessSensor<Double> sensor = new ChannelAccessSensor<Double>(rp.getId(), createChannel(Double.class, name), configModel.isFailOnSensorError());
aLoop.getSensors().add(sensor);
}
else if(p instanceof PseudoPositioner){
@@ -915,20 +872,17 @@ public class Acquisition {
Guard g = dimension.getGuard();
if(g != null){
// Map conditions
List<ChannelAccessGuardCondition> conditions = new ArrayList<ChannelAccessGuardCondition>();
List<ChannelAccessGuardCondition<?>> conditions = new ArrayList<>();
for(GuardCondition con: g.getCondition()){
Object value = null;
if(con.getType().equals("Integer")){
value = new Integer(con.getValue());
conditions.add(new ChannelAccessGuardCondition<Integer>(createChannel(Integer.class, con.getChannel()), new Integer(con.getValue())));
}
else if(con.getType().equals("Double")){
value = new Double(con.getValue());
conditions.add(new ChannelAccessGuardCondition<Double>(createChannel(Double.class, con.getChannel()), new Double(con.getValue())));
}
else{
value = con.getValue();
conditions.add(new ChannelAccessGuardCondition<String>(createChannel(String.class, con.getChannel()), con.getValue()));
}
conditions.add(new ChannelAccessGuardCondition(cservice, con.getChannel(), value));
}
// Create guard and add to loop
ChannelAccessGuard guard = new ChannelAccessGuard(conditions);
@@ -955,12 +909,11 @@ public class Acquisition {
*/
private JythonFunction mapFunction(Function f){
HashMap<String, JythonGlobalVariable> map = new HashMap<String, JythonGlobalVariable>();
JythonGlobalVariableDictionary dict = JythonGlobalVariableDictionary.getInstance();
for(ParameterMapping m: f.getMapping()){
if(m instanceof VariableParameterMapping){
VariableParameterMapping vp = (VariableParameterMapping)m;
Variable v = (Variable)vp.getName();
JythonGlobalVariable var = dict.getVariable(v.getName());
JythonGlobalVariable var = jVariableDictionary.get(v.getName());
var.setValue(v.getValue());
map.put(vp.getVariable(), var);
}
@@ -979,10 +932,10 @@ public class Acquisition {
// Add sensor
Sensor sensor;
if(sd.getType().equals("String")){
sensor = new ChannelAccessStringSensor(cservice, sd.getId(), sd.getName());
sensor = new ChannelAccessSensor<>(sd.getId(), createChannel(String.class,sd.getName()), configModel.isFailOnSensorError());
}
else{
sensor = new ChannelAccessDoubleSensor(cservice, sd.getId(), sd.getName());
sensor = new ChannelAccessSensor<>(sd.getId(), createChannel(Double.class,sd.getName()), configModel.isFailOnSensorError());
}
aLoop.getSensors().add(sensor);
@@ -994,7 +947,7 @@ public class Acquisition {
aLoop.getPreSensorActions().addAll(mapActions(ad.getPreAction()));
// Ad sensor
ChannelAccessDoubleArraySensor sensor = new ChannelAccessDoubleArraySensor(cservice, ad.getId(), ad.getName(), ad.getArraySize());
Sensor sensor = new ChannelAccessSensor<>(ad.getId(), createChannel(double[].class, ad.getName(), ad.getArraySize()), configModel.isFailOnSensorError());
aLoop.getSensors().add(sensor);
}
else if (detector instanceof DetectorOfDetectors){
@@ -1012,7 +965,7 @@ public class Acquisition {
Timestamp dd = (Timestamp) detector;
// Ad sensor
MillisecondTimestampSensor sensor = new MillisecondTimestampSensor(dd.getId());
TimestampSensor sensor = new TimestampSensor(dd.getId());
aLoop.getSensors().add(sensor);
}
else{
@@ -1037,7 +990,11 @@ public class Acquisition {
// Create loop
boolean zigZag = dimension.isZigzag(); // default value is false
OTFLoop actionLoop = new OTFLoop(cservice, configuration.getOtfChannelPrefix(), configuration.getOtfNfsServer(), configuration.getOtfNfsShare(), configuration.getOtfSmbShare(), zigZag);
Map<String,String> macros = new HashMap<>();
macros.put("PREFIX", configuration.getOtfChannelPrefix());
TemplateOTF template = new TemplateOTF();
createTemplateChannels(template, macros);
OTFLoop actionLoop = new OTFLoop(template, configuration.getOtfNfsServer(), configuration.getOtfNfsShare(), configuration.getOtfSmbShare(), zigZag);
actionLoop.getPreActions().addAll(mapActions(dimension.getPreAction()));
@@ -1047,10 +1004,7 @@ public class Acquisition {
if(p.getAdditionalBacklash()!=null){
backlash = p.getAdditionalBacklash();
}
OTFActuator actor = new OTFActuator(p.getId(), p.getName(), p.getReadback(), p.getStart(), p.getEnd(), p.getStepSize(), p.getIntegrationTime(), backlash);
actionLoop.setActor(actor);
actionLoop.getSensors().add(new OTFReadbackSensor(p.getId()));
actionLoop.setActuator(p.getId(), p.getName(), p.getReadback(), p.getStart(), p.getEnd(), p.getStepSize(), p.getIntegrationTime(), backlash);
// Map sensors
// ATTENTION: the sequence of the mapping depends on the sequence in the schema file !
@@ -1072,7 +1026,7 @@ public class Acquisition {
Timestamp detector = dimension.getTimestamp();
if(detector != null){
actionLoop.getSensors().add(new MillisecondTimestampSensor(detector.getId()));
actionLoop.getSensors().add(new TimestampSensor(detector.getId()));
}
actionLoop.getPostActions().addAll(mapActions(dimension.getPostAction()));
@@ -1107,24 +1061,23 @@ public class Acquisition {
if(p.getAdditionalBacklash()!=null){
backlash = p.getAdditionalBacklash();
}
OTFActuator actor = new OTFActuator(p.getId(), p.getName(), p.getReadback(), p.getStart(), p.getEnd(), p.getStepSize(), p.getIntegrationTime(), backlash);
actionLoop.setActor(actor);
actionLoop.setActuator(p.getId(), p.getName(), p.getReadback(), p.getStart(), p.getEnd(), p.getStepSize(), p.getIntegrationTime(), backlash);
// Map sensors
// ATTENTION: the sequence of the mapping depends on the sequence in the schema file !
for(SimpleScalarDetector detector: dimension.getDetector()){
if(!detector.isScr()){
actionLoop.getSensors().add(new OTFNamedChannelSensor(detector.getId(), detector.getName()));
actionLoop.getSensors().add(new CrlogicResource(detector.getId(), detector.getName()));
}
}
for(ScalerChannel detector: dimension.getScaler()){
actionLoop.getSensors().add(new OTFScalerChannelSensor(detector.getId(), detector.getChannel()));
actionLoop.getSensors().add(new CrlogicResource(detector.getId(), "SCALER"+detector.getChannel(), true));
}
Timestamp tdetector = dimension.getTimestamp();
if(tdetector != null){
actionLoop.getSensors().add(new MillisecondTimestampSensor(tdetector.getId()));
actionLoop.getSensors().add(new CrlogicResource(tdetector.getId(), "TIMESTAMP"));
}
actionLoop.getPostActions().addAll(mapActions(dimension.getPostAction()));
@@ -1139,14 +1092,17 @@ public class Acquisition {
aLoop = actionLoop;
}
else{
List<Sensor> sensors = new ArrayList<Sensor>();
List<Channel<DoubleTimestamp>> sensors = new ArrayList<>();
List<String> ids = new ArrayList<>();
for(SimpleScalarDetector detector: dimension.getDetector()){
if(detector.isScr()){
sensors.add(new ChannelAccessDoubleSensor(cservice, detector.getId(), detector.getName()));
ids.add(detector.getId());
sensors.add(createChannel(DoubleTimestamp.class, detector.getName()));
}
}
// Create soft(ware) based crlogic
ScrlogicLoop scrlogic = new ScrlogicLoop(cservice, sensors);
ScrlogicLoop scrlogic = new ScrlogicLoop(ids, sensors);
// Create parallel logic
ParallelCrlogic pcrlogic = new ParallelCrlogic(actionLoop, scrlogic);
@@ -1159,4 +1115,51 @@ public class Acquisition {
return aLoop;
}
/**
* Create channel and remember to be able to destroy channels at the end
* @param name
* @param type
* @return null if the name of the channel is null, otherwise the channel
*/
private <T> Channel<T> createChannel(Class<T> type, String name){
try {
if(name== null){
return null;
}
Channel<T> c = cservice.createChannel(new ChannelDescriptor<T>(type, name) );
channels.add(c);
return c;
} catch (ChannelException | InterruptedException | TimeoutException e) {
throw new RuntimeException("Unable to create channel: "+name,e);
}
}
private <T> Channel<T> createChannel(Class<T> type, String name, int size){
try {
if(name== null){
return null;
}
Channel<T> c = cservice.createChannel(new ChannelDescriptor<T>(type, name, false, size) );
channels.add(c);
return c;
} catch (ChannelException | InterruptedException | TimeoutException e) {
throw new RuntimeException("Unable to create channel: "+name,e);
}
}
private void createTemplateChannels(Object o, Map<String,String> macro){
try {
cservice.createAnnotatedChannels(o, macro);
templates.add(o);
} catch (ChannelException | InterruptedException | TimeoutException e) {
throw new RuntimeException("Unable to initialize template: "+o.getClass().getName(),e);
}
}
}

View File

@@ -35,11 +35,12 @@ import ch.psi.fda.install.ApplicationConfigurator;
* @author ebner
*
*/
public class AcquisitionEngineConfiguration {
public class AcquisitionConfiguration {
private static final Logger logger = Logger.getLogger(AcquisitionEngineConfiguration.class.getName());
private static final AcquisitionEngineConfiguration instance = new AcquisitionEngineConfiguration();
private static final Logger logger = Logger.getLogger(AcquisitionConfiguration.class.getName());
public final static String FDA_CONFIG_FILE = "ch.psi.fda.config.file";
private String otfChannelPrefix;
private String otfNfsServer;
@@ -70,37 +71,37 @@ public class AcquisitionEngineConfiguration {
private String smptServer;
/**
* Default Constructor
* The constructor will read the configuration from the /fda.properties file (resource) located in the classpath.
*/
private AcquisitionEngineConfiguration(){
public AcquisitionConfiguration(){
loadConfiguration();
}
/**
* Get instance of this configuration
* @return configuration
*/
public static AcquisitionEngineConfiguration getInstance(){
return(instance);
public void loadConfiguration(){
loadConfiguration(null);
}
/**
* Load configuration from properties file
*/
private void loadConfiguration() {
String config = System.getProperty(ApplicationConfigurator.FDA_CONFIG_FILE_ARGUMENT);
public void loadConfiguration(String file) {
if(file == null){
file = System.getProperty(FDA_CONFIG_FILE);
}
Properties properties = new Properties();
if(config != null){
// Only read in the property file if a file is specified
if(file != null){
try {
properties.load(new FileReader(config));
properties.load(new FileReader(file));
} catch (FileNotFoundException e) {
throw new RuntimeException("Configuration file "+config+" not found", e);
throw new RuntimeException("Configuration file "+file+" not found", e);
} catch (IOException e) {
throw new RuntimeException("Cannot read configuration file "+config, e);
throw new RuntimeException("Cannot read configuration file "+file, e);
}
}
else{
@@ -108,125 +109,38 @@ public class AcquisitionEngineConfiguration {
}
// The defaults are set here
otfChannelPrefix = properties.getProperty(AcquisitionEngineConfiguration.class.getPackage().getName()+".otf.channelPrefix", "");
otfScalerPrefix = properties.getProperty(AcquisitionEngineConfiguration.class.getPackage().getName()+".otf.scalerPrefix", "");
otfNfsServer = properties.getProperty(AcquisitionEngineConfiguration.class.getPackage().getName()+".otf.nfsServer", "");
otfNfsShare = properties.getProperty(AcquisitionEngineConfiguration.class.getPackage().getName()+".otf.nfsShare", "");
otfSmbShare = properties.getProperty(AcquisitionEngineConfiguration.class.getPackage().getName()+".otf.smbShare", "");
otfUseCrlogic = new Boolean(properties.getProperty(AcquisitionEngineConfiguration.class.getPackage().getName()+".otf.useCrlogic", "false"));
otfCrlogicPrefix = properties.getProperty(AcquisitionEngineConfiguration.class.getPackage().getName()+".otf.crlogicPrefix", "");
otfCrlogicKeepTmpFiles = new Boolean(properties.getProperty(AcquisitionEngineConfiguration.class.getPackage().getName()+".otf.crlogicKeepTmpFiles", "false"));
otfChannelPrefix = properties.getProperty(AcquisitionConfiguration.class.getPackage().getName()+".otf.channelPrefix", "");
otfScalerPrefix = properties.getProperty(AcquisitionConfiguration.class.getPackage().getName()+".otf.scalerPrefix", "");
otfNfsServer = properties.getProperty(AcquisitionConfiguration.class.getPackage().getName()+".otf.nfsServer", "");
otfNfsShare = properties.getProperty(AcquisitionConfiguration.class.getPackage().getName()+".otf.nfsShare", "");
otfSmbShare = properties.getProperty(AcquisitionConfiguration.class.getPackage().getName()+".otf.smbShare", "");
// Workaround
// dataBaseDirectory = properties.getProperty(AcquisitionEngineConfiguration.class.getPackage().getName()+".data.baseDirectory", ".");
if(System.getProperty(ApplicationConfigurator.FDA_HOME_ARGUMENT)!=null){
otfUseCrlogic = new Boolean(properties.getProperty(AcquisitionConfiguration.class.getPackage().getName()+".otf.useCrlogic", "false"));
otfCrlogicPrefix = properties.getProperty(AcquisitionConfiguration.class.getPackage().getName()+".otf.crlogicPrefix", "");
otfCrlogicKeepTmpFiles = new Boolean(properties.getProperty(AcquisitionConfiguration.class.getPackage().getName()+".otf.crlogicKeepTmpFiles", "false"));
if(System.getProperty(ApplicationConfigurator.FDA_HOME_ARGUMENT)!=null){ // TODO remove
dataBaseDirectory = System.getProperty(ApplicationConfigurator.FDA_HOME_ARGUMENT)+"/data";
}
else{
dataBaseDirectory = "./data";
}
dataFilePrefix = properties.getProperty(AcquisitionEngineConfiguration.class.getPackage().getName()+".data.filePrefix","");
dataFilePrefix = properties.getProperty(AcquisitionConfiguration.class.getPackage().getName()+".data.filePrefix","");
actorMoveTimeout = new Long(properties.getProperty(AcquisitionEngineConfiguration.class.getPackage().getName()+".actorMoveTimeout","600000"));
actorMoveTimeout = new Long(properties.getProperty(AcquisitionConfiguration.class.getPackage().getName()+".actorMoveTimeout","600000"));
smptServer= properties.getProperty(AcquisitionEngineConfiguration.class.getPackage().getName()+".notification.host","mail.psi.ch");
smptServer= properties.getProperty(AcquisitionConfiguration.class.getPackage().getName()+".notification.host","mail.psi.ch");
}
/**
* Reload this configuration from the corresponding properties file
* @throws IOException
* Replace ${name} and ${date} macro given string
* @param string
* @param date
* @param name
* @return
*/
public void reloadConfiguration() throws IOException{
loadConfiguration();
}
/**
* @return the otfChannelPrefix
*/
public String getOtfChannelPrefix() {
return otfChannelPrefix;
}
/**
* @return the otfScalerPrefix
*/
public String getOtfScalerPrefix() {
return otfScalerPrefix;
}
/**
* @return the otfNfsServer
*/
public String getOtfNfsServer() {
return otfNfsServer;
}
/**
* @return the otfNfsShare
*/
public String getOtfNfsShare() {
return otfNfsShare;
}
/**
* @return the otfSmbShare
*/
public String getOtfSmbShare() {
return otfSmbShare;
}
/**
* @return the otfUseCrlogic
*/
public boolean isOtfUseCrlogic() {
return otfUseCrlogic;
}
/**
* @return the dataBaseDirectory
*/
public String getDataBaseDirectory() {
return dataBaseDirectory;
}
/**
* @return the dataFilePrefix
*/
public String getDataFilePrefix() {
return dataFilePrefix;
}
/**
* @return the smptServer
*/
public String getSmptServer() {
return smptServer;
}
/**
* @return the otfCrlogicPrefix
*/
public String getOtfCrlogicPrefix() {
return otfCrlogicPrefix;
}
/**
* @return the otfCrlogicKeepTmpFiles
*/
public boolean isOtfCrlogicKeepTmpFiles() {
return otfCrlogicKeepTmpFiles;
}
/**
* @return the actorMoveTimeout
*/
public Long getActorMoveTimeout() {
return actorMoveTimeout;
}
public String replaceMacros(String string, Date date, String name){
String newString = string;
@@ -248,50 +162,100 @@ public class AcquisitionEngineConfiguration {
return newString;
}
// Getter and setter functions
public String getOtfChannelPrefix() {
return otfChannelPrefix;
}
public void setOtfChannelPrefix(String otfChannelPrefix) {
this.otfChannelPrefix = otfChannelPrefix;
}
public String getOtfNfsServer() {
return otfNfsServer;
}
public void setOtfNfsServer(String otfNfsServer) {
this.otfNfsServer = otfNfsServer;
}
public String getOtfNfsShare() {
return otfNfsShare;
}
public void setOtfNfsShare(String otfNfsShare) {
this.otfNfsShare = otfNfsShare;
}
public String getOtfSmbShare() {
return otfSmbShare;
}
public void setOtfSmbShare(String otfSmbShare) {
this.otfSmbShare = otfSmbShare;
}
public String getOtfScalerPrefix() {
return otfScalerPrefix;
}
public void setOtfScalerPrefix(String otfScalerPrefix) {
this.otfScalerPrefix = otfScalerPrefix;
}
public boolean isOtfUseCrlogic() {
return otfUseCrlogic;
}
public void setOtfUseCrlogic(boolean otfUseCrlogic) {
this.otfUseCrlogic = otfUseCrlogic;
}
public String getOtfCrlogicPrefix() {
return otfCrlogicPrefix;
}
public void setOtfCrlogicPrefix(String otfCrlogicPrefix) {
this.otfCrlogicPrefix = otfCrlogicPrefix;
}
public boolean isOtfCrlogicKeepTmpFiles() {
return otfCrlogicKeepTmpFiles;
}
public void setOtfCrlogicKeepTmpFiles(boolean otfCrlogicKeepTmpFiles) {
this.otfCrlogicKeepTmpFiles = otfCrlogicKeepTmpFiles;
}
public String getDataBaseDirectory() {
return dataBaseDirectory;
}
public void setDataBaseDirectory(String dataBaseDirectory) {
this.dataBaseDirectory = dataBaseDirectory;
}
public String getDataFilePrefix() {
return dataFilePrefix;
}
public void setDataFilePrefix(String dataFilePrefix) {
this.dataFilePrefix = dataFilePrefix;
}
public Long getActorMoveTimeout() {
return actorMoveTimeout;
}
public void setActorMoveTimeout(Long actorMoveTimeout) {
this.actorMoveTimeout = actorMoveTimeout;
}
public String getSmptServer() {
return smptServer;
}
public void setSmptServer(String smptServer) {
this.smptServer = smptServer;
}

View File

@@ -0,0 +1,102 @@
/**
*
* Copyright 2010 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 <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.aq;
import java.util.ArrayList;
import java.util.List;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import ch.psi.fda.core.messages.DataMessage;
import ch.psi.fda.core.messages.Metadata;
import ch.psi.fda.core.messages.StreamDelimiterMessage;
import ch.psi.fda.core.messages.EndOfStreamMessage;
import ch.psi.fda.core.messages.Message;
/**
* Collector class that is collecting and merging data from different Queues.
*/
public class Collector {
private EventBus bus;
private List<MessageListener> listeners = new ArrayList<>();
private List<Metadata> metadata;
private boolean first = true;
public Collector(EventBus b){
this.bus = b;
}
public void addEventBus(EventBus b){
MessageListener l = new MessageListener();
listeners.add(l);
b.register(l);
}
private class MessageListener{
private DataMessage message;
@Subscribe
public void onMessage(Message message){
int level = listeners.indexOf(this);
if(message instanceof DataMessage){
this.message = (DataMessage) message;
if(level==0){
if(first){
metadata = new ArrayList<>();
for(int i=listeners.size()-1;i>=0;i--){
// Correct/Add dimension information
for(Metadata m: listeners.get(i).getMessage().getMetadata()){
m.setDimension(i);
}
metadata.addAll(listeners.get(i).getMessage().getMetadata());
}
}
DataMessage m = new DataMessage(metadata);
for(int i=listeners.size()-1;i>=0;i--){
m.getData().addAll(listeners.get(i).getMessage().getData());
}
bus.post(m);
}
}
if(message instanceof EndOfStreamMessage){
StreamDelimiterMessage ddm = new StreamDelimiterMessage(level, ((EndOfStreamMessage)message).isIflag());
bus.post(ddm);
if(level==(listeners.size()-1)){ // if highest dimension then send end of stream
bus.post(new EndOfStreamMessage());
}
}
}
public DataMessage getMessage(){
return message;
}
}
}

View File

@@ -0,0 +1,77 @@
/**
*
* Copyright 2010 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 <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.aq;
import java.util.ArrayList;
import java.util.List;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import ch.psi.fda.core.Manipulation;
import ch.psi.fda.core.messages.DataMessage;
import ch.psi.fda.core.messages.Message;
import ch.psi.fda.core.messages.Metadata;
/**
* Applies manipulations to the data stream
*/
public class Manipulator {
private EventBus bus;
private final List<Manipulation> manipulations;
private boolean first = true;
private List<Metadata> metadata = new ArrayList<>();
public Manipulator(EventBus b, List<Manipulation> manipulations){
this.bus = b;
this.manipulations = manipulations;
}
@Subscribe
public void onMessage(Message message){
if(message instanceof DataMessage){
if(first){
first=false;
metadata.addAll(((DataMessage) message).getMetadata());
for(Manipulation manipulation: this.manipulations){
manipulation.initialize(this.metadata);
// Add manipulation id to metadata
this.metadata.add(new Metadata(manipulation.getId(),0)); // Calculated component always belongs to lowes dimension
}
}
DataMessage dm = (DataMessage) message;
// message = new DataMessage(metadata);
for(Manipulation manipulation: manipulations){
// ((DataMessage)message).getData().add(manipulation.execute(dm));
dm.getData().add(manipulation.execute(dm));
}
// Need to update the metadata of the message
dm.setMetadata(this.metadata);
}
bus.post(message);
}
}

View File

@@ -15,7 +15,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ch.psi.fda.notification;
package ch.psi.fda.aq;
import java.util.ArrayList;
import java.util.List;
@@ -32,9 +32,7 @@ import javax.mail.internet.MimeMessage;
import ch.psi.fda.model.v1.Recipient;
/**
* This is a copy of the NotificationAgent class that should go into the foundation classes
* This actually should be extracted to an own project
* @author ebner
* Agent to send out notifications to specified recipients.
*/
public class NotificationAgent {
@@ -55,7 +53,6 @@ public class NotificationAgent {
fromAddress = from;
properties = new Properties();
// Setup mail server
properties.put("mail.smtp.host", host);
}

View File

@@ -0,0 +1,271 @@
/**
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.aq;
import java.util.ArrayList;
import java.util.List;
import ch.psi.fda.model.v1.ArrayDetector;
import ch.psi.fda.model.v1.ContinuousPositioner;
import ch.psi.fda.model.v1.Detector;
import ch.psi.fda.model.v1.LinearPositioner;
import ch.psi.fda.model.v1.Positioner;
import ch.psi.fda.model.v1.PseudoPositioner;
import ch.psi.fda.model.v1.Visualization;
import ch.psi.fda.visualizer.SeriesDataFilter;
import ch.psi.fda.visualizer.XYSeriesArrayDataFilter;
import ch.psi.fda.visualizer.XYSeriesDataFilter;
import ch.psi.fda.visualizer.XYZSeriesArrayDataFilter;
import ch.psi.fda.visualizer.XYZSeriesDataFilter;
import ch.psi.plot.xyz.MatrixPlot;
import ch.psi.plot.xyz.MatrixPlotData;
/**
* @author ebner
*
*/
public class VisualizationMapper {
/**
* Retrieve id string of the passed object
* @param object
* @return Id string of object
*/
private static String getId(Object object){
String id;
if(object instanceof Positioner){
id = ((Positioner)object).getId();
}
else if (object instanceof Detector){
id = ((Detector)object).getId();
}
else if (object instanceof ch.psi.fda.model.v1.Manipulation){
id = ((ch.psi.fda.model.v1.Manipulation)object).getId();
}
// For testing purposes
else if(object instanceof String){
id = (String) object;
}
else{
throw new RuntimeException("Unable to identify id of object reference "+object);
}
return id;
}
public static List<SeriesDataFilter> mapVisualizations(List<Visualization> vl){
List<SeriesDataFilter> filters = new ArrayList<SeriesDataFilter>();
for(Visualization v: vl){
if(v instanceof ch.psi.fda.model.v1.LinePlot){
ch.psi.fda.model.v1.LinePlot lp = (ch.psi.fda.model.v1.LinePlot) v;
// Create plot for visualization
ch.psi.plot.xy.LinePlot plot = new ch.psi.plot.xy.LinePlot(lp.getTitle());
// Create data filter for visualization
String idX = getId(lp.getX());
List<Object> l = lp.getY();
for(Object o: l){
String idY = getId(o);
XYSeriesDataFilter filter = new XYSeriesDataFilter(idX, idY, plot);
filter.setSeriesName(idY);
filters.add(filter);
}
}
else if(v instanceof ch.psi.fda.model.v1.LinePlotArray){
// Array visualization
ch.psi.fda.model.v1.LinePlotArray lp = (ch.psi.fda.model.v1.LinePlotArray) v;
// Create plot for visualization
ch.psi.plot.xy.LinePlot plot = new ch.psi.plot.xy.LinePlot(lp.getTitle());
// Create data filter for visualization
List<Object> l = lp.getY();
for(Object o: l){
String idY = getId(o);
XYSeriesArrayDataFilter filter = new XYSeriesArrayDataFilter(idY, plot);
filter.setMaxSeries(lp.getMaxSeries()*lp.getY().size()); // Workaround - keep for each array max series
filter.setOffset(lp.getOffset());
filter.setSize(lp.getSize());
filter.setSeriesName(idY);
filters.add(filter);
}
}
else if(v instanceof ch.psi.fda.model.v1.MatrixPlot){
// MatrixPlot does currently not support RegionPositioners because of the
// plotting problems this would cause. If regions of the positioner have different
// step sizes it is not easily possible (without (specialized) rasterization) to plot the data.
ch.psi.fda.model.v1.MatrixPlot mp = (ch.psi.fda.model.v1.MatrixPlot) v;
double minX, maxX;
int nX;
double minY, maxY;
int nY;
String idX, idY, idZ;
// X Axis
if(mp.getX() instanceof LinearPositioner){
LinearPositioner linp = ((LinearPositioner)mp.getX());
idX = linp.getId();
minX = (Math.min(linp.getStart(), linp.getEnd()));
maxX = (Math.max(linp.getStart(), linp.getEnd()));
nX = ((int) Math.floor((Math.abs(maxX-minX))/linp.getStepSize()) + 1);
}
else if(mp.getX() instanceof PseudoPositioner){
PseudoPositioner pp = ((PseudoPositioner)mp.getX());
idX = pp.getId();
minX = (1); // Count starts at 1
maxX = (pp.getCounts());
nX = (pp.getCounts());
}
else if(mp.getX() instanceof ContinuousPositioner){
ContinuousPositioner conp = ((ContinuousPositioner)mp.getX());
idX = conp.getId();
minX = (Math.min(conp.getStart(), conp.getEnd()));
maxX = (Math.max(conp.getStart(), conp.getEnd()));
nX = ((int) Math.floor((Math.abs(maxX-minX))/conp.getStepSize()) + 1);
}
else{
// Fail as we cannot determine the min, max and number of steps
throw new RuntimeException(mp.getX().getClass().getName()+" is not supported as x-axis of a MatrixPlot");
}
// Y Axis
if(mp.getY() instanceof LinearPositioner){
LinearPositioner linp = ((LinearPositioner)mp.getY());
idY = linp.getId();
minY = (Math.min(linp.getStart(), linp.getEnd()));
maxY = (Math.max(linp.getStart(), linp.getEnd()));
nY = ((int) Math.floor((Math.abs(maxY-minY))/linp.getStepSize()) + 1);
}
else if(mp.getY() instanceof PseudoPositioner){
PseudoPositioner pp = ((PseudoPositioner)mp.getY());
idY = pp.getId();
minY = (1); // Count starts at 1
maxY = (pp.getCounts());
nY = (pp.getCounts());
}
else{
// Fail as we cannot determine the min, max and number of steps
throw new RuntimeException(mp.getY().getClass().getName()+" is not supported as y-axis of a MatrixPlot");
}
// Z Dimension
idZ = getId(mp.getZ());
// Create plot for visualization
MatrixPlotData data = new MatrixPlotData(minX, maxX, nX, minY, maxY, nY);
MatrixPlot plot = new MatrixPlot(mp.getTitle(), data);
XYZSeriesDataFilter filter = new XYZSeriesDataFilter(idX, idY, idZ, plot);
filters.add(filter);
}
else if(v instanceof ch.psi.fda.model.v1.MatrixPlotArray){
// Support for 2D waveform plots
ch.psi.fda.model.v1.MatrixPlotArray mp = (ch.psi.fda.model.v1.MatrixPlotArray) v;
// Get size of the array detector
int arraySize = 0;
Object o = mp.getZ();
if(o instanceof ArrayDetector){
ArrayDetector ad = (ArrayDetector) o;
arraySize = ad.getArraySize();
}
else{
// Workaround
arraySize = mp.getSize(); // of array is from a manipulation the size is not known. Then the size will indicate the size of the array to display
}
int offset = mp.getOffset();
// Determine size for array
int size = mp.getSize();
if(size>0 && offset+size<arraySize){
size = mp.getSize();
}
else{
size=arraySize-offset;
}
double minY, maxY;
int nY;
double minX = offset;
double maxX = offset+size-1;
int nX = size;
String idY, idZ;
// Y Axis
if(mp.getY() instanceof LinearPositioner){
LinearPositioner linp = ((LinearPositioner)mp.getY());
idY = linp.getId();
minY = (Math.min(linp.getStart(), linp.getEnd()));
maxY = (Math.max(linp.getStart(), linp.getEnd()));
nY = ((int) Math.floor((Math.abs(maxY-minY))/linp.getStepSize()) + 1);
}
else if(mp.getY() instanceof PseudoPositioner){
PseudoPositioner pp = ((PseudoPositioner)mp.getY());
idY = pp.getId();
minY = (1); // Count starts at 1
maxY = (pp.getCounts());
nY = (pp.getCounts());
}
else if(mp.getY() instanceof ContinuousPositioner){
ContinuousPositioner conp = ((ContinuousPositioner)mp.getY());
idY = conp.getId();
minY = (Math.min(conp.getStart(), conp.getEnd()));
maxY = (Math.max(conp.getStart(), conp.getEnd()));
nY = ((int) Math.floor((Math.abs(maxY-minY))/conp.getStepSize()) + 1);
}
else{
// Fail as we cannot determine the min, max and number of steps
throw new RuntimeException(mp.getY().getClass().getName()+" is not supported as x-axis of a MatrixPlot");
}
// Z Dimension
idZ = getId(mp.getZ());
// Create plot for visualization
MatrixPlotData data = new MatrixPlotData(minX, maxX, nX, minY, maxY, nY);
MatrixPlot plot = new MatrixPlot(mp.getTitle(), data);
XYZSeriesArrayDataFilter filter = new XYZSeriesArrayDataFilter(idY, idZ, offset, size, plot);
filters.add(filter);
}
else{
// Visualization type (currently) not supported
throw new RuntimeException(v.getClass().getName()+" is not supported as visualization type");
}
}
return filters;
}
}

View File

@@ -1,154 +0,0 @@
/**
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.aq.ng;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
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.fda.aq.ng.rdescriptors.ProbeDescriptor;
import ch.psi.fda.aq.ng.rdescriptors.ShellDescriptor;
import ch.psi.fda.aq.ng.resources.ChannelProbeResource;
import ch.psi.fda.aq.ng.resources.ShellResource;
import ch.psi.fda.core.messages.Message;
import ch.psi.jcae.Channel;
import ch.psi.jcae.ChannelDescriptor;
import ch.psi.jcae.ChannelException;
import ch.psi.jcae.ChannelService;
/**
* @author ebner
*
*/
public class AcquisitionEngineNG {
private static final Logger logger = Logger.getLogger(AcquisitionEngineNG.class.getName());
private ChannelService cservice;
private BlockingQueue<Message> outQueue;
public AcquisitionEngineNG(ChannelService cservice) {
this.cservice = cservice;
this.outQueue = new LinkedBlockingQueue<Message>(1000); // Create bounded queue to prevent running out of memory ...
// Workaround for Jython memory leak
// http://blog.hillbrecht.de/2009/07/11/jython-memory-leakout-of-memory-problem/
System.setProperty("python.options.internalTablesImpl", "weak");
}
/**
* Execute the specified script/logic while using the specified resources and paramters
* @param resourceDescriptors
* @param script
* @param parameter
*/
public void execute(Map<String, ?> resourceDescriptors, String script, List<String> parameter){
// TODO Remove debugging messages
// For debugging purpose only
logger.info("Resources to create: "+resourceDescriptors);
logger.info("Script to execute: "+script);
try {
ScriptEngine engine = new ScriptEngineManager().getEngineByName("python");
// Set logger
engine.put("logger", logger);
// Set parameters
engine.put("parameter", parameter);
// Create/retrieve and set resources
Map<String,?> resources = createResources(resourceDescriptors);
engine.put("resources", resources);
for(String k: resources.keySet()){ // For convenience make resources also available as variable named by the resource id
engine.put(k, resources.get(k));
}
// Execute script
engine.eval(script);
} catch (ScriptException e) {
logger.info(e.getMessage());
throw new RuntimeException("Action failed while executing the Jython script",e);
}
}
/**
* Create resources based on the passed rDescriptors
* Supported descriptor types are:
* ChannelDescriptor, ShellDescriptor, ProbeDescriptor
*
* @param resourceDescriptors
* @return
*/
private Map<String,?> createResources(Map<String, ?> resourceDescriptors){
Map<String,Object> resources = new HashMap<>();
for(String k: resourceDescriptors.keySet()){
if(resourceDescriptors.get(k) instanceof ChannelDescriptor){
ChannelDescriptor<?> descriptor = (ChannelDescriptor<?>)resourceDescriptors.get(k);
try {
resources.put(k, cservice.createChannel(descriptor));
// 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){
resources.put(k, new ShellResource());
// engine.put(k, new ShellResource());
}
else if(resourceDescriptors.get(k) instanceof ProbeDescriptor){
ProbeDescriptor descriptor = (ProbeDescriptor) resourceDescriptors.get(k);
List<Channel<?>> channels = new ArrayList<>();
for(ChannelDescriptor<?> s: descriptor.getSensors()){
try {
channels.add(cservice.createChannel(s));
} catch (ChannelException | InterruptedException | TimeoutException e) {
throw new RuntimeException("Unable to create resource for channel: "+s.getName(),e);
}
}
// TODO Remove workaround ...
resources.put(k, new ChannelProbeResource(channels, outQueue)); // Configure the probe to use the acquisitions out queue for writing data into
// engine.put(k, new ChannelProbeResource(channels, outQueue));
}
else{
throw new RuntimeException("Resource type not supported: "+resourceDescriptors.get(k).getClass().getName());
}
}
return resources;
}
public BlockingQueue<Message> getOutQueue(){
return outQueue;
}
}

View File

@@ -1,173 +0,0 @@
/**
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.aq.ng;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.inject.Inject;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.NotFoundException;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import ch.psi.fda.aq.ng.rdescriptors.ShellDescriptor;
import ch.psi.jcae.ChannelDescriptor;
/**
* @author ebner
*
*/
@Path("/")
public class AcquisitionEngineNGResource {
@Inject
private AcquisitionEngineNG engine;
@Inject
private LManager lmanager;
// @PUT
// @Path("logic")
// public void execute(String logic){
// Map<String, ?> map = new HashMap<>();
// engine.execute(map, logic);
// }
@GET
@Path("logic")
@Produces(MediaType.APPLICATION_JSON)
public Set<String> getLogics(){
return lmanager.getLogics();
}
@PUT
@Path("logic/{id}")
public void setLogic(@PathParam("id") String id, String logic){
lmanager.addLogic(id, logic);
}
@GET
@Path("logic/{id}")
public String getLogic(@PathParam("id") String id){
String logic = lmanager.getLogic(id);
if(logic==null){
throw new NotFoundException();
}
return logic;
}
@POST
@Path("logic/{id}")
@Consumes(MediaType.APPLICATION_JSON)
public void executeLogic(@PathParam("id") String id, EDescriptor edescriptor){
// Before executing the logic first merge the default descriptors and provided descriptors
// Where the provided descriptors take precedence over the default onces.
Map<String, RDescriptor> rdesc = new HashMap<>();
rdesc.putAll(lmanager.getResources(id));
if (edescriptor.getResources() != null) {
rdesc.putAll(edescriptor.getResources());
}
Map<String, ?> map = createResourceDescriptors(rdesc);
List<String> parameters = new ArrayList<>();
if(edescriptor.getParameter()!=null){
parameters = edescriptor.getParameter();
}
engine.execute(map, lmanager.getLogic(id), parameters);
}
@PUT
@Path("logic/{id}/resources")
public void setLogicResources(@PathParam("id") String id, Map<String, RDescriptor> rprofile){
lmanager.addResources(id, rprofile);
}
@GET
@Path("logic/{id}/resources")
public Map<String, RDescriptor> getLogicResources(@PathParam("id") String id){
Map<String, RDescriptor> rprofile = lmanager.getResources(id);
if(rprofile==null){
throw new NotFoundException();
}
return rprofile;
}
/**
* Create internal resource descriptors based on the rdescriptors passed to the method.
*
* Currently following rdescriptor types are supported:
* - channel
* - shell
*
* @param descriptor
* @return
*/
private Map<String, ?> createResourceDescriptors(Map<String, RDescriptor> resourceDescriptors) {
Map<String, Object> map = new HashMap<>();
for (String k : resourceDescriptors.keySet()) {
RDescriptor r = resourceDescriptors.get(k);
if (r.getType().equals("channel")) {
Class<?> c;
switch (r.getParameter().get("type").toLowerCase()) {
case "double":
c = Double.class;
break;
case "integer":
c = Integer.class;
break;
case "boolean":
c = Boolean.class;
break;
case "String":
c = String.class;
break;
default:
c = String.class;
}
;
String name = r.getParameter().get("name");
boolean monitored = false;
if(r.getParameter().get("monitor")!=null){
monitored = new Boolean(r.getParameter().get("monitor"));
}
// Create channel descriptor
ChannelDescriptor<?> cd = new ChannelDescriptor<>(c, name, monitored);
map.put(k, cd);
}
else if (r.getType().equals("shell")) {
map.put(k, new ShellDescriptor());
}
}
return map;
}
}

View File

@@ -1,52 +0,0 @@
/**
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.aq.ng;
import java.util.List;
import java.util.Map;
import javax.xml.bind.annotation.XmlRootElement;
import org.codehaus.jackson.map.annotate.JsonSerialize;
import org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion;
/**
* Execution descriptor - Describes resources and parameters used to execute a logic
*/
@XmlRootElement
@JsonSerialize(include = Inclusion.NON_NULL) // Do not serialize NULL values
public class EDescriptor {
private Map<String, RDescriptor> resources;
private List<String> parameter;
public Map<String, RDescriptor> getResources() {
return resources;
}
public void setResources(Map<String, RDescriptor> resources) {
this.resources = resources;
}
public List<String> getParameter() {
return parameter;
}
public void setParameter(List<String> parameter) {
this.parameter = parameter;
}
}

View File

@@ -1,58 +0,0 @@
/**
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.aq.ng;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* Logic Manager
* Basically a map holding id->logic pairs
*
* also holds default resource profiles for logics (rprofiles)
*/
public class LManager {
private final Map<String, String> logics = new HashMap<>();
/** Default resourses assigned to a logic */
private final Map<String, Map<String, RDescriptor>> resources = new HashMap<>();
public void addLogic(String id, String logic){
logics.put(id, logic);
resources.put(id, new HashMap<String,RDescriptor>()); // No default resources attached to logic
}
public void addResources(String id, Map<String, RDescriptor> lresources){
resources.put(id, lresources);
}
public String getLogic(String id){
return logics.get(id);
}
public Set<String> getLogics(){
return logics.keySet();
}
public Map<String, RDescriptor> getResources(String id){
return resources.get(id);
}
}

View File

@@ -1,119 +0,0 @@
/**
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.aq.ng;
import java.net.InetAddress;
import java.net.URI;
import java.net.UnknownHostException;
import java.util.concurrent.CountDownLatch;
import java.util.logging.Logger;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriBuilderException;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.GnuParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.glassfish.grizzly.http.server.HttpServer;
import org.glassfish.grizzly.http.server.StaticHttpHandler;
import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
import org.glassfish.jersey.jackson.JacksonFeature;
import org.glassfish.jersey.media.sse.SseFeature;
import org.glassfish.jersey.server.ResourceConfig;
import sun.misc.Signal;
import sun.misc.SignalHandler;
/**
* @author ebner
*
*/
@SuppressWarnings("restriction")
public class NGServer {
private static final Logger logger = Logger.getLogger(NGServer.class.getName());
/**
* @param args
* @throws ParseException
* @throws UnknownHostException
* @throws UriBuilderException
* @throws IllegalArgumentException
*/
public static void main(String[] args) throws ParseException, IllegalArgumentException, UriBuilderException, UnknownHostException {
// Option handling
int port = 8080;
Options options = new Options();
options.addOption("h", false, "Help");
options.addOption("p", true, "Server port (default: " + port + ")");
GnuParser parser = new GnuParser();
CommandLine line = parser.parse(options, args);
if (line.hasOption("p")) {
port = Integer.parseInt(line.getOptionValue("p"));
}
if (line.hasOption("h")) {
HelpFormatter f = new HelpFormatter();
f.printHelp("dae", options); // definition dae - http://www.urbandictionary.com/define.php?term=dae
return;
}
URI baseUri = UriBuilder.fromUri("http://" + InetAddress.getLocalHost().getHostName() + "/").port(port).build();
// final ResourceConfig resourceConfig = new
// ResourceConfig(ServerSentEventsResource.class, SseFeature.class);
ResourceConfig resourceConfig = new ResourceConfig(SseFeature.class, JacksonFeature.class);
resourceConfig.packages(AcquisitionEngineNGResource.class.getPackage().getName());
resourceConfig.register(new ResourceBinder());
HttpServer server = GrizzlyHttpServerFactory.createHttpServer(baseUri, resourceConfig);
// Static content
String home = System.getenv("DAE_BASE");
if (home == null) {
home = "src/main/assembly";
}
home = home + "/www";
server.getServerConfiguration().addHttpHandler(new StaticHttpHandler(home), "/static");
logger.info("dae started");
logger.info(String.format("Management interface available at %sstatic/", baseUri));
logger.info("Use ctrl+c to stop ...");
// Signal handling
final CountDownLatch latch = new CountDownLatch(1);
Signal.handle(new Signal("INT"), new SignalHandler() {
public void handle(Signal sig) {
latch.countDown();
}
});
// Wait for termination, i.e. wait for ctrl+c
try {
latch.await();
} catch (InterruptedException e) {
}
server.stop();
}
}

View File

@@ -1,58 +0,0 @@
/**
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.aq.ng;
import java.util.Map;
import javax.xml.bind.annotation.XmlRootElement;
import org.codehaus.jackson.map.annotate.JsonSerialize;
import org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion;
/**
* Resource descriptor - Used to identify and/or create resource on server
*/
@XmlRootElement
@JsonSerialize(include = Inclusion.NON_NULL) // Do not serialize NULL values
public class RDescriptor {
private String ref;
private String type;
private Map<String,String> parameter;
public String getRef() {
return ref;
}
public void setRef(String ref) {
this.ref = ref;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public Map<String, String> getParameter() {
return parameter;
}
public void setParameter(Map<String, String> parameter) {
this.parameter = parameter;
}
}

View File

@@ -1,31 +0,0 @@
package ch.psi.fda.aq.ng;
import org.glassfish.hk2.utilities.binding.AbstractBinder;
//import org.glassfish.jersey.media.sse.SseBroadcaster;
//import ch.psi.da.hub.model.Keystore;
import ch.psi.jcae.impl.DefaultChannelService;
public class ResourceBinder extends AbstractBinder {
@Override
protected void configure() {
// request scope binding
// bind(MyInjectablePerRequest.class).to(MyInjectablePerRequest.class).in(RequestScope.class);
// singleton binding
// bind(MyInjectableSingleton.class).in(Singleton.class);
// singleton instance binding
// KeystoreSerializer serializer = new KeystoreSerializer();
// Keystore keystore = serializer.deserialize();
// bind(new SseBroadcaster()).to(SseBroadcaster.class);
// bind(serializer).to(KeystoreSerializer.class);
// bind(new KeystoreBroadcaster()).to(KeystoreBroadcaster.class);
// bind(keystore).to(Keystore.class);
bind(new AcquisitionEngineNG(new DefaultChannelService())).to(AcquisitionEngineNG.class);
bind(new LManager()).to(LManager.class);
}
}

View File

@@ -1,405 +0,0 @@
/**
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.aq.ng;
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.aq.ng.rdescriptors.ProbeDescriptor;
import ch.psi.fda.aq.ng.rdescriptors.ShellDescriptor;
import ch.psi.fda.core.messages.ComponentMetadata;
import ch.psi.fda.core.messages.DataMessageMetadata;
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.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.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;
/**
* Mapper to transform a FDA v1 xml into the new internal model
*
*/
public class ScanMapperNG {
// Reserved resource id's
private static final String PROBE_RESOURCE_ID = "probe";
private static final String SHELL_RESOURCE_ID = "shell";
// "logger" is also a special variable as it is bound to the logger of the application!
private static final Logger logger = Logger.getLogger(ScanMapperNG.class.getName());
private static final String INDENT = " ";
private StringBuilder script = new StringBuilder();
private Set<String> imports = new HashSet<>();
private Map<String, Object> resourceDescriptors = new HashMap<>();
private ProbeDescriptor probeDescriptor = new ProbeDescriptor();
private DataMessageMetadata dataMessageMetadata = new DataMessageMetadata();
private String indentation = "";
public void map(Configuration configuration) {
// Clear object state
script = new StringBuilder();
imports = new HashSet<>();
resourceDescriptors = new HashMap<>();
probeDescriptor = new ProbeDescriptor();
resourceDescriptors.put(PROBE_RESOURCE_ID, probeDescriptor);
Scan scan = configuration.getScan();
mapActions(scan.getPreAction());
// Bring the dimensions into the correct order and then map them
// to the script
List<Dimension> dimensions = new ArrayList<>();
int size = scan.getDimension().size();
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) {
dimensions.add(scan.getCdimension());
}
mapDimensions(dimensions, 0);
// map
mapActions(scan.getPostAction());
// 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(s + "\n");
}
scriptlines.append(script);
return scriptlines.toString();
}
/**
* Get map of required resources
* @return
*/
public Map<String, Object> getResourceDescriptors(){
return resourceDescriptors;
}
/**
* TODO need to be moved somewhere else
* @return
*/
public DataMessageMetadata getDataMessageMetadata(){
return dataMessageMetadata;
}
private void mapDimensions(List<Dimension> 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;
mapActions(d.getPreAction());
List<String> actuators = new ArrayList<>();
for(DiscreteStepPositioner positioner: d.getPositioner()){
Class<?> type = String.class;
switch (positioner.getType()) {
case "Integer":
type = Integer.class;
break;
case "Double":
type = Double.class;
break;
}
String var = getChannelResourceVariable(positioner.getName(), type, false);
actuators.add(var);
// Readback
if(positioner.getReadback()==null){
probeDescriptor.getSensors().add(new ChannelDescriptor<>(type, positioner.getName(), false));
}
else{
// Use readback
probeDescriptor.getSensors().add(new ChannelDescriptor<>(type, positioner.getReadback(), false));
}
// System.out.println(positioner.getId());
dataMessageMetadata.getComponents().add(new ComponentMetadata(positioner.getId(), (dimensions.size()-1-index)));
// TODO Done resource
if(positioner instanceof LinearPositioner){
// Calculate steps and add it to position array
LinearPositioner lpositioner = (LinearPositioner) positioner;
boolean first = true;
StringBuffer b = new StringBuffer();
b.append("[");
for(double i=0;(lpositioner.getStart()+i*lpositioner.getStepSize())<=lpositioner.getEnd();i++){
if(first){
first=false;
}
else{
b.append(",");
}
b.append(String.format("%f", (lpositioner.getStart()+i*lpositioner.getStepSize())));
}
b.append("]");
script.append(indentation + var+"_positions="+b.toString()+"\n");
}
else if(positioner instanceof ArrayPositioner){
ArrayPositioner apositioner = (ArrayPositioner) positioner;
// Calculate positions
String[] positions = apositioner.getPositions().trim().split(" +");
boolean first = true;
StringBuffer b = new StringBuffer();
b.append("[");
for(String po: positions){
if(first){
first=false;
}
else{
b.append(",");
}
b.append(getPythonValue(po, type));
}
b.append("]");
script.append(indentation + var+"_positions="+b.toString()+"\n");
}
else if(positioner instanceof FunctionPositioner){
// TODO take variable mappings into account !
}
else if(positioner instanceof PseudoPositioner){
// TODO implement
}
else if(positioner instanceof RegionPositioner){
// TODO implement
}
}
// Create dimension loop
String v = getUniqueVariableName();
script.append(indentation + "for "+v+"_idx ,"+v+"_pos in enumerate("+actuators.get(0)+"_positions):\n");
indentation = indentation + INDENT;
// Set all actuators of this dimension
for(String a: actuators){
script.append(indentation + a+".setValue("+a+"_positions["+v+"_idx])\n");
}
// Add all actions executed between actuator and sensors
mapActions(d.getAction());
// TODO map guard and sensors
// Check whether final dimension reached
if ((index + 1) < dimensions.size()) {
// Map next dimension
mapDimensions(dimensions, (index + 1));
}
else{
// Final dimension reached - readout probe
script.append(indentation + PROBE_RESOURCE_ID+".read()\n");
}
indentation = indentation.replaceFirst(INDENT, ""); // decrease indentation
script.append(indentation + PROBE_RESOURCE_ID+".delimiter("+(dimensions.size()-1-index)+", "+(d.isDataGroup()?"True":"False")+")\n");
// send delimiter for this dimension
// if lowest dimension end of stream message
// if highest dimension no delimiter
if(index==0){
script.append(indentation + PROBE_RESOURCE_ID+".terminateStream()\n");
}
mapActions(d.getPostAction());
} else if (dimension instanceof ContinuousDimension) {
// ContinuousDimension d = (ContinuousDimension) dimension;
// TODO Map continuous dimension
}
}
private void mapActions(List<Action> 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+".setValueNoWait("+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;
}
// If delay is specified wait specified time
if (ca.getDelay() != null) {
imports.add("import time");
script.append("time.sleep(" + (ca.getDelay()) + ")\n");
}
} else if (action instanceof ShellAction) {
ShellAction saction = (ShellAction) action;
resourceDescriptors.put(SHELL_RESOURCE_ID, new ShellDescriptor());
// TODO Need to indicate that shell resource is required
script.append(indentation + String.format(SHELL_RESOURCE_ID+".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+"\n");
}
script.append(indentation + "\n");
}
}
}
/**
* 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 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 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;
}
}

View File

@@ -1,94 +0,0 @@
/**
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.aq.ng.resources;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import ch.psi.fda.core.messages.DataMessage;
import ch.psi.fda.core.messages.EndOfStreamMessage;
import ch.psi.fda.core.messages.Message;
import ch.psi.fda.core.messages.StreamDelimiterMessage;
import ch.psi.jcae.Channel;
import ch.psi.jcae.ChannelException;
/**
* @author ebner
*
*/
public class ChannelProbeResource {
private final List<Channel<?>> channels;
private BlockingQueue<Message> queue;
public ChannelProbeResource(List<Channel<?>> channels, BlockingQueue<Message> queue){
this.channels = channels;
this.queue = queue;
}
/**
* Read configured channels and send out data message
*/
public void read(){
try{
DataMessage message = new DataMessage();
for(Channel<?> sensor: channels){
// Readout sensor
Object o = sensor.getValue();
// Add sensor data item to message
message.getData().add(o);
}
System.out.println("MESSAGE: "+message);
queue.put(message);
} catch (InterruptedException | TimeoutException | ChannelException | ExecutionException e) {
throw new RuntimeException(e);
}
}
/**
* Send a stream delimiter message for the given index
* @param index
* @param iflag
*/
public void delimiter(int index, boolean iflag){
try {
StreamDelimiterMessage message = new StreamDelimiterMessage(index, iflag);
System.out.println(message);
queue.put(message);
} catch (InterruptedException e) {
throw new RuntimeException("Unable to send delimiter message", e);
}
}
/**
* Send end of stream message
*/
public void terminateStream(){
try {
EndOfStreamMessage message = new EndOfStreamMessage();
System.out.println(message);
queue.put(message);
} catch (InterruptedException e) {
throw new RuntimeException("Unable to send end of stream message", e);
}
}
}

View File

@@ -1,73 +0,0 @@
/**
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.aq.ng.resources;
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());
/**
* Execute script/command in shell
* @param script
*/
public void execute(String script){
execute(script, 0, true);
}
/**
* Execute script/command in shell
* @param script
* @param returnValue
* @param checkReturnValue
*/
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);
}
}
}

View File

@@ -19,10 +19,6 @@
package ch.psi.fda.core;
/**
* @author ebner
*
*/
public interface Action {
/**
@@ -34,13 +30,4 @@ public interface Action {
* Abort the execution logic of the action
*/
public void abort();
/**
* Destroy action.
* Can be used for the cleanup of used resources of the action (e.g. to close connections, ...) if
* this cannot be done automatically by the GarbageCollector.
*
* After calling this method the action must not be executed any more!
*/
public void destroy();
}

View File

@@ -21,14 +21,11 @@ package ch.psi.fda.core;
import java.util.List;
import ch.psi.fda.core.messages.DataQueue;
import com.google.common.eventbus.EventBus;
/**
* Loop of actions to accomplish a task. Depending on the loop
* actions may be executed in a different way.
*
* @author ebner
*
*/
public interface ActionLoop extends Action {
@@ -65,5 +62,5 @@ public interface ActionLoop extends Action {
*/
public void setDataGroup(boolean dataGroup);
public DataQueue getDataQueue();
public EventBus getEventBus();
}

View File

@@ -19,11 +19,6 @@
package ch.psi.fda.core;
/**
*
* @author ebner
*
*/
public interface Actor {
/**
* Set actor value
@@ -51,14 +46,4 @@ public interface Actor {
* Reset the actuator to its initial configuration
*/
public void reset();
/**
* Destroy action.
* Can be used for the cleanup of used resources of the actor (e.g. to close connections, ...) if
* this cannot be done automatically by the GarbageCollector.
*
* After calling this method the actor must not be used any more!
*/
public void destroy();
}

View File

@@ -23,25 +23,18 @@ import java.util.concurrent.Callable;
/**
* Callable used for parallel execution of the set method of an actor
* @author ebner
*
*/
public class ActorSetCallable implements Callable<Object> {
// Callable actor
private Actor actor;
public ActorSetCallable(Actor actor){
this.actor = actor;
}
/* (non-Javadoc)
* @see java.util.concurrent.Callable#call()
*/
@Override
public Object call() throws Exception {
actor.set();
return null;
}
}

View File

@@ -1,87 +0,0 @@
/**
*
* Copyright 2010 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 <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core;
/**
* Singleton object for holing the core engine configuration
*
* @author ebner
*/
public class EngineConfiguration {
/**
* Flag to indicate whether the engine should fail if there is an error while reading out a sensor.
*/
private boolean failOnSensorError = true;
/**
* Flag to indicate whether the set value of the actor should be verified after the set operation.
* Having this flag on true will enable detecting for example that a motor hit the end switch or
* did not move correctly.
*/
private boolean checkActorSet = true;
/**
* Singleton instance
*/
private final static EngineConfiguration instance = new EngineConfiguration();
private EngineConfiguration(){
}
/**
* Get singleton instance of this class
* @return Engine configuration
*/
public static EngineConfiguration getInstance(){
return instance;
}
/**
* @return the failOnSensorError
*/
public boolean isFailOnSensorError() {
return failOnSensorError;
}
/**
* @param failOnSensorError the failOnSensorError to set
*/
public void setFailOnSensorError(boolean failOnSensorError) {
this.failOnSensorError = failOnSensorError;
}
/**
* @return the checkActorSet
*/
public boolean isCheckActorSet() {
return checkActorSet;
}
/**
* @param checkActorSet the checkActorSet to set
*/
public void setCheckActorSet(boolean checkActorSet) {
this.checkActorSet = checkActorSet;
}
}

View File

@@ -25,9 +25,6 @@ package ch.psi.fda.core;
*
* Example:
* An Guard can be used to check whether an injection happened while the the detector were read.
*
* @author ebner
*
*/
public interface Guard {
@@ -41,13 +38,4 @@ public interface Guard {
* @return Returns true if the guard condition was not constrainted since the last init call. False otherwise.
*/
public boolean check();
/**
* Destroy guard.
* Can be used for the cleanup of used resources of the guard (e.g. to close connections, ...) if
* this cannot be done automatically by the GarbageCollector.
*
* After calling this method the guard must not be used any more!
*/
public void destroy();
}

View File

@@ -17,15 +17,13 @@
*
*/
package ch.psi.fda.core.manipulator;
package ch.psi.fda.core;
import java.util.List;
import ch.psi.fda.core.messages.DataMessage;
import ch.psi.fda.core.messages.DataMessageMetadata;
import ch.psi.fda.core.messages.Metadata;
/**
* @author ebner
*
*/
public interface Manipulation {
/**
@@ -38,7 +36,7 @@ public interface Manipulation {
* Initialize the manipulation
* @param metadata Metadata of the incomming data message
*/
public void initialize(DataMessageMetadata metadata);
public void initialize(List<Metadata> metadata);
/**
* Execute the manipulation on the passed data message

View File

@@ -23,8 +23,6 @@ package ch.psi.fda.core;
* The sensor interface describes an entity that can be read out like a
* simple channel or (image) detector. Depending on the sensor type the
* returned data is of a certain type.
* @author ebner
*
*/
public interface Sensor {
/**
@@ -38,13 +36,4 @@ public interface Sensor {
* @return id of sensor
*/
public String getId();
/**
* Destroy sensor.
* Can be used for the cleanup of used resources of the sensor (e.g. to close connections, ...) if
* this cannot be done automatically by the GarbageCollector.
*
* After calling this method the sensor must not be used any more!
*/
public void destroy();
}

View File

@@ -2,15 +2,15 @@
*
* Copyright 2010 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 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.
* 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 <http://www.gnu.org/licenses/>.
@@ -19,145 +19,106 @@
package ch.psi.fda.core.actions;
import java.util.Comparator;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.logging.Logger;
import ch.psi.fda.core.Action;
import ch.psi.jcae.Channel;
import ch.psi.jcae.ChannelDescriptor;
import ch.psi.jcae.ChannelException;
import ch.psi.jcae.ChannelService;
/**
* Perform a put on the specified Channel Access channel. The put can be done
* synchronous or asynchronously.
*
* @author ebner
*
* Perform a put on the specified Channel Access channel. The put can be done synchronous or
* asynchronously.
*/
public class ChannelAccessCondition<E> implements Action {
// Get Logger
private static Logger logger = Logger.getLogger(ChannelAccessCondition.class.getName());
/**
* Channel to set
*/
private final Channel<E> channel;
/**
* Value to wait for
*/
private final E expectedValue;
private Long timeout;
private final Comparator<E> comparator;
private final Long timeout;
private volatile boolean abort = false;
private volatile Thread waitT = null;
/**
* Constructor
* @param channel Channel to wait value for
* @param expectedValue Value to wait for
* @param timeout Timeout of the condition in milliseconds (null accepted - will take default wait timeout for channels ch.psi.jcae.ChannelBeanFactory.waitTimeout)
*
* @param channelName
* Name of the channel to set the value
* @param expectedValue
* Value to wait for
* @param timeout
* Timeout of the condition in milliseconds (null accepted - will
* take default wait timeout for channels
* ch.psi.jcae.ChannelBeanFactory.waitTimeout)
*
* @throws IllegalArgumentException
* Unable to initialize channel, Timeout specified is not >=0
* @throws IllegalArgumentException Timeout specified is not >=0
*/
@SuppressWarnings("unchecked")
public ChannelAccessCondition(ChannelService s, String channelName, E expectedValue, Long timeout) {
public ChannelAccessCondition(Channel<E> channel, E expectedValue, Long timeout){
if (timeout != null && timeout <= 0) {
if(timeout != null && timeout<=0){
throw new IllegalArgumentException("Timeout must be > 0");
}
try {
this.channel = (Channel<E>) s.createChannel(new ChannelDescriptor<>(expectedValue.getClass(), channelName, false));
} catch (ChannelException | TimeoutException e) {
throw new IllegalArgumentException("Unable to initialize actuator channel [name:" + channelName + "]", e);
} catch (InterruptedException e) {
throw new RuntimeException("Unable to initialize actuator channel [name:" + channelName + "]", e);
}
this.channel = channel;
this.expectedValue = expectedValue;
this.comparator = null;
this.timeout = timeout;
}
public ChannelAccessCondition(Channel<E> channel, E expectedValue, Comparator<E> comparator, Long timeout){
if (timeout == null) {
// this.timeout = channel.get.getWaitTimeout();
this.timeout=1L;
} else {
this.timeout = timeout;
if(timeout != null && timeout<=0){
throw new IllegalArgumentException("Timeout must be > 0");
}
this.channel = channel;
this.expectedValue = expectedValue;
this.comparator = comparator;
this.timeout = timeout;
}
/*
* (non-Javadoc)
*
* @see ch.psi.fda.core.Action#execute()
*/
/**
* @throws InterruptedException
* @throws RuntimeException
* Channel value did not reach expected value (within the
* specified timeout period)
* @throws RuntimeException Channel value did not reach expected value (within the specified timeout period)
*/
@Override
public void execute() throws InterruptedException {
abort = false;
logger.finest("Checking channel " + channel.getName() + " for value " + expectedValue + " [timeout: " + timeout + "]");
try {
abort=false;
logger.finest("Checking channel "+channel.getName()+" for value "+expectedValue+" [timeout: "+timeout+"]" );
try{
waitT = Thread.currentThread();
channel.waitForValueAsync(expectedValue).get(timeout, TimeUnit.MILLISECONDS); // Workaround use
// 10seconds default
// set timeout to
// check several
// times whether the
// channel has
// reached the value
} catch (InterruptedException e) {
if (!abort) {
throw e;
try {
if(comparator==null){
if(timeout == null){
channel.waitForValue(expectedValue);
}
else{
channel.waitForValue(expectedValue, timeout);
}
}
else{
if(timeout == null){
channel.waitForValue(expectedValue, comparator);
}
else{
channel.waitForValue(expectedValue, comparator, timeout);
}
}
} catch (ExecutionException | ChannelException | TimeoutException | InterruptedException e) {
if(abort && e instanceof InterruptedException){
return;
}
throw new RuntimeException("Channel [name:"+channel.getName()+"] did not reach expected value "+expectedValue+" ", e);
}
} catch (ExecutionException | TimeoutException | ChannelException e) {
throw new RuntimeException("Channel [name:" + channel.getName() + "] did not reach expected value " + expectedValue + " ", e);
} finally {
waitT = null;
}
finally{
waitT=null;
}
}
/*
* (non-Javadoc)
*
* @see ch.psi.fda.core.Action#abort()
*/
@Override
public void abort() {
abort = true;
if (waitT != null) {
abort=true;
if(waitT!=null){
waitT.interrupt();
}
}
/*
* (non-Javadoc)
*
* @see ch.psi.fda.core.Action#destroy()
*/
@Override
public void destroy() {
// Destroy channel
logger.finest("Destroy action channel: " + channel.getName());
try {
channel.destroy();
} catch (ChannelException e) {
throw new RuntimeException("Unable to destroy channel [" + channel.getName() + "]", e);
}
}
}

View File

@@ -1,159 +0,0 @@
/**
*
* Copyright 2010 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 <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.actions;
import java.util.Comparator;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import java.util.logging.Logger;
import ch.psi.fda.core.Action;
import ch.psi.jcae.Channel;
import ch.psi.jcae.ChannelDescriptor;
import ch.psi.jcae.ChannelException;
import ch.psi.jcae.ChannelService;
/**
* Perform a put on the specified Channel Access channel. The put can be done synchronous or
* asynchronously.
* @author ebner
*
*/
public class ChannelAccessConditionAnd<E extends Integer> implements Action {
// Get Logger
private static Logger logger = Logger.getLogger(ChannelAccessConditionAnd.class.getName());
/**
* Channel to set
*/
private final Channel<E> channel;
/**
* Value to wait for
*/
private final E expectedValue;
private final Long timeout;
private volatile boolean abort = false;
private volatile Thread waitT = null;
/**
* Constructor
* @param channelName Name of the channel to set the value
* @param expectedValue Value to wait for
* @param timeout Timeout of the condition in milliseconds (null accepted - will take default wait timeout for channels ch.psi.jcae.ChannelBeanFactory.waitTimeout)
*
* @throws IllegalArgumentException Unable to initialize channel,
* Timeout specified is not >=0
*/
@SuppressWarnings("unchecked")
public ChannelAccessConditionAnd(ChannelService s, String channelName, E expectedValue, Long timeout){
if(timeout !=null && timeout<=0){
throw new IllegalArgumentException("Timeout must be > 0");
}
try {
this.channel = s.createChannel(new ChannelDescriptor<>( (Class<E>) expectedValue.getClass(), channelName, false));
} catch (ChannelException | TimeoutException e) {
// Convert Exception into unchecked RuntimeException
throw new IllegalArgumentException("Unable to initialize actuator channel [name:"+channelName+"]",e);
} catch (InterruptedException e) {
throw new RuntimeException("Unable to initialize actuator channel [name:"+channelName+"]",e);
}
this.expectedValue = expectedValue;
if(timeout==null){
// this.timeout = channel.getWaitTimeout();
this.timeout = 0L;
}
else{
this.timeout = timeout;
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Action#execute()
*/
/**
* @throws InterruptedException
* @throws RuntimeException Channel value did not reach expected value (within the specified timeout period)
*/
@Override
public void execute() throws InterruptedException {
abort=false;
logger.finest("Checking channel "+channel.getName()+" for value "+expectedValue+" [timeout: "+timeout+"]" );
try{
waitT = Thread.currentThread();
channel.waitForValue(expectedValue, new Comparator<E>() {
@Override
public int compare(E o1, E o2) {
int one = o1;
int two = o2;
if((one & two) != 0){
return 0;
}
return 1;
}
}
, timeout); // Workaround use 10seconds default set timeout to check several times whether the channel has reached the value
} catch (ChannelException | ExecutionException e) {
throw new RuntimeException("Channel [name:"+channel.getName()+"] did not reach expected value "+expectedValue+" ", e);
} catch(InterruptedException e){
if(!abort){
throw e;
}
}
finally{
waitT=null;
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Action#abort()
*/
@Override
public void abort() {
abort=true;
if(waitT!=null){
waitT.interrupt();
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Action#destroy()
*/
@Override
public void destroy() {
// Destroy channel
try {
logger.finest("Destroy action channel: "+channel.getName());
channel.destroy();
} catch (ChannelException e) {
throw new RuntimeException("Unable to destroy channel ["+channel.getName()+"]",e);
}
}
}

View File

@@ -1,159 +0,0 @@
/**
*
* Copyright 2010 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 <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.actions;
import java.util.Comparator;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import java.util.logging.Logger;
import ch.psi.fda.core.Action;
import ch.psi.jcae.Channel;
import ch.psi.jcae.ChannelDescriptor;
import ch.psi.jcae.ChannelException;
import ch.psi.jcae.ChannelService;
/**
* Perform a put on the specified Channel Access channel. The put can be done synchronous or
* asynchronously.
* @author ebner
*
*/
public class ChannelAccessConditionOr<E extends Integer> implements Action {
// Get Logger
private static Logger logger = Logger.getLogger(ChannelAccessConditionOr.class.getName());
/**
* Channel to set
*/
private final Channel<E> channel;
/**
* Value to wait for
*/
private final E expectedValue;
private final Long timeout;
private volatile boolean abort = false;
private volatile Thread waitT = null;
/**
* Constructor
* @param channelName Name of the channel to set the value
* @param expectedValue Value to wait for
* @param timeout Timeout of the condition in milliseconds (null accepted - will take default wait timeout for channels ch.psi.jcae.ChannelBeanFactory.waitTimeout)
*
* @throws IllegalArgumentException Unable to initialize channel,
* Timeout specified is not >=0
*/
@SuppressWarnings("unchecked")
public ChannelAccessConditionOr(ChannelService s, String channelName, E expectedValue, Long timeout){
if(timeout !=null && timeout<=0){
throw new IllegalArgumentException("Timeout must be > 0");
}
try {
this.channel = s.createChannel(new ChannelDescriptor<>( (Class<E>) expectedValue.getClass(), channelName, false));
} catch (ChannelException | TimeoutException e) {
// Convert Exception into unchecked RuntimeException
throw new IllegalArgumentException("Unable to initialize actuator channel [name:"+channelName+"]",e);
} catch (InterruptedException e) {
throw new RuntimeException("Unable to initialize actuator channel [name:"+channelName+"]",e);
}
this.expectedValue = expectedValue;
if(timeout==null){
// this.timeout = channel.getWaitTimeout();
this.timeout = 0L;
}
else{
this.timeout = timeout;
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Action#execute()
*/
/**
* @throws InterruptedException
* @throws RuntimeException Channel value did not reach expected value (within the specified timeout period)
*/
@Override
public void execute() throws InterruptedException {
abort=false;
logger.finest("Checking channel "+channel.getName()+" for value "+expectedValue+" [timeout: "+timeout+"]" );
try{
waitT = Thread.currentThread();
channel.waitForValue(expectedValue, new Comparator<E>() {
@Override
public int compare(E o1, E o2) {
int one = o1;
int two = o2;
if((one | two) != 0){
return 0;
}
return 1;
}
}
, timeout); // Workaround use 10seconds default set timeout to check several times whether the channel has reached the value
} catch (ChannelException | ExecutionException e) {
throw new RuntimeException("Channel [name:"+channel.getName()+"] did not reach expected value "+expectedValue+" ", e);
} catch(InterruptedException e){
if(!abort){
throw e;
}
}
finally{
waitT=null;
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Action#abort()
*/
@Override
public void abort() {
abort=true;
if(waitT!=null){
waitT.interrupt();
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Action#destroy()
*/
@Override
public void destroy() {
// Destroy channel
try {
logger.finest("Destroy action channel: "+channel.getName());
channel.destroy();
} catch (ChannelException e) {
throw new RuntimeException("Unable to destroy channel ["+channel.getName()+"]",e);
}
}
}

View File

@@ -1,153 +0,0 @@
/**
*
* Copyright 2010 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 <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.actions;
import java.util.Comparator;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import java.util.logging.Logger;
import ch.psi.fda.core.Action;
import ch.psi.jcae.Channel;
import ch.psi.jcae.ChannelDescriptor;
import ch.psi.jcae.ChannelException;
import ch.psi.jcae.ChannelService;
/**
* Perform a put on the specified Channel Access channel. The put can be done synchronous or
* asynchronously.
* @author ebner
*
*/
public class ChannelAccessConditionRegex<E extends String> implements Action {
// Get Logger
private static Logger logger = Logger.getLogger(ChannelAccessConditionRegex.class.getName());
/**
* Channel to set
*/
private final Channel<E> channel;
/**
* Value to wait for
*/
private final E expectedValue;
private final Long timeout;
private volatile boolean abort = false;
private volatile Thread waitT = null;
/**
* Constructor
* @param channelName Name of the channel to set the value
* @param expectedValue Value to wait for
* @param timeout Timeout of the condition in milliseconds (null accepted - will take default wait timeout for channels ch.psi.jcae.ChannelBeanFactory.waitTimeout)
*
* @throws IllegalArgumentException Unable to initialize channel,
* Timeout specified is not >=0
*/
@SuppressWarnings("unchecked")
public ChannelAccessConditionRegex(ChannelService s, String channelName, E expectedValue, Long timeout){
if(timeout !=null && timeout<=0){
throw new IllegalArgumentException("Timeout must be > 0");
}
try {
this.channel = s.createChannel(new ChannelDescriptor<>( (Class<E>) expectedValue.getClass(), channelName, false));
} catch (ChannelException | TimeoutException e) {
// Convert Exception into unchecked RuntimeException
throw new IllegalArgumentException("Unable to initialize actuator channel [name:"+channelName+"]",e);
} catch (InterruptedException e) {
throw new RuntimeException("Unable to initialize actuator channel [name:"+channelName+"]",e);
}
this.expectedValue = expectedValue;
if(timeout==null){
// this.timeout = channel.getWaitTimeout();
this.timeout = 0L;
}
else{
this.timeout = timeout;
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Action#execute()
*/
/**
* @throws InterruptedException
* @throws RuntimeException Channel value did not reach expected value (within the specified timeout period)
*/
@Override
public void execute() throws InterruptedException {
abort=false;
logger.finest("Checking channel "+channel.getName()+" for value "+expectedValue+" [timeout: "+timeout+"]" );
try{
waitT = Thread.currentThread();
channel.waitForValue(expectedValue, new Comparator<E>() {
@Override
public int compare(E o1, E o2) {
return o1.matches(o2) ? 0:1;
}
}, timeout); // Workaround use 10seconds default set timeout to check several times whether the channel has reached the value
} catch (ChannelException | ExecutionException e) {
throw new RuntimeException("Channel [name:"+channel.getName()+"] did not reach expected value "+expectedValue+" ", e);
} catch(InterruptedException e){
if(!abort){
throw e;
}
}
finally{
waitT=null;
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Action#abort()
*/
@Override
public void abort() {
abort=true;
if(waitT!=null){
waitT.interrupt();
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Action#destroy()
*/
@Override
public void destroy() {
// Destroy channel
try {
logger.finest("Destroy action channel: "+channel.getName());
channel.destroy();
} catch (ChannelException e) {
throw new RuntimeException("Unable to destroy channel ["+channel.getName()+"]",e);
}
}
}

View File

@@ -26,57 +26,31 @@ import java.util.logging.Logger;
import ch.psi.fda.core.Action;
import ch.psi.jcae.Channel;
import ch.psi.jcae.ChannelDescriptor;
import ch.psi.jcae.ChannelException;
import ch.psi.jcae.ChannelService;
/**
* Perform a put on the specified Channel Access channel. The put can be done synchronous or
* asynchronously.
* @author ebner
*
*/
public class ChannelAccessPut<E> implements Action {
// Get Logger
private static Logger logger = Logger.getLogger(ChannelAccessPut.class.getName());
/**
* Channel to set
*/
private final Channel<E> channel;
/**
* Value to set
*/
private final E value;
/**
* Put mode, true = fire and forget, false = wait for response
*/
private final boolean asynchronous;
private final Long timeout;
/**
* Constructor
* @param channelName Name of the channel to set the value
* @param channel
* @param value Value to set
* @param asynchronous Flag whether to set the value synchronous (wait for response) or asynchronously (fire and forget)
* @param timeout Timeout used for set operation (time that set need to come back)
*
* @throws IllegalArgumentException Unable to initialize channel
*/
@SuppressWarnings("unchecked")
public ChannelAccessPut(ChannelService s, String channelName, E value, boolean asynchronous, Long timeout){
public ChannelAccessPut(Channel<E> channel, E value, boolean asynchronous, Long timeout){
try {
this.channel = s.createChannel(new ChannelDescriptor<>((Class<E>)value.getClass(), channelName, false));
} catch (ChannelException | TimeoutException e) {
// Convert Exception into unchecked RuntimeException
throw new IllegalArgumentException("Unable to initialize actuator channel [name:"+channelName+"]",e);
} catch (InterruptedException e) {
throw new RuntimeException("Unable to initialize actuator channel [name:"+channelName+"]",e);
}
this.channel = channel;
this.value = value;
this.asynchronous = asynchronous;
this.timeout = timeout;
@@ -84,20 +58,14 @@ public class ChannelAccessPut<E> implements Action {
/**
* Additional constructor for convenience. This constructor defaults the operation type to synchronous put.
* @param channelName Name of the channel to set the value
* @param channel
* @param value Value to set
*
* @throws RuntimeException Unable to initialize channel
*/
public ChannelAccessPut(ChannelService s, String channelName, E value){
this(s, channelName, value, false, null);
public ChannelAccessPut(Channel<E> channel, E value){
this(channel, value, false, null);
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Action#execute()
*/
/**
* @throws InterruptedException
* @throws RuntimeException Cannot set value on channel
*/
@Override
@@ -115,32 +83,12 @@ public class ChannelAccessPut<E> implements Action {
channel.setValueAsync(value).get(timeout, TimeUnit.MILLISECONDS);
}
}
} catch (ChannelException | ExecutionException | TimeoutException e) {
// Convert Exception into unchecked RuntimeException
} catch (ExecutionException | TimeoutException | ChannelException e) {
throw new RuntimeException("Unable to set channel [name:"+channel.getName()+"] to value "+value, e);
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Action#abort()
*/
@Override
public void abort() {
// This action cannot be aborted, therefore this method is not implemented
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Action#destroy()
*/
@Override
public void destroy() {
// Destroy channel
try {
logger.finest("Destroy action channel: "+channel.getName());
channel.destroy();
} catch (ChannelException e) {
throw new RuntimeException("Unable to destroy channel ["+channel.getName()+"]",e);
}
}
}

View File

@@ -23,19 +23,13 @@ import ch.psi.fda.core.Action;
/**
* Wait a specific time until executing the next action ...
* @author ebner
*
*/
public class Delay implements Action {
/**
* Time to wait
*/
private final long time;
/**
* Constructor
* @param time Time to wait (in milliseconds)
* @param time Time to wait in milliseconds
*/
public Delay(long time){
@@ -47,28 +41,12 @@ public class Delay implements Action {
this.time = time;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Action#execute()
*/
@Override
public void execute() throws InterruptedException {
Thread.sleep(time);
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Action#abort()
*/
@Override
public void abort() {
// Not implemented because not needed
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Action#destroy()
*/
@Override
public void destroy() {
// Nothing to be done
}
}

View File

@@ -19,8 +19,9 @@
package ch.psi.fda.core.actions;
import java.util.List;
import java.util.concurrent.TimeoutException;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -30,20 +31,12 @@ import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import ch.psi.fda.core.Action;
import ch.psi.fda.core.scripting.JythonParameterMapping;
import ch.psi.fda.core.scripting.JythonParameterMappingChannel;
import ch.psi.jcae.Channel;
import ch.psi.jcae.ChannelDescriptor;
import ch.psi.jcae.ChannelException;
import ch.psi.jcae.ChannelService;
/**
* @author ebner
*
* Executes a python script inside a Jython interpreter
*/
public class JythonAction implements Action {
// Get Logger
private static Logger logger = Logger.getLogger(JythonAction.class.getName());
/**
@@ -52,17 +45,19 @@ public class JythonAction implements Action {
private static final String entryFunction = "process";
private static final String entryFunctionPattern = "def "+entryFunction+"\\((.*)\\):";
/**
* Script engine of the manipulator
*/
private ScriptEngine engine;
/**
* Jython entry call
*/
private String jythonCall;
private String jythonCall; // entry call to script - including all parameters, etc.
private final Map<String,Object> globalObjects;
public JythonAction(String script, Map<String, ?> mapping){
this(script, mapping, new HashMap<String,Object>());
}
public JythonAction(String script, Map<String, ?> mapping, Map<String,Object> globalObjects){
public JythonAction(ChannelService s, String script, List<JythonParameterMappingChannel> mapping){
this.globalObjects = globalObjects;
// Workaround for Jython memory leak
// http://blog.hillbrecht.de/2009/07/11/jython-memory-leakout-of-memory-problem/
@@ -77,7 +72,13 @@ public class JythonAction implements Action {
String[] functionParameters = null;
if(matcher.find() && matcher.groupCount()==1){
logger.finest("Entry function '"+entryFunctionPattern+"' found - Identified parameters: "+matcher.group(1));
functionParameters = matcher.group(1).split(" *, *");
jythonCall = entryFunction+"("+matcher.group(1)+")";
if(matcher.group(1).matches(" *")){
functionParameters = new String[0];
}
else{
functionParameters = matcher.group(1).split(" *, *");
}
}
else{
throw new IllegalArgumentException("Cannot determine entry function: "+entryFunctionPattern);
@@ -88,8 +89,8 @@ public class JythonAction implements Action {
String p = functionParameters[i];
p = p.trim();
boolean found = false;
for(JythonParameterMapping pm: mapping){
if(pm.getVariable().equals(p)){
for(String pm: mapping.keySet()){
if(pm.equals(p)){
found=true;
break;
}
@@ -111,60 +112,31 @@ public class JythonAction implements Action {
throw new RuntimeException("Unable to load manipulation script", e);
}
StringBuffer buffer = new StringBuffer();
buffer.append(entryFunction);
buffer.append("(");
for(JythonParameterMappingChannel b: mapping){
// Create channel
Channel<?> cb;
try {
cb = s.createChannel(new ChannelDescriptor<>(b.getType(), b.getChannel(), true));
} catch (TimeoutException | ChannelException e) {
throw new IllegalArgumentException("Unable to establish channel: "+b.getChannel(), e);
} catch (InterruptedException e) {
throw new RuntimeException("Unable to establish channel: "+b.getChannel(), e);
}
for(String b: mapping.keySet()){
// Assign channel bean to variable
engine.put(b.getVariable(), cb);
buffer.append(b.getVariable());
buffer.append(",");
engine.put(b, mapping.get(b));
}
buffer.setCharAt(buffer.length()-1, ')');
jythonCall = buffer.toString();
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Action#execute()
*/
@Override
public void execute() {
// Set global objects
// This block is not in initialization as we want to assure that all invocations
// of this manipulation will get the same value (i.e. to prevent inconsistent behavior
// if variable was changed during an execution of the manipulation)
for(String k: globalObjects.keySet()){
engine.put(k, globalObjects.get(k));
}
try {
engine.eval(jythonCall);
engine.eval(jythonCall+"\n");
} catch (ScriptException e) {
throw new RuntimeException("Action failed while executing the Jython script",e);
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Action#abort()
*/
@Override
public void abort() {
// TODO need to find a way to abort script execution
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Action#destroy()
*/
@Override
public void destroy() {
// Nothing to be done
}
}

View File

@@ -29,13 +29,10 @@ import java.util.logging.Logger;
import ch.psi.fda.core.Action;
/**
* Action that executes a specified script when it is executed.
* @author ebner
*
* Action that executes a specified command when it is executed.
*/
public class ShellAction implements Action{
// Get Logger
private static Logger logger = Logger.getLogger(ShellAction.class.getName());
private volatile Process process;
@@ -50,8 +47,7 @@ public class ShellAction implements Action{
private final String script;
/**
* Constructor
* @param script Name of the script to execute when this action is invoked
* @param script Name of the command to execute when this action is invoked
*
* @throws IllegalArgumentException Specified script does not exist
*/
@@ -64,15 +60,6 @@ public class ShellAction implements Action{
this.script = script;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Action#execute()
*/
/**
* @throws InterruptedException
* @throws RuntimeException Script did not exit with 0,
* Execution was interrupted,
* IO problem occurred
*/
@Override
public void execute() throws InterruptedException {
try{
@@ -84,7 +71,7 @@ public class ShellAction implements Action{
// Log output of the shell script if loglevel is finest
if(logger.isLoggable(Level.FINEST)){
logger.finest("STDOUT [BEGIN]");
// TODO The readout of the stream should be in parallel to the processing of the script! I.e. the output appears in the log as it is generated by the script!
// Ideally the readout of the stream should be in parallel to the processing of the script! I.e. the output appears in the log as it is generated by the script!
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = null;
while((line=reader.readLine()) != null){
@@ -93,7 +80,7 @@ public class ShellAction implements Action{
logger.finest("STDOUT [END]");
logger.finest("STDERR [BEGIN]");
// TODO The readout of the stream should be in parallel to the processing of the script! I.e. the output appears in the log as it is generated by the script!
// Ideally the readout of the stream should be in parallel to the processing of the script! I.e. the output appears in the log as it is generated by the script!
reader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
line = null;
while((line=reader.readLine()) != null){
@@ -113,61 +100,33 @@ public class ShellAction implements Action{
throw new RuntimeException("Script ["+script+"] returned with an exit value not equal to 0");
}
}
process = null; // Ensure that the process is null
process = null;
}
catch(IOException e){
// Convert Exception into unchecked RuntimeException
throw new RuntimeException("Unable to execute script: "+script,e);
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Action#abort()
*/
@Override
public void abort() {
abort=true;
// This action cannot be aborted, therefore this function is not implemented.
if(process!=null){
// Terminate process via kill
process.destroy();
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Action#destroy()
*/
@Override
public void destroy() {
// Nothing to be done
}
/**
* @return the checkExitValue
*/
public boolean isCheckExitValue() {
return checkExitValue;
}
/**
* @param checkExitValue the checkExitValue to set
*/
public void setCheckExitValue(boolean checkExitValue) {
this.checkExitValue = checkExitValue;
}
/**
* @return the exitValue
*/
public int getExitValue() {
return exitValue;
}
/**
* @param exitValue the exitValue to set
*/
public void setExitValue(int exitValue) {
this.exitValue = exitValue;
}

View File

@@ -25,43 +25,18 @@ import java.util.concurrent.TimeoutException;
import java.util.logging.Logger;
import ch.psi.fda.core.Actor;
import ch.psi.fda.core.EngineConfiguration;
import ch.psi.jcae.Channel;
import ch.psi.jcae.ChannelDescriptor;
import ch.psi.jcae.ChannelException;
import ch.psi.jcae.ChannelService;
/**
* This actuator sets an Channel Access channel from a start to an end value by doing discrete steps.
* @author ebner
*
*/
public class ChannelAccessFunctionActuator<T> implements Actor {
// Get Logger
private static Logger logger = Logger.getLogger(ChannelAccessFunctionActuator.class.getName());
private boolean asynchronous = false;
/**
* Start value of the actuator
*/
private double start;
/**
* End value of the actuator
*/
private double end;
/**
* Step size of the move
*/
private double stepSize;
/**
* Move direction (start&lt;end = 1, start&gt;end = -1)
*/
private int direction;
private int direction; // Move direction (start&lt;end = 1, start&gt;end = -1)
/**
* Execution count of actuator. This variable is used to minimize the floating point
@@ -87,14 +62,9 @@ public class ChannelAccessFunctionActuator<T> implements Actor {
private double accuracy;
/**
* Channel Access channel of the actuator
* Move timeout
*/
private Channel<Double> channel;
/**
* Channel Access channel of the actuator
*/
private Channel<T> doneChannel = null;
private Long timeout;
private final T doneValue;
private final long doneDelay;
@@ -103,13 +73,11 @@ public class ChannelAccessFunctionActuator<T> implements Actor {
private final double originalEnd;
private final int originalDirection;
/**
* Move timeout
*/
private Long timeout;
private Channel<Double> channel;
private Channel<T> doneChannel = null;
private final Function function;
private boolean checkActorSet = true;
/**
* Constructor - Initialize actor
@@ -119,14 +87,14 @@ public class ChannelAccessFunctionActuator<T> implements Actor {
* @param stepSize
* @param timeout Maximum move time (in milliseconds)
*/
public ChannelAccessFunctionActuator(ChannelService s, String channelName, Function function, double start, double end, double stepSize, Long timeout){
this(s, channelName, null, null, 0, function, start, end, stepSize, timeout);
public ChannelAccessFunctionActuator(Channel<Double> channel, Function function, double start, double end, double stepSize, Long timeout){
this(channel, null, null, 0, function, start, end, stepSize, timeout);
}
/**
* Constructor
* @param channelName
* @param doneChannelName If null actor will not wait (for this channel) to continue
* @param channel
* @param doneChannel If null actor will not wait (for this channel) to continue
* @param doneValue
* @param doneDelay Delay in seconds before checking the done channel
* @param start
@@ -134,8 +102,7 @@ public class ChannelAccessFunctionActuator<T> implements Actor {
* @param stepSize
* @param timeout Maximum move time (in milliseconds)
*/
@SuppressWarnings("unchecked")
public ChannelAccessFunctionActuator(ChannelService s, String channelName, String doneChannelName, T doneValue, double doneDelay, Function function, double start, double end, double stepSize, Long timeout){
public ChannelAccessFunctionActuator(Channel<Double> channel, Channel<T> doneChannel, T doneValue, double doneDelay, Function function, double start, double end, double stepSize, Long timeout){
this.doneValue = doneValue;
this.doneDelay = (long) Math.floor((doneDelay*1000));
@@ -170,31 +137,10 @@ public class ChannelAccessFunctionActuator<T> implements Actor {
this.originalEnd = end;
this.originalDirection = direction;
// Initialize/create Channel Access channel
try {
channel = s.createChannel(new ChannelDescriptor<>(Double.class, channelName, false));
} catch (ChannelException | TimeoutException e) {
// Convert Exception into unchecked RuntimeException
throw new IllegalArgumentException("Unable to initialize actuator channel [name:"+channelName+"]",e);
} catch (InterruptedException e) {
throw new RuntimeException("Unable to initialize actuator channel [name:"+channelName+"]",e);
}
if(doneChannelName != null){
try {
doneChannel = s.createChannel(new ChannelDescriptor<>((Class<T>)doneValue.getClass(), doneChannelName, false));
} catch (ChannelException | TimeoutException e) {
// Convert Exception into unchecked RuntimeException
throw new IllegalArgumentException("Unable to initialize actuator channel [name:"+doneChannelName+"]",e);
} catch (InterruptedException e) {
throw new RuntimeException("Unable to initialize actuator channel [name:"+doneChannelName+"]",e);
}
}
this.channel = channel;
this.doneChannel = doneChannel;
}
/* (non-Javadoc)
* @see ch.psi.fda.engine.Actor#set()
*/
@Override
public void set() throws InterruptedException {
@@ -226,7 +172,7 @@ public class ChannelAccessFunctionActuator<T> implements Actor {
}
// Check whether the set value is really on the value that was set before.
if(EngineConfiguration.getInstance().isCheckActorSet()){
if(checkActorSet){
double c = channel.getValue(true);
double a = Math.abs( c - fvalue );
if ( a > accuracy ){
@@ -234,8 +180,7 @@ public class ChannelAccessFunctionActuator<T> implements Actor {
}
}
} catch (ChannelException | ExecutionException | TimeoutException e) {
// Convert Exception into unchecked RuntimeException
} catch (ExecutionException | TimeoutException | ChannelException e) {
throw new RuntimeException("Unable to move actuator [channel: "+channel.getName()+"] to value "+value,e);
}
@@ -258,17 +203,11 @@ public class ChannelAccessFunctionActuator<T> implements Actor {
}
}
/* (non-Javadoc)
* @see ch.psi.fda.engine.Actor#hasNext()
*/
@Override
public boolean hasNext() {
return next;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#init()
*/
@Override
public void init() {
this.count = 0;
@@ -278,16 +217,12 @@ public class ChannelAccessFunctionActuator<T> implements Actor {
if(start>end){
direction=-1; // Move in negative direction
}
// Set first set value to the start value
this.value = start;
this.next = true;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#reverse()
*/
@Override
public synchronized void reverse() {
double oldStart = start;
@@ -302,9 +237,6 @@ public class ChannelAccessFunctionActuator<T> implements Actor {
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#reset()
*/
@Override
public void reset() {
this.start = this.originalStart;
@@ -312,42 +244,10 @@ public class ChannelAccessFunctionActuator<T> implements Actor {
this.direction = this.originalDirection;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#destroy()
*/
@Override
public void destroy() {
// Destroy channel
try {
logger.finest("Destroy actor channel: "+channel.getName());
channel.destroy();
} catch (ChannelException e) {
throw new RuntimeException("Unable to destroy channel ["+channel.getName()+"]",e);
}
// Destroy done channel if exists
if(doneChannel != null){
try {
logger.finest("Destroy actor done channel: "+doneChannel.getName());
doneChannel.destroy();
} catch (ChannelException e) {
throw new RuntimeException("Unable to destroy channel ["+channel.getName()+"]",e);
}
}
}
/**
* @return the asynchronous
*/
public boolean isAsynchronous() {
return asynchronous;
}
/**
* @param asynchronous the asynchronous to set
*/
public void setAsynchronous(boolean asynchronous) {
this.asynchronous = asynchronous;
}
}

View File

@@ -25,42 +25,21 @@ import java.util.concurrent.TimeoutException;
import java.util.logging.Logger;
import ch.psi.fda.core.Actor;
import ch.psi.fda.core.EngineConfiguration;
import ch.psi.jcae.Channel;
import ch.psi.jcae.ChannelDescriptor;
import ch.psi.jcae.ChannelException;
import ch.psi.jcae.ChannelService;
/**
* This actuator sets an Channel Access channel from a start to an end value by doing discrete steps.
* @author ebner
*
*/
public class ChannelAccessLinearActuator<T> implements Actor {
// Get Logger
private static Logger logger = Logger.getLogger(ChannelAccessLinearActuator.class.getName());
private boolean asynchronous = false;
/**
* Start value of the actuator
*/
private double start;
/**
* End value of the actuator
*/
private double end;
/**
* Step size of the move
*/
private double stepSize;
/**
* Move direction (start&lt;end = 1, start&gt;end = -1)
*/
private int direction;
/**
@@ -86,15 +65,7 @@ public class ChannelAccessLinearActuator<T> implements Actor {
*/
private double accuracy;
/**
* Channel Access channel of the actuator
*/
private Channel<Double> channel;
/**
* Channel Access channel of the actuator
*/
private Channel<T> doneChannel = null;
private final T doneValue;
private final long doneDelay;
@@ -103,17 +74,17 @@ public class ChannelAccessLinearActuator<T> implements Actor {
private final double originalEnd;
private final int originalDirection;
private Long timeout; // Set timeout
/**
* Move timeout
*/
private Long timeout;
private final Channel<Double> channel;
private final Channel<T> doneChannel;
private boolean checkActorSet = true;
/**
* Constructor
* @param channelName
* @param doneChannelName If null actor will not wait (for this channel) to continue
* @param channel
* @param doneChannel If null actor will not wait (for this channel) to continue
* @param doneValue
* @param doneDelay Delay in seconds before checking the done channel
* @param start
@@ -121,8 +92,7 @@ public class ChannelAccessLinearActuator<T> implements Actor {
* @param stepSize
* @param timeout Maximum move time (in milliseconds)
*/
@SuppressWarnings("unchecked")
public ChannelAccessLinearActuator(ChannelService s, String channelName, String doneChannelName, T doneValue, double doneDelay, double start, double end, double stepSize, Long timeout){
public ChannelAccessLinearActuator(Channel<Double> channel, Channel<T> doneChannel, T doneValue, double doneDelay, double start, double end, double stepSize, Long timeout){
this.doneValue = doneValue;
this.doneDelay = (long) Math.floor((doneDelay*1000));
@@ -152,31 +122,10 @@ public class ChannelAccessLinearActuator<T> implements Actor {
this.originalEnd = end;
this.originalDirection = direction;
// Initialize/create Channel Access channel
try {
channel = s.createChannel(new ChannelDescriptor<>(Double.class, channelName, false));
} catch (ChannelException | TimeoutException e) {
// Convert Exception into unchecked RuntimeException
throw new IllegalArgumentException("Unable to initialize actuator channel [name:"+channelName+"]",e);
} catch (InterruptedException e) {
throw new RuntimeException("Unable to initialize actuator channel [name:"+channelName+"]",e);
}
if(doneChannelName != null){
try {
doneChannel = s.createChannel(new ChannelDescriptor<>((Class<T>) doneValue.getClass(), doneChannelName, false));
} catch (ChannelException | TimeoutException e) {
// Convert Exception into unchecked RuntimeException
throw new IllegalArgumentException("Unable to initialize actuator channel [name:"+doneChannelName+"]",e);
} catch (InterruptedException e) {
throw new RuntimeException("Unable to initialize actuator channel [name:"+doneChannelName+"]",e);
}
}
this.channel = channel;
this.doneChannel = doneChannel;
}
/* (non-Javadoc)
* @see ch.psi.fda.engine.Actor#set()
*/
@Override
public void set() throws InterruptedException {
@@ -207,7 +156,7 @@ public class ChannelAccessLinearActuator<T> implements Actor {
}
// Check whether the set value is really on the value that was set before.
if(EngineConfiguration.getInstance().isCheckActorSet()){
if(checkActorSet){
double c = channel.getValue(true);
double a = Math.abs( c - value );
if ( a > accuracy ){
@@ -215,8 +164,7 @@ public class ChannelAccessLinearActuator<T> implements Actor {
}
}
} catch (ChannelException | TimeoutException | ExecutionException e) {
// Convert Exception into unchecked RuntimeException
} catch (ExecutionException | TimeoutException | ChannelException e) {
throw new RuntimeException("Unable to move actuator [channel: "+channel.getName()+"] to value "+value,e);
}
@@ -235,17 +183,11 @@ public class ChannelAccessLinearActuator<T> implements Actor {
}
}
/* (non-Javadoc)
* @see ch.psi.fda.engine.Actor#hasNext()
*/
@Override
public boolean hasNext() {
return next;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#init()
*/
@Override
public void init() {
this.count = 0;
@@ -262,9 +204,6 @@ public class ChannelAccessLinearActuator<T> implements Actor {
this.next = true;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#reverse()
*/
@Override
public synchronized void reverse() {
double oldStart = start;
@@ -279,9 +218,6 @@ public class ChannelAccessLinearActuator<T> implements Actor {
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#reset()
*/
@Override
public void reset() {
this.start = this.originalStart;
@@ -289,44 +225,10 @@ public class ChannelAccessLinearActuator<T> implements Actor {
this.direction = this.originalDirection;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#destroy()
*/
@Override
public void destroy() {
// Destroy channel
try {
logger.finest("Destroy actor channel: "+channel.getName());
channel.destroy();
} catch (ChannelException e) {
throw new RuntimeException("Unable to destroy channel ["+channel.getName()+"]",e);
}
// Destroy done channel if exists
if(doneChannel != null){
try {
logger.finest("Destroy actor done channel: "+doneChannel.getName());
doneChannel.destroy();
} catch (ChannelException e) {
throw new RuntimeException("Unable to destroy channel ["+channel.getName()+"]",e);
}
}
}
/**
* @return the asynchronous
*/
public boolean isAsynchronous() {
return asynchronous;
}
/**
* @param asynchronous the asynchronous to set
*/
public void setAsynchronous(boolean asynchronous) {
this.asynchronous = asynchronous;
}
}

View File

@@ -25,11 +25,8 @@ import java.util.concurrent.TimeoutException;
import java.util.logging.Logger;
import ch.psi.fda.core.Actor;
import ch.psi.fda.core.EngineConfiguration;
import ch.psi.jcae.Channel;
import ch.psi.jcae.ChannelDescriptor;
import ch.psi.jcae.ChannelException;
import ch.psi.jcae.ChannelService;
/**
* This actuator sets an Channel Access channel by using the positions from the given table.
@@ -38,7 +35,6 @@ import ch.psi.jcae.ChannelService;
*/
public class ChannelAccessTableActuator<T> implements Actor {
// Get Logger
private static Logger logger = Logger.getLogger(ChannelAccessTableActuator.class.getName());
private boolean asynchronous = false;
@@ -66,14 +62,7 @@ public class ChannelAccessTableActuator<T> implements Actor {
private boolean next;
/**
* Channel Access channel of the actuator
*/
private Channel<Double> channel;
/**
* Channel Access channel of the actuator
*/
private Channel<T> doneChannel = null;
private final T doneValue;
@@ -90,6 +79,7 @@ public class ChannelAccessTableActuator<T> implements Actor {
*/
private Long timeout = null;
private boolean checkActorSet = true;
/**
* Constructor - Initialize actor
@@ -97,21 +87,20 @@ public class ChannelAccessTableActuator<T> implements Actor {
* @param table Position table with the explicit positions for each step
* @param timeout Maximum move time (in milliseconds)
*/
public ChannelAccessTableActuator(ChannelService s, String channelName, double[] table, Long timeout){
this(s, channelName, null, null, 0, table, timeout);
public ChannelAccessTableActuator(Channel<Double> channel, double[] table, Long timeout){
this(channel, null, null, 0, table, timeout);
}
/**
* Constructor
* @param channelName
* @param doneChannelName
* @param channel
* @param doneChannel
* @param doneValue
* @param doneDelay
* @param table
* @param timeout Maximum move time (in milliseconds)
*/
@SuppressWarnings("unchecked")
public ChannelAccessTableActuator(ChannelService s, String channelName, String doneChannelName, T doneValue, double doneDelay, double[] table, Long timeout){
public ChannelAccessTableActuator(Channel<Double> channel, Channel<T> doneChannel, T doneValue, double doneDelay, double[] table, Long timeout){
this.doneValue = doneValue;
this.doneDelay = (long) Math.floor((doneDelay*1000));
@@ -138,31 +127,10 @@ public class ChannelAccessTableActuator<T> implements Actor {
// Save the initial direction
this.originalPositiveDirection = positiveDirection;
// Initialize/create Channel Access channel
try {
channel = s.createChannel(new ChannelDescriptor<>(Double.class, channelName, false));
} catch (ChannelException | TimeoutException e) {
// Convert Exception into unchecked RuntimeException
throw new IllegalArgumentException("Unable to initialize actuator channel [name:"+channelName+"]",e);
} catch (InterruptedException e) {
throw new RuntimeException("Unable to initialize actuator channel [name:"+channelName+"]",e);
}
if(doneChannelName != null){
try {
doneChannel = s.createChannel(new ChannelDescriptor<>((Class<T>)doneValue.getClass(), doneChannelName, false));
} catch (ChannelException | TimeoutException e) {
// Convert Exception into unchecked RuntimeException
throw new IllegalArgumentException("Unable to initialize actuator channel [name:"+doneChannelName+"]",e);
} catch (InterruptedException e) {
throw new RuntimeException("Unable to initialize actuator channel [name:"+doneChannelName+"]",e);
}
}
this.channel = channel;
this.doneChannel = doneChannel;
}
/* (non-Javadoc)
* @see ch.psi.fda.engine.Actor#set()
*/
@Override
public void set() throws InterruptedException {
@@ -193,14 +161,13 @@ public class ChannelAccessTableActuator<T> implements Actor {
}
// Check whether the set value is really on the value that was set before.
if(doneChannel==null && !asynchronous && EngineConfiguration.getInstance().isCheckActorSet()){
if(doneChannel==null && !asynchronous && checkActorSet){
if ( Math.abs( channel.getValue() - table[count] ) > accuracy ){
throw new RuntimeException("Actor could not be set to the value "+table[count]+" The readback of the set value does not match the value that was set");
}
}
} catch (ChannelException | ExecutionException | TimeoutException e) {
// Convert Exception into unchecked RuntimeException
} catch (ExecutionException | ChannelException | TimeoutException e) {
throw new RuntimeException("Move actuator [channel: "+channel.getName()+"] to value "+table[count],e);
}
@@ -226,17 +193,11 @@ public class ChannelAccessTableActuator<T> implements Actor {
}
}
/* (non-Javadoc)
* @see ch.psi.fda.engine.Actor#hasNext()
*/
@Override
public boolean hasNext() {
return next;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#init()
*/
@Override
public void init() {
@@ -253,9 +214,6 @@ public class ChannelAccessTableActuator<T> implements Actor {
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#reverse()
*/
@Override
public void reverse() {
if(positiveDirection){
@@ -266,52 +224,15 @@ public class ChannelAccessTableActuator<T> implements Actor {
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#reset()
*/
@Override
public void reset() {
this.positiveDirection = this.originalPositiveDirection;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#destroy()
*/
@Override
public void destroy() {
// Destroy channel
try {
logger.finest("Destroy actor channel: "+channel.getName());
channel.destroy();
} catch (ChannelException e) {
throw new RuntimeException("Unable to destroy channel ["+channel.getName()+"]",e);
}
// Destroy done channel if exists
if(doneChannel != null){
try {
logger.finest("Destroy actor done channel: "+doneChannel.getName());
doneChannel.destroy();
} catch (ChannelException e) {
throw new RuntimeException("Unable to destroy channel ["+channel.getName()+"]",e);
}
}
}
/**
* @return the asynchronous
*/
public boolean isAsynchronous() {
return asynchronous;
}
/**
* @param asynchronous the asynchronous to set
*/
public void setAsynchronous(boolean asynchronous) {
this.asynchronous = asynchronous;
}
}

View File

@@ -31,13 +31,9 @@ import ch.psi.fda.core.Actor;
* steps of the actors that this actuator consists of.
* First all the steps of the first actor are used, after that the steps of the next actor are done.
* Before the first step of an actor pre actions are available and after the last step of an actor a post action is available.
*
* @author ebner
*
*/
public class ComplexActuator implements Actor {
// Get Logger
private static Logger logger = Logger.getLogger(ComplexActuator.class.getName());
/**
@@ -76,9 +72,6 @@ public class ComplexActuator implements Actor {
*/
private boolean firstrun;
/**
* Constructor
*/
public ComplexActuator(){
this.actors = new ArrayList<Actor>();
this.preActions = new ArrayList<Action>();
@@ -90,12 +83,8 @@ public class ComplexActuator implements Actor {
this.firstrun = true;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#set()
*/
@Override
public void set() throws InterruptedException {
// Throw an IllegalStateException in the case that set is called although there is no next step.
if(!next){
throw new IllegalStateException("The actuator does not have any next step.");
}
@@ -139,20 +128,13 @@ public class ComplexActuator implements Actor {
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#hasNext()
*/
@Override
public boolean hasNext() {
return next;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#init()
*/
@Override
public void init() {
// Initialize all actors this actor consist of
for(Actor a: actors){
a.init();
@@ -191,9 +173,6 @@ public class ComplexActuator implements Actor {
this.firstrun = true;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#reverse()
*/
@Override
public void reverse() {
// Reverse all actors this actor consist of
@@ -202,9 +181,6 @@ public class ComplexActuator implements Actor {
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#reset()
*/
@Override
public void reset() {
// Reset all actors this actor consist of
@@ -213,49 +189,13 @@ public class ComplexActuator implements Actor {
}
}
/**
* Get the list of actors of this ComplexActor
* @return the actors
*/
public List<Actor> getActors() {
return actors;
}
/**
* @return the preActions
*/
public List<Action> getPreActions() {
return preActions;
}
/**
* @return the postActions
*/
public List<Actor> getActors() {
return actors;
}
public List<Action> getPostActions() {
return postActions;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#destroy()
*/
@Override
public void destroy() {
// Destroy preActions
for(Action a: preActions){
a.destroy();
}
// Destroy actors
for(Actor a: actors){
a.destroy();
}
// Destroy postActions
for(Action a: postActions){
a.destroy();
}
}
}

View File

@@ -19,10 +19,6 @@
package ch.psi.fda.core.actors;
/**
* @author ebner
*
*/
public interface Function {
public double calculate(double parameter);
}

View File

@@ -30,28 +30,23 @@ import javax.script.ScriptException;
import ch.psi.fda.core.scripting.JythonGlobalVariable;
/**
* @author ebner
*
*/
public class JythonFunction implements Function {
// Get Logger
private static final Logger logger = Logger.getLogger(JythonFunction.class.getName());
public static final String ENTRY_FUNCTION_NAME = "calculate";
private static final String ENTRY_FUNCTION_PATTERN = "def "+ENTRY_FUNCTION_NAME+"\\((.*)\\):";
/**
* Script engine of the manipulator
*/
private ScriptEngine engine;
private String additionalParameter = "";
public JythonFunction(String script, Map<String, JythonGlobalVariable> map){
// Create new script engine
// Workaround for Jython memory leak
// http://blog.hillbrecht.de/2009/07/11/jython-memory-leakout-of-memory-problem/
System.setProperty("python.options.internalTablesImpl","weak");
this.engine = new ScriptEngineManager().getEngineByName("python");
// Determine script entry function and the function parameters
@@ -95,9 +90,6 @@ public class JythonFunction implements Function {
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.actors.Function#calculate(double)
*/
@Override
public double calculate(double parameter) {
logger.fine("Function called");

View File

@@ -1,188 +0,0 @@
/**
*
* Copyright 2010 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 <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.actors;
import ch.psi.fda.core.Actor;
/**
* Special actuator for the OTFLoop. This type of actor must not be used in any other
* type of loop than OTFLoop. If it is used it will, depending on the loop, immediately stop the loop
* as it no single step.
* @author ebner
*
*/
public class OTFActuator implements Actor {
/**
* Name of the motor channel
*/
private final String name;
/**
* Channel name of the encoder;
*/
private final String readback;
private double start;
private double end;
private final double stepSize;
private final double integrationTime;
private final String id;
/**
* Additional backlash for the motor
*/
private final double additionalBacklash;
public OTFActuator(String id, String name, String readback, double start, double end, double stepSize, double integrationTime, double additionalBacklash){
this.id = id;
this.name = name;
this.readback = readback;
this.start = start;
this.end = end;
this.stepSize = stepSize;
this.integrationTime = integrationTime;
this.additionalBacklash = additionalBacklash;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#set()
*/
@Override
public void set() {
// Do nothing
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#hasNext()
*/
@Override
public boolean hasNext() {
return false;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @return the readback
*/
public String getReadback() {
return readback;
}
/**
* @return the start
*/
public double getStart() {
return start;
}
/**
* @return the end
*/
public double getEnd() {
return end;
}
/**
* @return the stepSize
*/
public double getStepSize() {
return stepSize;
}
/**
* @return the integrationTime
*/
public double getIntegrationTime() {
return integrationTime;
}
/**
* @return the additionalBacklash
*/
public double getAdditionalBacklash() {
return additionalBacklash;
}
/**
* @return the id
*/
public String getId() {
return id;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#init()
*/
@Override
public void init() {
// Not implemented
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#reverse()
*/
@Override
public void reverse() {
// Not implemented
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#reset()
*/
@Override
public void reset() {
// Not implemented
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#destroy()
*/
@Override
public void destroy() {
// Nothing to be done
}
/**
* @param start the start to set
*/
public void setStart(double start) {
this.start = start;
}
/**
* @param end the end to set
*/
public void setEnd(double end) {
this.end = end;
}
}

View File

@@ -24,8 +24,6 @@ import ch.psi.fda.core.Sensor;
/**
* Pseudo actor that is literally doing nothing for n times
* @author ebner
*
*/
public class PseudoActuatorSensor implements Actor, Sensor {
@@ -42,7 +40,6 @@ public class PseudoActuatorSensor implements Actor, Sensor {
private final String id;
/**
* Constructor
* @param counts
* @param id Id of the Actor/Sensor
*/
@@ -57,13 +54,8 @@ public class PseudoActuatorSensor implements Actor, Sensor {
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#set()
*/
@Override
public void set() {
// Throw an IllegalStateException in the case that set is called although there is no next step.
if(!hasNext()){
throw new IllegalStateException("The actuator does not have any next step.");
}
@@ -71,65 +63,31 @@ public class PseudoActuatorSensor implements Actor, Sensor {
count++;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#hasNext()
*/
@Override
public boolean hasNext() {
return (count<counts);
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#init()
*/
@Override
public void init() {
count=0; // Set count back to 0
count=0;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#reverse()
*/
@Override
public void reverse() {
// Not implemented
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#reset()
*/
@Override
public void reset() {
// NOt implemented
}
// Sensor implementation
/* (non-Javadoc)
* @see ch.psi.fda.core.Sensor#read()
*/
@Override
public Object read() {
return new Double(count); // Return actual count
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Sensor#getId()
*/
@Override
public String getId() {
return this.id;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#destroy()
*/
@Override
public void destroy() {
// Nothing to be done
}
}

View File

@@ -1,165 +0,0 @@
/**
*
* Copyright 2010 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 <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.collector;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.logging.Logger;
import ch.psi.fda.core.messages.ComponentMetadata;
import ch.psi.fda.core.messages.DataMessage;
import ch.psi.fda.core.messages.DataMessageMetadata;
import ch.psi.fda.core.messages.DataQueue;
import ch.psi.fda.core.messages.StreamDelimiterMessage;
import ch.psi.fda.core.messages.EndOfStreamMessage;
import ch.psi.fda.core.messages.Message;
/**
* Collector class that is collecting and merging data from different Queues.
* @author ebner
*
*/
public class Collector implements Runnable{
// Get Logger
private static Logger logger = Logger.getLogger(Collector.class.getName());
/**
* List of queues and their metadata this collector is responsible to readout.
* The logic is as follows:
* Read out the last queue until the first queue in the list has the EndOfLoopMessage.
*/
private List<DataQueue> queues;
/**
* Outgoing queue of this collector
*/
private BlockingQueue<Message> outQueue;
/**
* Constructor
*/
public Collector(){
queues = new ArrayList<DataQueue>();
outQueue = new LinkedBlockingQueue<Message>(1000); // Create bounded queue to prevent running out of memory ...
}
/* (non-Javadoc)
* @see java.lang.Runnable#run()
*/
@Override
public void run() {
if(queues.size()>0){
try{
readQueue(0, null);
}
catch(InterruptedException e){
// Readout aborted through interrupt
}
}
else{
// No queue registered for reading
}
try {
outQueue.put(new EndOfStreamMessage());
} catch (InterruptedException e) {
// TODO Stop loop and exit logic instead of throwing an Exception
throw new RuntimeException("Unable to terminate stream with and End of Stream Message",e);
}
logger.info("END");
}
private void readQueue(int index, DataMessage m) throws InterruptedException{
BlockingQueue<Message> q = queues.get(index).getQueue();
// Read Message
Message message = q.take();
while(message instanceof DataMessage){
// Create new data message
DataMessage dm = new DataMessage();
if(m!=null){
dm.getData().addAll(m.getData());
}
dm.getData().addAll(((DataMessage)message).getData());
if(index<(queues.size()-1)){
readQueue(index+1, dm);
}
else{
// Write message to outgoing queue
outQueue.put(dm);
}
// Read next message
message = q.take();
}
if(message instanceof EndOfStreamMessage){
// Translate EndOfStream to StreamDelimiter message
StreamDelimiterMessage ddm = new StreamDelimiterMessage(queues.size()-1-index, ((EndOfStreamMessage)message).isIflag());
// Write message to outgoing queue
outQueue.put(ddm);
}
}
/**
* @return the queues
*/
public List<DataQueue> getQueues() {
return queues;
}
/**
* Get the outgoing data queue.
* Attention, only call this method after all ingoing queues were registered! Otherwise the data returned
* by this method is not accurate.
* @return output queue of collector
*/
public DataQueue getOutQueue(){
DataMessageMetadata dataMessageMetadata = new DataMessageMetadata();
dataMessageMetadata.getComponents();
// Generate new combined metadata and add dimension information to the components
int nq = queues.size();
for(int i=0;i<nq;i++){
DataQueue q = queues.get(i);
for(ComponentMetadata cm: q.getDataMessageMetadata().getComponents()){
// The dimension number is the number of queues minus the index of the current queue minus 1 (because dimension index starts at 0)
dataMessageMetadata.getComponents().add(new ComponentMetadata(cm.getId(), nq-i-1));
}
}
return(new DataQueue(outQueue, dataMessageMetadata));
}
}

View File

@@ -1,88 +0,0 @@
/**
*
* Copyright 2010 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 <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.collector;
import java.util.ArrayList;
import java.util.List;
import ch.psi.fda.core.messages.DataQueue;
import ch.psi.fda.core.messages.EndOfStreamMessage;
import ch.psi.fda.core.messages.Message;
/**
* Serialize data received by a DataQueue
* @author ebner
*
*/
public class DataDispatcher implements Runnable{
private DataQueue queue;
private List<DataQueue> outQueues;
public DataDispatcher(DataQueue queue){
this.queue = queue;
this.outQueues = new ArrayList<DataQueue>();
}
/* (non-Javadoc)
* @see java.lang.Runnable#run()
*/
@Override
public void run() {
try{
// TODO Need to synchronize message metadata
// for(DataQueue q: outQueues){
// }
// Dispatch Messages
Message message = queue.getQueue().take();
while(!(message instanceof EndOfStreamMessage)){
// Clone message ...
for(DataQueue q: outQueues){
q.getQueue().put(message);
}
// Read next message
message = queue.getQueue().take();
}
// Write end of stream message
for(DataQueue q: outQueues){
q.getQueue().put(message);
}
} catch (InterruptedException e) {
// TODO Stop loop and exit logic instead of throwing an Exception
throw new RuntimeException("Data serializer was interrupted while writing data to file",e);
}
}
/**
* @return the outQueues
*/
public List<DataQueue> getOutQueues() {
return outQueues;
}
}

View File

@@ -32,33 +32,24 @@ import ch.psi.jcae.ChannelException;
/**
* Guard checking channels to meet a certain condition
* @author ebner
*
*/
public class ChannelAccessGuard implements Guard {
// Get Logger
private static Logger logger = Logger.getLogger(ChannelAccessGuard.class.getName());
/**
* Flag to indicate whether a guard condition failed since the last init call
* true: all conditions met, false: at least one condition failed
*/
private boolean check = true;
private volatile boolean check = true;
private final List<ChannelAccessGuardCondition> conditions;
private final List<ChannelAccessGuardCondition<?>> conditions;
/**
* Constructor
* @param conditions
*/
public ChannelAccessGuard(List<ChannelAccessGuardCondition> conditions){
public ChannelAccessGuard(List<ChannelAccessGuardCondition<?>> conditions){
this.conditions = conditions;
// Create channel that contribute to the status of the guard
for(final ChannelAccessGuardCondition condition: conditions){
for(final ChannelAccessGuardCondition<?> condition: conditions){
condition.getChannel().addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
@@ -70,49 +61,29 @@ public class ChannelAccessGuard implements Guard {
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Guard#init()
*/
@Override
public void init() {
check = true;
// Check one time if all conditions are met
for(ChannelAccessGuardCondition condition: conditions){
for(ChannelAccessGuardCondition<?> condition: conditions){
try{
if(! (condition.getChannel().getValue(true)).equals(condition.getValue()) ){
check=false;
// Early exit
break;
}
}
catch(ChannelException | TimeoutException | ExecutionException e){
catch (InterruptedException e) {
throw new RuntimeException("Guard interrupted ",e);
} catch (TimeoutException | ChannelException | ExecutionException e) {
logger.log(Level.WARNING, "Unable ", e);
check=false;
} catch (InterruptedException e) {
throw new RuntimeException("Guard interrupted ",e);
}
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Guard#check()
*/
@Override
public boolean check() {
return check;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Guard#destroy()
*/
@Override
public void destroy() {
// Destroy Guard Conditions
for(ChannelAccessGuardCondition condition: conditions){
condition.destroy();
}
}
}

View File

@@ -19,80 +19,23 @@
package ch.psi.fda.core.guard;
import java.util.concurrent.TimeoutException;
import java.util.logging.Logger;
import ch.psi.jcae.Channel;
import ch.psi.jcae.ChannelDescriptor;
import ch.psi.jcae.ChannelException;
import ch.psi.jcae.ChannelService;
/**
* Channel and condition that need to be met.
* @author ebner
*
*/
public class ChannelAccessGuardCondition {
public class ChannelAccessGuardCondition<T> {
// Get Logger
private static Logger logger = Logger.getLogger(ChannelAccessGuardCondition.class.getName());
/**
* Channel name
*/
private final Channel<?> channel;
/**
* Value of the channel to meet condition
*/
private final Object value;
private final Channel<T> channel;
private final T value; // Value of the channel to meet condition
/**
* Constructor
* @param channel Name of the channel that contributes to a guard
* @param value
*/
public ChannelAccessGuardCondition(ChannelService s, String channel, Object value){
try {
this.channel = s.createChannel(new ChannelDescriptor<>(value.getClass(), channel, true));
} catch (ChannelException | TimeoutException e) {
// Convert Exception into unchecked RuntimeException
throw new IllegalArgumentException("Unable to initialize actuator channel [name:"+channel+"]",e);
} catch (InterruptedException e) {
throw new RuntimeException("Unable to initialize actuator channel [name:"+channel+"]",e);
}
public ChannelAccessGuardCondition(Channel<T> channel, T value){
this.channel = channel;
this.value = value;
}
/**
* @return the channel
*/
public Channel<?> getChannel() {
public Channel<T> getChannel() {
return channel;
}
/**
* @return the value
*/
public Object getValue() {
public T getValue() {
return value;
}
/**
* Destroy guard condition.
* Can be used for the cleanup of used resources of the guard condition (e.g. to close connections, ...) if
* this cannot be done automatically by the GarbageCollector.
*
* After calling this method the guard condition must not be used any more!
*/
public void destroy(){
// Destroy channel
try {
logger.finest("Destroy guard condition channel: "+channel.getName());
channel.destroy();
} catch (ChannelException e) {
throw new RuntimeException("Unable to destroy channel ["+channel.getName()+"]",e);
}
}
}

View File

@@ -21,35 +21,29 @@ package ch.psi.fda.core.loops;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.logging.Logger;
import com.google.common.eventbus.EventBus;
import ch.psi.fda.core.Action;
import ch.psi.fda.core.ActionLoop;
import ch.psi.fda.core.Actor;
import ch.psi.fda.core.ActorSetCallable;
import ch.psi.fda.core.Guard;
import ch.psi.fda.core.Sensor;
import ch.psi.fda.core.messages.ComponentMetadata;
import ch.psi.fda.core.messages.DataMessage;
import ch.psi.fda.core.messages.DataMessageMetadata;
import ch.psi.fda.core.messages.DataQueue;
import ch.psi.fda.core.messages.EndOfStreamMessage;
import ch.psi.fda.core.messages.Message;
import ch.psi.fda.core.messages.Metadata;
/**
* Loop of actions to accomplish a task or test.
* @author ebner
*
*/
public class ActorSensorLoop implements ActionLoop {
// Get Logger
private static Logger logger = Logger.getLogger(ActorSensorLoop.class.getName());
/**
@@ -101,12 +95,6 @@ public class ActorSensorLoop implements ActionLoop {
*/
private List<Sensor> sensors;
/**
* Data queue sensor data is posted to. A message consists of a list of data objects
* that are read out of the sensors of this loop.
*/
private BlockingQueue<Message> dataQueue;
/**
* Guard used to check whether the environment was ok while reading out the sensors
*/
@@ -119,17 +107,13 @@ public class ActorSensorLoop implements ActionLoop {
private List<ActorSetCallable> pactors;
private EventBus eventBus = new EventBus();
/**
* Default constructor
*/
public ActorSensorLoop(){
this(false);
}
/**
* Create instance of the
*/
public ActorSensorLoop(boolean zigZag){
this.zigZag = zigZag;
this.actionLoops = new ArrayList<ActionLoop>();
@@ -143,14 +127,9 @@ public class ActorSensorLoop implements ActionLoop {
this.actors = new ArrayList<Actor>();
this.pactors = new ArrayList<ActorSetCallable>();
this.sensors = new ArrayList<Sensor>();
this.dataQueue = new LinkedBlockingQueue<Message>(1000);
}
/* (non-Javadoc)
* @see ch.psi.fda.engine.ActionLoop#execute()
*/
/**
* Executes the actor sensor loop. The actor sensor loop is build up as follows:
* preActions
@@ -171,6 +150,14 @@ public class ActorSensorLoop implements ActionLoop {
public void execute() throws InterruptedException {
abort = false;
List<Metadata> metadata = new ArrayList<>();
// Build up data message metadata based on the sensors currently registered.
for(Sensor s: sensors){
metadata.add(new Metadata(s.getId()));
}
/**
* Thread pool for parallel execution of tasks
*/
@@ -294,7 +281,7 @@ public class ActorSensorLoop implements ActionLoop {
}
// Read sensors
DataMessage message = new DataMessage();
DataMessage message = new DataMessage(metadata);
for(Sensor sensor: sensors){
// Readout sensor
Object o = sensor.read();
@@ -319,7 +306,7 @@ public class ActorSensorLoop implements ActionLoop {
if(guardOK){
// Post a message with the sensor data
dataQueue.put(message);
eventBus.post(message);
// Loop all configured ActionLoop objects
for(ActionLoop actionLoop: actionLoops){
@@ -339,7 +326,7 @@ public class ActorSensorLoop implements ActionLoop {
// Issue end of loop control message
// Set iflag of the EndOfStreamMessage according to dataGroup flag of this loop
dataQueue.put(new EndOfStreamMessage(dataGroup));
eventBus.post(new EndOfStreamMessage(dataGroup));
}
if(zigZag){
@@ -353,9 +340,6 @@ public class ActorSensorLoop implements ActionLoop {
}
/* (non-Javadoc)
* @see ch.psi.fda.engine.ActionLoop#abort()
*/
@Override
public void abort(){
abort = true;
@@ -372,13 +356,8 @@ public class ActorSensorLoop implements ActionLoop {
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.ActionLoop#prepare()
*/
@Override
public void prepare() {
// Put in prepare code here
// Create callable for all actors
pactors.clear();
for(final Actor a: actors){
@@ -396,195 +375,62 @@ public class ActorSensorLoop implements ActionLoop {
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.ActionLoop#cleanup()
*/
@Override
public void cleanup() {
// Put in cleanup code here
// Recursively call cleanup() method of all registered action loops
for(ActionLoop actionLoop: actionLoops){
actionLoop.cleanup();
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Action#destroy()
*/
@Override
public void destroy() {
// Call destroy method of sub components
for(Action a: preActions){
logger.finest("Destroy pre-action");
a.destroy();
}
for(Action a: postActions){
logger.finest("Destroy post-action");
a.destroy();
}
for(Action a: preActorActions){
logger.finest("Destroy pre-actor action");
a.destroy();
}
for(Action a: postActorActions){
logger.finest("Destroy post-actor action");
a.destroy();
}
for(Action a: preSensorActions){
logger.finest("Destroy pre-sensor action");
a.destroy();
}
for(Action a: postSensorActions){
logger.finest("Destroy post-sensor action");
a.destroy();
}
for(Actor a: actors){
logger.finest("Destroy actor");
a.destroy();
}
for(Sensor s: sensors){
logger.finest("Destroy sensor");
s.destroy();
}
if(guard != null){
logger.finest("Destroy guard");
guard.destroy();
}
// Recursively call cleanup() method of all registered action loops
for(ActionLoop actionLoop: actionLoops){
logger.finest("Destroy action loop");
actionLoop.destroy();
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.ActionLoop#getPreActions()
*/
@Override
public List<Action> getPreActions() {
return preActions;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.ActionLoop#getPostActions()
*/
@Override
public List<Action> getPostActions() {
return postActions;
}
/**
* The structure of the data message depends on the sensors registered at this loop
* at the time this method is called.
* @return the data queue and the metadata of the data messages
*/
public DataQueue getDataQueue() {
DataMessageMetadata m = new DataMessageMetadata();
// Build up data message metadata based on the sensors currently registered.
for(Sensor s: sensors){
m.getComponents().add(new ComponentMetadata(s.getId()));
}
return new DataQueue(dataQueue, m);
@Override
public EventBus getEventBus(){
return eventBus;
}
// Getter functions for variable parts
/**
* @return the actionLoops
*/
public List<ActionLoop> getActionLoops() {
return actionLoops;
}
/**
* @return the preActorActions
*/
public List<Action> getPreActorActions() {
return preActorActions;
}
/**
* @return the postActorActions
*/
public List<Action> getPostActorActions() {
return postActorActions;
}
/**
* @return the preSensorActions
*/
public List<Action> getPreSensorActions() {
return preSensorActions;
}
/**
* @return the postSensorActions
*/
public List<Action> getPostSensorActions() {
return postSensorActions;
}
/**
* @return the actors
*/
public List<Actor> getActors() {
return actors;
}
/**
* @return the sensors
*/
public List<Sensor> getSensors() {
return sensors;
}
/**
* @return the guard
*/
public Guard getGuard() {
return guard;
}
/**
* @param guard the guard to set
*/
public void setGuard(Guard guard) {
this.guard = guard;
}
/**
* @return the dataGroup
*/
public boolean isDataGroup() {
return dataGroup;
}
/**
* @param dataGroup the dataGroup to set
*/
public void setDataGroup(boolean dataGroup) {
this.dataGroup = dataGroup;
}
}

View File

@@ -20,8 +20,7 @@
package ch.psi.fda.core.loops.cr;
/**
* @author ebner
*
* Filter calculating the delta of two subsequent values
*/
public class CrlogicDeltaDataFilter {

View File

@@ -34,26 +34,18 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.logging.Logger;
import com.google.common.eventbus.EventBus;
import jcifs.smb.SmbFile;
import ch.psi.fda.core.Action;
import ch.psi.fda.core.ActionLoop;
import ch.psi.fda.core.Sensor;
import ch.psi.fda.core.actors.OTFActuator;
import ch.psi.fda.core.messages.ComponentMetadata;
import ch.psi.fda.core.messages.DataMessage;
import ch.psi.fda.core.messages.DataMessageMetadata;
import ch.psi.fda.core.messages.DataQueue;
import ch.psi.fda.core.messages.EndOfStreamMessage;
import ch.psi.fda.core.messages.Message;
import ch.psi.fda.core.sensors.MillisecondTimestampSensor;
import ch.psi.fda.core.sensors.OTFNamedChannelSensor;
import ch.psi.fda.core.sensors.OTFScalerChannelSensor;
import ch.psi.fda.core.messages.Metadata;
import ch.psi.jcae.ChannelException;
import ch.psi.jcae.ChannelService;
/**
* @author ebner
*
* While using Crlogic the IOC system clock rate should/must be set to 1000 (default 60)
*
* sysClkRateSet 1000
@@ -61,7 +53,6 @@ import ch.psi.jcae.ChannelService;
*/
public class CrlogicLoop implements ActionLoop {
// Get Logger
private static final Logger logger = Logger.getLogger(CrlogicLoop.class.getName());
/**
@@ -76,8 +67,6 @@ public class CrlogicLoop implements ActionLoop {
private volatile boolean stopReadoutThread = false;
private Thread readoutThread;
// Constants
/**
* Default timeout (in milliseconds) for wait operations
*/
@@ -118,33 +107,23 @@ public class CrlogicLoop implements ActionLoop {
*/
private String prefix;
private CrlogicChannelsTemplate template;
private MotorChannelsTemplate motortemplate;
private TemplateCrlogic template;
private TemplateMotor motortemplate;
/**
* Semaphore to ensure that data is read in correct sequence
*/
private Semaphore semaphore = new Semaphore(1);
/**
* Special OTF Actuator
*/
private OTFActuator actuator = null;
/**
* List of sensors of this loop
*/
private List<Sensor> sensors;
private List<CrlogicResource> sensors;
private List<String> readoutResources;
private Map<Integer, CrlogicDeltaDataFilter> scalerIndices;
private CrlogicRangeDataFilter crlogicDataFilter;
/**
* Data queue sensor data is posted to. A message consists of a list of data objects
* that are read out of the sensors of this loop.
*/
private BlockingQueue<Message> dataQueue;
/**
* Abort status
@@ -153,9 +132,25 @@ public class CrlogicLoop implements ActionLoop {
private boolean abortForce = false;
private Thread executionThread = null;
private ChannelService cservice;
public CrlogicLoop(ChannelService s, String prefix, String server, String share, String smbShare, boolean zigZag){
cservice = s;
private final ChannelService cservice;
private String id;
private String name; // name of the motor channel
private String readback; // name of the encoder channel
private double start;
private double end;
private double stepSize;
private double integrationTime;
private double additionalBacklash;
private final EventBus eventbus;
private List<Metadata> metadata;
public CrlogicLoop(ChannelService cservice, String prefix, String server, String share, String smbShare, boolean zigZag){
eventbus = new EventBus();
this.cservice = cservice;
this.prefix = prefix;
this.server = server;
this.share = share;
@@ -165,15 +160,25 @@ public class CrlogicLoop implements ActionLoop {
// Initialize lists used by the loop
this.preActions = new ArrayList<Action>();
this.postActions = new ArrayList<Action>();
this.sensors = new ArrayList<Sensor>();
this.sensors = new ArrayList<>();
this.readoutResources = new ArrayList<String>();
this.scalerIndices = new HashMap<Integer, CrlogicDeltaDataFilter>();
this.crlogicDataFilter = new CrlogicRangeDataFilter();
this.dataQueue = new LinkedBlockingQueue<Message>(2000);
}
public void setActuator(String id, String name, String readback, double start, double end, double stepSize, double integrationTime, double additionalBacklash){
this.id = id;
this.name = name;
this.readback = readback;
this.start = start;
this.end = end;
this.stepSize = stepSize;
this.integrationTime = integrationTime;
this.additionalBacklash = additionalBacklash;
}
/**
* Collect data from share
* @param tmpFileName Name of the temporary file
@@ -234,7 +239,7 @@ public class CrlogicLoop implements ActionLoop {
// logger.info(line);
// Write into queue
DataMessage message = new DataMessage();
DataMessage message = new DataMessage(metadata);
String[] tokens = line.split("\t");
boolean use = true;
@@ -285,7 +290,7 @@ public class CrlogicLoop implements ActionLoop {
// Filter data
if(use && !discardAnyway){
dataQueue.put(message);
eventbus.post(message);
mcounter++;
}
@@ -308,7 +313,7 @@ public class CrlogicLoop implements ActionLoop {
}
// Issue end of loop control message
dataQueue.put(new EndOfStreamMessage(dataGroup));
eventbus.post(new EndOfStreamMessage(dataGroup));
semaphore.release();
}
@@ -321,15 +326,9 @@ public class CrlogicLoop implements ActionLoop {
public void execute() throws InterruptedException {
try{
double stepSize = actuator.getStepSize();
double start = actuator.getStart();
double end = actuator.getEnd();
double integrationTime = actuator.getIntegrationTime();
double ubacklash = actuator.getAdditionalBacklash();
// Set values for the datafilter
crlogicDataFilter.setStart(actuator.getStart());
crlogicDataFilter.setEnd(actuator.getEnd());
crlogicDataFilter.setStart(start);
crlogicDataFilter.setEnd(end);
// Reset data filter
for(Integer k: scalerIndices.keySet()){
@@ -356,20 +355,20 @@ public class CrlogicLoop implements ActionLoop {
Long timeout = 600000l; // 10 minutes move timeout
// Check if logic is inactive, otherwise return early
if(!template.getStatus().getValue().equals(CrlogicChannelsTemplate.Status.INACTIVE.toString())){
if(!template.getStatus().getValue().equals(TemplateCrlogic.Status.INACTIVE.toString())){
logger.info("CRLOGIC is not inactive!");
// TODO Decide what to do in this situation
if(template.getStatus().getValue().equals(CrlogicChannelsTemplate.Status.FAULT.toString())){
if(template.getStatus().getValue().equals(TemplateCrlogic.Status.FAULT.toString())){
// If in fault show message and recover
logger.info("CRLOGIC in FAULT state");
logger.info("Error message: "+template.getMessage().getValue());
logger.info("Recover logic and set it to INACTIVE");
template.getStatus().setValue(CrlogicChannelsTemplate.Status.INACTIVE.toString());
template.getStatus().setValue(TemplateCrlogic.Status.INACTIVE.toString());
}
else if(template.getStatus().getValue().equals(CrlogicChannelsTemplate.Status.ACTIVE.toString())){
template.getStatus().setValue(CrlogicChannelsTemplate.Status.STOP.toString());
template.getStatus().waitForValue(CrlogicChannelsTemplate.Status.INACTIVE.toString(), startStopTimeout);
else if(template.getStatus().getValue().equals(TemplateCrlogic.Status.ACTIVE.toString())){
template.getStatus().setValue(TemplateCrlogic.Status.STOP.toString());
template.getStatus().waitForValue(TemplateCrlogic.Status.INACTIVE.toString(), startStopTimeout);
}
else{
throw new RuntimeException("CRLOGIC is not inactive");
@@ -459,7 +458,7 @@ public class CrlogicLoop implements ActionLoop {
// TODO Calculate and set motor speed, backlash, etc.
double motorSpeed = stepSize/integrationTime;
double backlash = (0.5*motorSpeed*motortemplate.getAccelerationTime().getValue())+motorBacklash+ubacklash;
double backlash = (0.5*motorSpeed*motortemplate.getAccelerationTime().getValue())+motorBacklash+additionalBacklash;
double realEnd = end+(backlash*direction);
double realStart = start-(backlash*direction);
@@ -500,17 +499,17 @@ public class CrlogicLoop implements ActionLoop {
// Start crlogic logic
logger.info("Start CRLOGIC");
template.getStatus().setValue(CrlogicChannelsTemplate.Status.INITIALIZE.toString());
template.getStatus().setValue(TemplateCrlogic.Status.INITIALIZE.toString());
try{
template.getStatus().waitForValue(CrlogicChannelsTemplate.Status.ACTIVE.toString(), startStopTimeout);
template.getStatus().waitForValue(TemplateCrlogic.Status.ACTIVE.toString(), startStopTimeout);
}
catch(ChannelException e){
catch(ChannelException | ExecutionException | TimeoutException e){
logger.info( "Failed to start CRLOGIC. Logic in status: "+template.getStatus().getValue() );
if(template.getStatus().getValue().equals(CrlogicChannelsTemplate.Status.FAULT.toString())){
if(template.getStatus().getValue().equals(TemplateCrlogic.Status.FAULT.toString())){
logger.info("Error message: "+template.getMessage().getValue());
}
// Recover to inactive
template.getStatus().setValue(CrlogicChannelsTemplate.Status.INACTIVE.toString());
template.getStatus().setValue(TemplateCrlogic.Status.INACTIVE.toString());
// TODO Improve error handling
throw new RuntimeException("Failed to start CRLOGIC. Logic in status: "+template.getStatus().getValue()+ " Error message: "+template.getMessage().getValue(), e);
@@ -524,8 +523,8 @@ public class CrlogicLoop implements ActionLoop {
catch (InterruptedException e) {
if(abort & (!abortForce)){
// Abort motor move
motortemplate.getCommand().setValue(MotorChannelsTemplate.Commands.Stop.ordinal());
motortemplate.getCommand().setValue(MotorChannelsTemplate.Commands.Go.ordinal());
motortemplate.getCommand().setValue(TemplateMotor.Commands.Stop.ordinal());
motortemplate.getCommand().setValue(TemplateMotor.Commands.Go.ordinal());
}
else{
throw e;
@@ -535,13 +534,13 @@ public class CrlogicLoop implements ActionLoop {
// Stop crlogic logic
logger.info("Stop CRLOGIC");
template.getStatus().setValue(CrlogicChannelsTemplate.Status.STOP.toString());
template.getStatus().setValue(TemplateCrlogic.Status.STOP.toString());
// Wait until stopped
logger.info("Wait until stopped");
try{
template.getStatus().waitForValue(CrlogicChannelsTemplate.Status.INACTIVE.toString(), startStopTimeout);
template.getStatus().waitForValue(TemplateCrlogic.Status.INACTIVE.toString(), startStopTimeout);
}
catch(ChannelException | ExecutionException e){
catch(ChannelException | ExecutionException | TimeoutException e){
logger.info( "Failed to stop CRLOGIC. Logic in status: "+template.getStatus().getValue() );
// TODO Improve error handling
throw new RuntimeException("Failed to stop CRLOGIC. Logic in status: "+template.getStatus().getValue(), e);
@@ -566,27 +565,11 @@ public class CrlogicLoop implements ActionLoop {
// Request read of data file
readQueue.put(tmpFileName);
// // Read data
// Thread t = new Thread(new Runnable() {
//
// @Override
// public void run() {
// try {
// collectData(smbShare, tmpFileName);
// } catch (InterruptedException e) {
// throw new RuntimeException("Unable to read CRLOGIC raw data file",e);
// } catch (IOException e) {
// throw new RuntimeException("Unable to read CRLOGIC raw data file",e);
// }
// }
// });
// t.start();
if(zigZag){
// Swap start and end
double aend = actuator.getEnd();
actuator.setEnd(actuator.getStart());
actuator.setStart(aend);
// reverse start/end
double aend = end;
end=start;
start=aend;
}
synchronized(this){
@@ -598,18 +581,11 @@ public class CrlogicLoop implements ActionLoop {
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Action#abort()
*/
@Override
public void abort() {
abort(false);
}
/**
* Abort logic
* @param force
*/
public synchronized void abort(boolean force){
abort = true;
abortForce = force;
@@ -620,35 +596,18 @@ public class CrlogicLoop implements ActionLoop {
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Action#destroy()
*/
@Override
public void destroy() {
stopReadoutThread = true;
readoutThread.interrupt();
// TODO eventually interrupt readout thread
try {
cservice.destroyAnnotatedChannels(template);
cservice.destroyAnnotatedChannels(motortemplate);
template = null;
motortemplate = null;
} catch (Exception e) {
throw new RuntimeException("Unable to destroy CrlogicLoop", e);
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.ActionLoop#prepare()
*/
@Override
public void prepare() {
metadata = new ArrayList<>();
// Build up metadata
metadata.add(new Metadata(this.id));
for(CrlogicResource s: sensors){
metadata.add(new Metadata(s.getId()));
}
stopReadoutThread = false;
// Start readout Thread
readoutThread = new Thread(new Runnable() {
@@ -679,22 +638,22 @@ public class CrlogicLoop implements ActionLoop {
try{
// Connect crlogic channels
template = new CrlogicChannelsTemplate();
template = new TemplateCrlogic();
logger.info("Connect channels");
Map<String, String> m = new HashMap<>();
m.put("PREFIX", prefix);
cservice.createAnnotatedChannels(template, m);
Map<String,String> map = new HashMap<>();
map.put("PREFIX", prefix);
cservice.createAnnotatedChannels(template, map);
// Connect motor channels
motortemplate = new MotorChannelsTemplate();
m = new HashMap<>();
m.put("PREFIX", actuator.getName());
cservice.createAnnotatedChannels(motortemplate, m);
motortemplate = new TemplateMotor();
map = new HashMap<>();
map.put("PREFIX", this.name);
cservice.createAnnotatedChannels(motortemplate, map);
useReadback = motortemplate.getUseReadback().getValue();
useEncoder = motortemplate.getUseEncoder().getValue();
logger.info("Motor type: "+ MotorChannelsTemplate.Type.values()[motortemplate.getType().getValue()]);
logger.info("Motor type: "+ TemplateMotor.Type.values()[motortemplate.getType().getValue()]);
logger.info("Motor use readback: "+useReadback);
logger.info("Motor use encoder: "+useEncoder);
@@ -705,20 +664,20 @@ public class CrlogicLoop implements ActionLoop {
// Determine mode of motor
if((!useReadback) && (!useEncoder)){
// Open loop
if(actuator.getReadback()!=null){
if(this.readback!=null){
throw new IllegalArgumentException("Readback not supported if motor is configured in open loop");
}
else{
readoutResources.add(actuator.getName());
readoutResources.add(this.name);
}
}
else if(useReadback && (!useEncoder)){
String readback;
// use readback link
if(actuator.getReadback()!=null){
if(this.readback!=null){
// Use specified readback
readback = (actuator.getReadback());
readback = this.readback;
}
else{
// Set resouce to readback link
@@ -730,13 +689,13 @@ public class CrlogicLoop implements ActionLoop {
// Fill readback encoder settings
// Connect to encoder
EncoderChannelsTemplate encodertemplate = new EncoderChannelsTemplate();
m = new HashMap<>();
m.put("PREFIX", readback);
cservice.createAnnotatedChannels(encodertemplate, m);
TemplateEncoder encodertemplate = new TemplateEncoder();
map = new HashMap<>();
map.put("PREFIX", readback);
cservice.createAnnotatedChannels(encodertemplate, map);
// Read encoder settings
if(encodertemplate.getDirection().getValue()==EncoderChannelsTemplate.Direction.Positive.ordinal()){
if(encodertemplate.getDirection().getValue()==TemplateEncoder.Direction.Positive.ordinal()){
crlogicDataFilter.setEncoderDirection(1);
}
else{
@@ -751,12 +710,12 @@ public class CrlogicLoop implements ActionLoop {
}
else if (useEncoder && (!useReadback)){
// use readback link
if(actuator.getReadback()!=null){
if(this.readback!=null){
throw new IllegalArgumentException("Readback not supported if motor is configured to use encoder");
}
else{
// Set resouce to readback link
readoutResources.add(actuator.getName()+"_ENC");
readoutResources.add(this.name+"_ENC");
}
}
else{
@@ -764,7 +723,7 @@ public class CrlogicLoop implements ActionLoop {
}
// Fill Motor specific settings
if(motortemplate.getDirection().getValue()==MotorChannelsTemplate.Direction.Positive.ordinal()){
if(motortemplate.getDirection().getValue()==TemplateMotor.Direction.Positive.ordinal()){
crlogicDataFilter.setMotorDirection(1);
}
else{
@@ -779,23 +738,11 @@ public class CrlogicLoop implements ActionLoop {
scalerIndices.clear();
int c = 1; // We start at 1 because the actuator right now is an implicit sensor
for(Sensor s: sensors){
if(s instanceof OTFNamedChannelSensor){
// Monitored channel (MUST be configured MODULE ID'S)
OTFNamedChannelSensor so = (OTFNamedChannelSensor) s;
readoutResources.add(so.getName());
}
else if (s instanceof OTFScalerChannelSensor){
OTFScalerChannelSensor so = (OTFScalerChannelSensor) s;
readoutResources.add("SCALER"+so.getIndex());
for(CrlogicResource s: sensors){
readoutResources.add(s.getKey());
if(s.isDelta()){
scalerIndices.put(c, new CrlogicDeltaDataFilter());
}
else if (s instanceof MillisecondTimestampSensor){
readoutResources.add("TIMESTAMP");
}
else{
throw new IllegalArgumentException("Sensor type "+s.getClass()+" is not supported by this loop");
}
c++;
}
@@ -808,101 +755,55 @@ public class CrlogicLoop implements ActionLoop {
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.ActionLoop#cleanup()
*/
@Override
public void cleanup() {
// TODO Auto-generated method stub
stopReadoutThread = true;
readoutThread.interrupt();
try {
cservice.destroyAnnotatedChannels(template);
cservice.destroyAnnotatedChannels(motortemplate);
template = null;
motortemplate = null;
} catch (Exception e) {
throw new RuntimeException("Unable to destroy CrlogicLoop", e);
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.ActionLoop#getPreActions()
*/
@Override
public List<Action> getPreActions() {
return preActions;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.ActionLoop#getPostActions()
*/
@Override
public List<Action> getPostActions() {
return postActions;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.ActionLoop#isDataGroup()
*/
@Override
public boolean isDataGroup() {
// TODO Auto-generated method stub
return dataGroup;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.ActionLoop#setDataGroup(boolean)
*/
@Override
public void setDataGroup(boolean dataGroup) {
this.dataGroup = dataGroup;
}
/**
* @return the sensors
*/
public List<Sensor> getSensors() {
public List<CrlogicResource> getSensors() {
return sensors;
}
/**
* @return the actor
*/
public OTFActuator getActor() {
return actuator;
}
/**
* @param actor the actor to set
*/
public void setActor(OTFActuator actor) {
this.actuator = actor;
}
/**
* The structure of the data message depends on the sensors registered at this loop
* at the time this method is called.
* @return the data queue and the metadata of the data messages
*/
public DataQueue getDataQueue() {
DataMessageMetadata m = new DataMessageMetadata();
// Build up data message metadata based on the sensors currently registered.
m.getComponents().add(new ComponentMetadata(actuator.getId()));
for(Sensor s: sensors){
m.getComponents().add(new ComponentMetadata(s.getId()));
}
return new DataQueue(dataQueue, m);
}
/**
* @return the keepTmpFiles
*/
public boolean isKeepTmpFiles() {
return keepTmpFiles;
}
/**
* @param keepTmpFiles the keepTmpFiles to set
*/
public void setKeepTmpFiles(boolean keepTmpFiles) {
this.keepTmpFiles = keepTmpFiles;
}
public EventBus getEventBus(){
return eventbus;
}
}

View File

@@ -0,0 +1,71 @@
/**
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.loops.cr;
/**
* Readout resource of crlogic
*/
public class CrlogicResource {
/**
* Id of the data
*/
private String id;
/**
* Id of the crlogic resource to be read out. As configured in the CRLOGIC part of the IOC startup script
*/
private String key;
/**
* Flag whether to read back the delta of the values of this resource. (delta is done in software)
*/
private boolean delta = false;
public CrlogicResource(){
}
public CrlogicResource(String id, String key){
this.id = id;
this.key = key;
}
public CrlogicResource(String id, String key, boolean delta){
this.id = id;
this.key = key;
this.delta = delta;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public boolean isDelta() {
return delta;
}
public void setDelta(boolean delta) {
this.delta = delta;
}
}

View File

@@ -21,28 +21,27 @@ package ch.psi.fda.core.loops.cr;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import ch.psi.fda.core.Action;
import ch.psi.fda.core.ActionLoop;
import ch.psi.fda.core.messages.DataQueue;
import ch.psi.fda.core.sensors.MillisecondTimestampSensor;
import ch.psi.fda.core.messages.Message;
/**
* @author ebner
*
*/
public class ParallelCrlogic implements ActionLoop {
// Get Logger
private static final Logger logger = Logger.getLogger(ParallelCrlogic.class.getName());
/**
@@ -66,6 +65,8 @@ public class ParallelCrlogic implements ActionLoop {
private ParallelCrlogicStreamMerge merger;
private final EventBus eventbus;
public ParallelCrlogic(CrlogicLoop crlogic, ScrlogicLoop scrlogic){
if(crlogic==null){
@@ -75,32 +76,42 @@ public class ParallelCrlogic implements ActionLoop {
throw new IllegalArgumentException("No Scrloop specified");
}
this.eventbus = new EventBus();
this.crlogic = crlogic;
// Add timestamp to sensor at the beginning of the sensor list as this is required for merging the data
// Timestamp will be at the second position of a message in the queue!
this.crlogic.getSensors().add(0, new MillisecondTimestampSensor("tmp_timestamp"));
this.crlogic.getSensors().add(0, new CrlogicResource("tmp_timestamp","TIMESTAMP"));
this.scrlogic = scrlogic;
// Initialize lists used by the loop
this.preActions = new ArrayList<Action>();
this.postActions = new ArrayList<Action>();
this.merger = new ParallelCrlogicStreamMerge(crlogic.getDataQueue(), scrlogic.getDataQueue());
final BlockingQueue<Message> q1 = new LinkedBlockingQueue<>();
final BlockingQueue<Message> q2 = new LinkedBlockingQueue<>();
crlogic.getEventBus().register(new Object(){
@Subscribe
public void onMessage(Message m){
q1.add(m);
}
});
scrlogic.getEventBus().register(new Object(){
@Subscribe
public void onMessage(Message m){
q2.add(m);
}
});
this.merger = new ParallelCrlogicStreamMerge(q1, q2, eventbus);
}
/* (non-Javadoc)
* @see ch.psi.fda.logic.Logic#prepare()
*/
@Override
public void prepare() {
// TODO Auto-generated method stub
}
/* (non-Javadoc)
* @see ch.psi.fda.logic.Logic#execute()
*/
@Override
public void execute() throws InterruptedException {
@@ -191,78 +202,36 @@ public class ParallelCrlogic implements ActionLoop {
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Action#abort()
*/
@Override
public void abort() {
// TODO Auto-generated method stub
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Action#destroy()
*/
@Override
public void destroy() {
crlogic.destroy();
scrlogic.destroy();
}
/* (non-Javadoc)
* @see ch.psi.fda.core.ActionLoop#cleanup()
*/
@Override
public void cleanup() {
// TODO Auto-generated method stub
}
/* (non-Javadoc)
* @see ch.psi.fda.core.ActionLoop#getPreActions()
*/
@Override
public List<Action> getPreActions() {
return preActions;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.ActionLoop#getPostActions()
*/
@Override
public List<Action> getPostActions() {
return postActions;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.ActionLoop#isDataGroup()
*/
@Override
public boolean isDataGroup() {
return dataGroup;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.ActionLoop#setDataGroup(boolean)
*/
@Override
public void setDataGroup(boolean dataGroup) {
this.dataGroup = dataGroup;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.ActionLoop#getDataQueue()
*/
@Override
public DataQueue getDataQueue() {
return(merger.getDataQueue());
public EventBus getEventBus(){
return eventbus;
}
}

View File

@@ -19,40 +19,41 @@
package ch.psi.fda.core.loops.cr;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import com.google.common.eventbus.EventBus;
import ch.psi.fda.core.messages.DataMessage;
import ch.psi.fda.core.messages.DataMessageMetadata;
import ch.psi.fda.core.messages.DataQueue;
import ch.psi.fda.core.messages.EndOfStreamMessage;
import ch.psi.fda.core.messages.Message;
import ch.psi.fda.core.messages.Metadata;
/**
* @author ebner
*
* Class to merge two data streams into one. The secondary queues data is added to the primary queues data.
* The resulting queue therefor will hold the same amount of elements as the primary queue does.
* The datagroup flag set in the end of stream message will be set according to the flag set in the primary queue.
*/
public class ParallelCrlogicStreamMerge {
private BlockingQueue<Message> dataQueue;
private DataQueue primaryQueue;
private DataQueue secondaryQueue;
private BlockingQueue<Message> primaryQueue;
private BlockingQueue<Message> secondaryQueue;
private final EventBus eventbus;
private List<Metadata> metadata;
/**
* Class to merge two data streams into one. The secondary queues data is added to the primary queues data.
* The resulting queue therefor will hold the same amount of elements as the primary queue does.
* The datagroup flag set in the end of stream message will be set according to the flag set in the primary queue.
*
* @param pqueue Primary/master queue
* @param squeue Secondary queue
*/
public ParallelCrlogicStreamMerge(DataQueue pqueue, DataQueue squeue){
public ParallelCrlogicStreamMerge(BlockingQueue<Message> pqueue, BlockingQueue<Message> squeue, EventBus ebus){
this.primaryQueue = pqueue;
this.secondaryQueue = squeue;
this.dataQueue = new LinkedBlockingQueue<Message>();
this.eventbus = ebus;
}
/**
@@ -61,11 +62,16 @@ public class ParallelCrlogicStreamMerge {
*/
public void merge() throws InterruptedException{
metadata = new ArrayList<>();
boolean firstPrimary = true;
boolean firstSecondary = true;
// Actual data of the secondary queue
List<Object> currData = null;
// Take first element of the primary queue (wait until message is available)
Message m = primaryQueue.getQueue().take();
Message m = primaryQueue.take();
while(! (m instanceof EndOfStreamMessage)){
@@ -73,18 +79,26 @@ public class ParallelCrlogicStreamMerge {
DataMessage dm = (DataMessage) m;
if(firstPrimary){
firstPrimary = false;
List<Metadata> pqm = dm.getMetadata();
metadata.add(pqm.get(0)); // add first component (this is the actuator)
// Skip the next component as this is the timestamp used to merge the data
for(int i=2;i<pqm.size();i++){
metadata.add(pqm.get(i));
}
}
// Get and remove merge timestamp from the data of the message
Double timestamp = (Double) dm.getData().remove(1);
long milliseconds = (long) (timestamp*1000);
long nanoOffset = (long)((timestamp*1000-milliseconds)*1000000);
// System.out.println("timestamp: "+new Date(milliseconds)+" "+milliseconds+" ."+nanoOffset);
while(true){
// Assumption: the secondary Queue holds at least the data up to the
// timestamp of the primary queue
Message mess = secondaryQueue.getQueue().peek();
// Message mess = secondaryQueue.getQueue().take();
Message mess = secondaryQueue.peek();
if(mess instanceof EndOfStreamMessage){
break;
@@ -95,23 +109,29 @@ public class ParallelCrlogicStreamMerge {
}
if(mess instanceof DataMessage){
// Check whether timestamp of the next message is bigger than the timestamp of the
// message from the primary queue - if the timestamp is bigger do not take message out of the queue
DataMessage msCheck = (DataMessage) mess;
// System.out.println("Mess: "+mess);
if(firstSecondary){
firstSecondary = false;
List<Metadata> sqm = msCheck.getMetadata();
// Skip first two components of the message as this is the timestamp
for(int i=2;i<sqm.size();i++){
metadata.add(sqm.get(i));
}
}
long currMilliCheck = ((Double) msCheck.getData().get(0)).longValue();
long currNanoCheck = ((Double) msCheck.getData().get(1)).longValue();
// Check
if(currMilliCheck>milliseconds || (currMilliCheck==milliseconds && currNanoCheck>nanoOffset)){
break;
}
DataMessage ms = (DataMessage) secondaryQueue.getQueue().take();
// System.out.println("Ms: "+ms);
DataMessage ms = (DataMessage) secondaryQueue.take();
currData = ms.getData();
// Remove timestamps
@@ -126,44 +146,18 @@ public class ParallelCrlogicStreamMerge {
// Add data to primary data queue message and put it into the out queue
dm.getData().addAll(currData);
dataQueue.add(dm);
dm.setMetadata(metadata);
eventbus.post(dm);
}
m = primaryQueue.getQueue().take();
m = primaryQueue.take();
}
// Add the end of stream message of the primary queue
dataQueue.add(m);
eventbus.post(m);
// Clear all remaining messages in secondary queue
secondaryQueue.getQueue().clear();
secondaryQueue.clear();
}
/**
* The structure of the data message depends on the sensors registered at this loop
* at the time this method is called.
* @return the data queue and the metadata of the data messages
*/
public DataQueue getDataQueue() {
DataMessageMetadata m = new DataMessageMetadata();
DataMessageMetadata pqm = primaryQueue.getDataMessageMetadata();
m.getComponents().add(pqm.getComponents().get(0)); // add first component (this is the actuator)
// Skip the next component as this is the timestamp used to merge the data
for(int i=2;i<pqm.getComponents().size();i++){
m.getComponents().add(pqm.getComponents().get(i));
}
DataMessageMetadata sqm = secondaryQueue.getDataMessageMetadata();
// Skip first two components of the message as this is the timestamp
for(int i=2;i<sqm.getComponents().size();i++){
m.getComponents().add(sqm.getComponents().get(i));
}
return new DataQueue(dataQueue, m);
}
}

View File

@@ -19,39 +19,26 @@
package ch.psi.fda.core.loops.cr;
import gov.aps.jca.Monitor;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeoutException;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.google.common.eventbus.EventBus;
import ch.psi.fda.core.Action;
import ch.psi.fda.core.ActionLoop;
import ch.psi.fda.core.Sensor;
import ch.psi.fda.core.messages.ComponentMetadata;
import ch.psi.fda.core.messages.DataMessage;
import ch.psi.fda.core.messages.DataMessageMetadata;
import ch.psi.fda.core.messages.DataQueue;
import ch.psi.fda.core.messages.EndOfStreamMessage;
import ch.psi.fda.core.messages.Message;
import ch.psi.fda.core.sensors.ChannelAccessDoubleSensor;
import ch.psi.fda.core.messages.Metadata;
import ch.psi.jcae.Channel;
import ch.psi.jcae.ChannelDescriptor;
import ch.psi.jcae.ChannelException;
import ch.psi.jcae.ChannelService;
import ch.psi.jcae.impl.type.DoubleTimestamp;
/**
* @author ebner
*
* Assumptions: - The delay between the monitor writing the value to the
* monitor queue and the readout of all the queues is sufficient to
* prevent the situation that some monitors of events close to each
@@ -81,16 +68,14 @@ public class ScrlogicLoop implements ActionLoop {
* Data queue sensor data is posted to. A message consists of a list of data
* objects that are read out of the sensors of this loop.
*/
private final BlockingQueue<Message> dataQueue = new LinkedBlockingQueue<Message>();
// private final BlockingQueue<Message> dataQueue = new LinkedBlockingQueue<Message>();
private boolean dataGroup = false;
private final List<Action> preActions = new ArrayList<Action>();
private final List<Action> postActions = new ArrayList<Action>();
/**
* Sensors to read out
*/
// private List<Sensor> sensors;
private List<String> sensorIds;
private List<Channel<DoubleTimestamp>> sensors;
/**
* List of monitors that were attached to the sensor channels (i.e
@@ -105,27 +90,15 @@ public class ScrlogicLoop implements ActionLoop {
private CountDownLatch latch;
private List<Channel<DoubleTimestamp>> sensors = new ArrayList<>();
private List<String> sensorIds = new ArrayList<>();
private ChannelService cservice;
private final EventBus eventbus;
private List<Metadata> metadata;
public ScrlogicLoop(ChannelService s, List<Sensor> sensors) {
try{
for(Sensor ss: sensors){
this.sensors.add(s.createChannel(new ChannelDescriptor<DoubleTimestamp>(DoubleTimestamp.class, ((ChannelAccessDoubleSensor)ss).getChannel().getName(), true)));
sensorIds.add(ss.getId());
}
this.cservice = s;
} catch (ChannelException | InterruptedException | TimeoutException e) {
throw new RuntimeException(e);
}
public ScrlogicLoop(List<String> sensorIds, List<Channel<DoubleTimestamp>> sensors) {
this.eventbus = new EventBus();
this.sensorIds = sensorIds;
this.sensors = sensors;
}
/*
* (non-Javadoc)
*
* @see ch.psi.fda.core.Action#execute()
*/
@Override
public void execute() throws InterruptedException {
@@ -135,26 +108,21 @@ public class ScrlogicLoop implements ActionLoop {
// Attach monitors to the channels (this is actually a workaround)
for (Channel<DoubleTimestamp> sensor : sensors) {
// if (sensor instanceof ChannelAccessDoubleSensor) {
// ChannelAccessDoubleSensor s = (ChannelAccessDoubleSensor) sensor;
// Channel<Double> b = s.getChannel();
// Create data queue for the channel
final BlockingQueue<TimestampedValue> q = new LinkedBlockingQueue<TimestampedValue>();
queues.add(q);
final BlockingQueue<TimestampedValue> q = new LinkedBlockingQueue<TimestampedValue>();
queues.add(q);
PropertyChangeListener listener = new PropertyChangeListener() {
PropertyChangeListener b = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
DoubleTimestamp value = (DoubleTimestamp) evt.getNewValue();
q.add(new TimestampedValue(value.getValue(), value.getTimestamp().getTime(), value.getNanosecondOffset()));
@Override
public void propertyChange(PropertyChangeEvent evt) {
if(evt.getPropertyName().equals("value")){
DoubleTimestamp v = (DoubleTimestamp) evt.getNewValue();
q.add(new TimestampedValue(v.getValue(), v.getTimestamp().getTime(), v.getNanosecondOffset()));
}
};
sensor.addPropertyChangeListener("value", b);
monitors.add(b);
// }
}
};
sensor.addPropertyChangeListener(listener);
monitors.add(listener);
}
logger.info("Start data acquisition");
@@ -162,15 +130,10 @@ public class ScrlogicLoop implements ActionLoop {
latch.await();
// Remove monitors
try{
for (int i = 0; i < sensors.size(); i++) {
Channel<DoubleTimestamp> sensor = sensors.get(i);
sensor.removePropertyChangeListener(monitors.get(i));
}
}
finally{
// Clear all monitors in the list
monitors.clear();
for (int i = 0; i < sensors.size(); i++) {
Channel<DoubleTimestamp> sensor = sensors.get(i);
sensor.removePropertyChangeListener(monitors.get(i));
}
// Merge data
@@ -181,122 +144,58 @@ public class ScrlogicLoop implements ActionLoop {
q.clear();
}
queues.clear();
// Put end of stream to the queue
dataQueue.add(new EndOfStreamMessage(dataGroup));
eventbus.post(new EndOfStreamMessage(dataGroup));
}
/*
* (non-Javadoc)
*
* @see ch.psi.fda.core.Action#abort()
*/
@Override
public void abort() {
latch.countDown();
}
/*
* (non-Javadoc)
*
* @see ch.psi.fda.core.Action#destroy()
*/
@Override
public void destroy() {
// Destroy all sensors
for (Channel<DoubleTimestamp> s : sensors) {
try {
s.destroy();
} catch (ChannelException e) {
throw new RuntimeException(e);
}
}
sensors.clear();
}
/*
* (non-Javadoc)
*
* @see ch.psi.fda.core.ActionLoop#prepare()
*/
@Override
public void prepare() {
// do nothing
metadata = new ArrayList<>();
// Build up data message metadata based on the channels registered.
metadata.add(new Metadata(ID_TIMESTAMP_MILLISECONDS));
metadata.add(new Metadata(ID_TIMESTAMP_OFFSET_NANOSECONDS));
for (String id : sensorIds) {
metadata.add(new Metadata(id));
}
}
/*
* (non-Javadoc)
*
* @see ch.psi.fda.core.ActionLoop#cleanup()
*/
@Override
public void cleanup() {
// Do nothing
}
/*
* (non-Javadoc)
*
* @see ch.psi.fda.core.ActionLoop#getPreActions()
*/
@Override
public List<Action> getPreActions() {
return preActions;
}
/*
* (non-Javadoc)
*
* @see ch.psi.fda.core.ActionLoop#getPostActions()
*/
@Override
public List<Action> getPostActions() {
return postActions;
}
/*
* (non-Javadoc)
*
* @see ch.psi.fda.core.ActionLoop#isDataGroup()
*/
@Override
public boolean isDataGroup() {
return dataGroup;
}
/*
* (non-Javadoc)
*
* @see ch.psi.fda.core.ActionLoop#setDataGroup(boolean)
*/
@Override
public void setDataGroup(boolean dataGroup) {
this.dataGroup = dataGroup;
}
/**
* The structure of the data message depends on the sensors registered at
* this loop at the time this method is called.
*
* @return the data queue and the metadata of the data messages
*/
public DataQueue getDataQueue() {
DataMessageMetadata m = new DataMessageMetadata();
// Build up data message metadata based on the channels registered.
m.getComponents().add(new ComponentMetadata(ID_TIMESTAMP_MILLISECONDS));
m.getComponents().add(
new ComponentMetadata(ID_TIMESTAMP_OFFSET_NANOSECONDS));
for (String id : sensorIds) {
m.getComponents().add(new ComponentMetadata(id));
}
return new DataQueue(dataQueue, m);
}
private boolean hasNext(){
for (int i = 0; i < queues.size(); i++) {
if(!queues.get(i).isEmpty()){
for (BlockingQueue<TimestampedValue> q: queues) {
if(!q.isEmpty()){
return true;
}
}
@@ -309,7 +208,6 @@ public class ScrlogicLoop implements ActionLoop {
* @throws InterruptedException
*/
private void merge() throws InterruptedException {
// Array to hold temporary channel values
TimestampedValue[] cvalues = new TimestampedValue[queues.size()];
TimestampedValueComparator comparator = new TimestampedValueComparator();
@@ -319,8 +217,6 @@ public class ScrlogicLoop implements ActionLoop {
List<Integer> indexes = new ArrayList<Integer>();
while (hasNext()) {
// semaphore.acquire();
Thread.sleep(10); // Ensure that close by monitors have time to
// catch up / also ensure context switch
@@ -384,7 +280,7 @@ public class ScrlogicLoop implements ActionLoop {
}
// Assemble data message ...
DataMessage message = new DataMessage();
DataMessage message = new DataMessage(metadata);
message.getData().add(new Double(timestamp));
message.getData().add(new Double(nanoOffset));
@@ -397,9 +293,13 @@ public class ScrlogicLoop implements ActionLoop {
}
}
// System.out.println(message);
dataQueue.add(message);
eventbus.post(message);
}
}
}
public EventBus getEventBus(){
return eventbus;
}
}

View File

@@ -22,17 +22,8 @@ package ch.psi.fda.core.loops.cr;
import ch.psi.jcae.Channel;
import ch.psi.jcae.annotation.CaChannel;
/**
* @author ebner
*
*/
public class CrlogicChannelsTemplate {
public class TemplateCrlogic {
/**
* Status of the OTFSCAN IOC logic
*/
public enum Status { SETUP, INACTIVE, INITIALIZE, ACTIVE, STOP, FAULT, ERROR };
/**
* Ticks per second - IOC setting
* ATTENTION - This field must only be set bu the IOC - ATTENTION
@@ -43,6 +34,7 @@ public class CrlogicChannelsTemplate {
/**
* Status of the OTFSCAN IOC logic
*/
public enum Status { SETUP, INACTIVE, INITIALIZE, ACTIVE, STOP, FAULT, ERROR };
@CaChannel(type=String.class, name ="${PREFIX}:STATUS")
private Channel<String> status;
@@ -83,7 +75,6 @@ public class CrlogicChannelsTemplate {
@CaChannel(type=Boolean.class, name ="${PREFIX}:FAPPE")
private Channel<Boolean> appendFile;
/**
* Readout resources
*/
@@ -91,65 +82,31 @@ public class CrlogicChannelsTemplate {
private Channel<String[]> readoutResources;
/**
* @return the ticksPerSecond
*/
public Channel<Integer> getTicksPerSecond() {
return ticksPerSecond;
}
/**
* @return the status
*/
public Channel<String> getStatus() {
return status;
}
/**
* @return the message
*/
public Channel<String> getMessage() {
return message;
}
/**
* @return the ticksBetweenInterrupts
*/
public Channel<Integer> getTicksBetweenInterrupts() {
return ticksBetweenInterrupts;
}
/**
* @return the nfsServer
*/
public Channel<String> getNfsServer() {
return nfsServer;
}
/**
* @return the nfsShare
*/
public Channel<String> getNfsShare() {
return nfsShare;
}
/**
* @return the dataFile
*/
public Channel<String> getDataFile() {
return dataFile;
}
/**
* @return the appendFile
*/
public Channel<Boolean> getAppendFile() {
return appendFile;
}
/**
* @return the readoutResources
*/
public Channel<String[]> getReadoutResources() {
return readoutResources;
}

View File

@@ -22,11 +22,7 @@ package ch.psi.fda.core.loops.cr;
import ch.psi.jcae.Channel;
import ch.psi.jcae.annotation.CaChannel;
/**
* @author ebner
*
*/
public class EncoderChannelsTemplate {
public class TemplateEncoder {
/**
* Resolution - $(P)$(E)_SCL
@@ -48,23 +44,13 @@ public class EncoderChannelsTemplate {
private Channel<Integer> direction;
/**
* @return the resolution
*/
public Channel<Double> getResolution() {
return resolution;
}
/**
* @return the offset
*/
public Channel<Double> getOffset() {
return offset;
}
/**
* @return the direction
*/
public Channel<Integer> getDirection() {
return direction;
}

View File

@@ -22,11 +22,7 @@ package ch.psi.fda.core.loops.cr;
import ch.psi.jcae.Channel;
import ch.psi.jcae.annotation.CaChannel;
/**
* @author ebner
*
*/
public class MotorChannelsTemplate {
public class TemplateMotor {
public enum Type {SOFT_CHANNEL, MOTOR_SIMULATION, OMS_VME58, OMS_MAXv};
@@ -334,317 +330,140 @@ public class MotorChannelsTemplate {
@CaChannel(type=Boolean.class, name ="${PREFIX}.DMOV", monitor=true)
private Channel<Boolean> moveDone;
/**
* @return the highLimit
*/
public Channel<Double> getHighLimit() {
return highLimit;
}
/**
* @return the lowLimit
*/
public Channel<Double> getLowLimit() {
return lowLimit;
}
/**
* @return the readbackValue
*/
public Channel<Double> getReadbackValue() {
return readbackValue;
}
/**
* @return the setValue
*/
public Channel<Double> getSetValue() {
return setValue;
}
/**
* @return the relativeMoveValue
*/
public Channel<Double> getRelativeMoveValue() {
return relativeMoveValue;
}
/**
* @return the tweakValue
*/
public Channel<Double> getTweakValue() {
return tweakValue;
}
/**
* @return the tweakReverse
*/
public Channel<Integer> getTweakReverse() {
return tweakReverse;
}
/**
* @return the tweakForward
*/
public Channel<Integer> getTweakForward() {
return tweakForward;
}
/**
* @return the jogReverse
*/
public Channel<Integer> getJogReverse() {
return jogReverse;
}
/**
* @return the jogForward
*/
public Channel<Integer> getJogForward() {
return jogForward;
}
/**
* @return the homeReverse
*/
public Channel<Integer> getHomeReverse() {
return homeReverse;
}
/**
* @return the homeForward
*/
public Channel<Integer> getHomeForward() {
return homeForward;
}
/**
* @return the engineeringUnit
*/
public Channel<String> getEngineeringUnit() {
return engineeringUnit;
}
/**
* @return the type
*/
public Channel<Integer> getType() {
return type;
}
/**
* @return the description
*/
public Channel<String> getDescription() {
return description;
}
/**
* @return the dialHighLimit
*/
public Channel<Double> getDialHighLimit() {
return dialHighLimit;
}
/**
* @return the dialLowLimit
*/
public Channel<Double> getDialLowLimit() {
return dialLowLimit;
}
/**
* @return the dialReadbackValue
*/
public Channel<Double> getDialReadbackValue() {
return dialReadbackValue;
}
/**
* @return the dialSetValue
*/
public Channel<Double> getDialSetValue() {
return dialSetValue;
}
/**
* @return the rawValue
*/
public Channel<Integer> getRawValue() {
return rawValue;
}
/**
* @return the rawReadbackValue
*/
public Channel<Integer> getRawReadbackValue() {
return rawReadbackValue;
}
/**
* @return the command
*/
public Channel<Integer> getCommand() {
return command;
}
/**
* @return the calibration
*/
public Channel<Integer> getCalibration() {
return calibration;
}
/**
* @return the userOffset
*/
public Channel<Double> getOffset() {
return offset;
}
/**
* @return the offsetMode
*/
public Channel<Integer> getOffsetMode() {
return offsetMode;
}
/**
* @return the direction
*/
public Channel<Integer> getDirection() {
return direction;
}
/**
* @return the velocity
*/
public Channel<Double> getVelocity() {
return velocity;
}
/**
* @return the backlashVelocity
*/
public Channel<Double> getBacklashVelocity() {
return backlashVelocity;
}
/**
* @return the baseSpeed
*/
public Channel<Double> getBaseSpeed() {
return baseSpeed;
}
/**
* @return the accelerationTime
*/
public Channel<Double> getAccelerationTime() {
return accelerationTime;
}
/**
* @return the backlashAccelerationTime
*/
public Channel<Double> getBacklashAccelerationTime() {
return backlashAccelerationTime;
}
/**
* @return the backlashDistance
*/
public Channel<Double> getBacklashDistance() {
return backlashDistance;
}
/**
* @return the moveFracion
*/
public Channel<Double> getMoveFracion() {
return moveFracion;
}
/**
* @return the motorResolution
*/
public Channel<Double> getMotorResolution() {
return motorResolution;
}
/**
* @return the encoderResolution
*/
public Channel<Double> getEncoderResolution() {
return encoderResolution;
}
/**
* @return the readbackResolution
*/
public Channel<Double> getReadbackResolution() {
return readbackResolution;
}
/**
* @return the retryDeadband
*/
public Channel<Double> getRetryDeadband() {
return retryDeadband;
}
/**
* @return the maxRetryCount
*/
public Channel<Integer> getMaxRetryCount() {
return maxRetryCount;
}
/**
* @return the retryCount
*/
public Channel<Integer> getRetryCount() {
return retryCount;
}
/**
* @return the useEncoder
*/
public Channel<Boolean> getUseEncoder() {
return useEncoder;
}
/**
* @return the useReadback
*/
public Channel<Boolean> getUseReadback() {
return useReadback;
}
/**
* @return the readbackDelay
*/
public Channel<Double> getReadbackDelay() {
return readbackDelay;
}
/**
* @return the readbackLink
*/
public Channel<String> getReadbackLink() {
return readbackLink;
}
/**
* @return the outputMode
*/
public Channel<Integer> getOutputMode() {
return outputMode;
}
/**
* @return the moveDone
*/
public Channel<Boolean> getMoveDone() {
return moveDone;
}

View File

@@ -24,17 +24,12 @@ import java.util.List;
import ch.psi.jcae.Channel;
import ch.psi.jcae.annotation.CaChannel;
/**
* @author ebner
*
*/
public class VSC16ScalerChannelsTemplate {
public class TemplateVSC16Scaler {
public enum Command {Done, Count};
/**
* Command
*/
public enum Command {Done, Count};
@CaChannel(type=Integer.class, name ="${PREFIX}.CNT")
private Channel<Integer> command;
@@ -65,39 +60,21 @@ public class VSC16ScalerChannelsTemplate {
@CaChannel(type=Integer.class, name={"${PREFIX}.PR1", "${PREFIX}.PR2", "${PREFIX}.PR3", "${PREFIX}.PR4", "${PREFIX}.PR5", "${PREFIX}.PR6", "${PREFIX}.PR7", "${PREFIX}.PR8", "${PREFIX}.PR9", "${PREFIX}.PR10", "${PREFIX}.PR11", "${PREFIX}.PR12", "${PREFIX}.PR13", "${PREFIX}.PR14", "${PREFIX}.PR15", "${PREFIX}.PR16"})
private List<Channel<Integer>> channelPresetCount;
/**
* @return the command
*/
public Channel<Integer> getCommand() {
return command;
}
/**
* @return the mode
*/
public Channel<Integer> getMode() {
return mode;
}
/**
* @return the channelDescription
*/
public List<Channel<Boolean>> getChannelDescription() {
return channelDescription;
}
/**
* @return the channelGate
*/
public List<Channel<Boolean>> getChannelGate() {
return channelGate;
}
/**
* @return the channelPresetCount
*/
public List<Channel<Integer>> getChannelPresetCount() {
return channelPresetCount;
}
}

View File

@@ -19,15 +19,11 @@
package ch.psi.fda.core.loops.cr;
/**
* @author ebner
*
*/
public class TimestampedValue {
private Double value;
private long timestamp;
private long nanosecondsOffset;
private final Double value;
private final long timestamp;
private final long nanosecondsOffset;
public TimestampedValue(Double value, long timestamp, long nanosecondsOffset){
this.value = value;
@@ -35,47 +31,13 @@ public class TimestampedValue {
this.nanosecondsOffset = nanosecondsOffset;
}
/**
* @return the value
*/
public Double getValue() {
return value;
}
/**
* @param value the value to set
*/
public void setValue(Double value) {
this.value = value;
}
/**
* @return the timestamp
*/
public long getTimestamp() {
return timestamp;
}
/**
* @param timestamp the timestamp to set
*/
public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}
/**
* @return the nanosecondsOffset
*/
public long getNanosecondsOffset() {
return nanosecondsOffset;
}
/**
* @param nanosecondsOffset the nanosecondsOffset to set
*/
public void setNanosecondsOffset(long nanosecondsOffset) {
this.nanosecondsOffset = nanosecondsOffset;
}
}

View File

@@ -22,8 +22,7 @@ package ch.psi.fda.core.loops.cr;
import java.util.Comparator;
/**
* @author ebner
*
* Comparator for comparint 2 timestamped values
*/
public class TimestampedValueComparator implements Comparator<TimestampedValue> {

View File

@@ -16,7 +16,7 @@
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.loops;
package ch.psi.fda.core.loops.otf;
import java.io.File;
import java.io.FileReader;
@@ -26,10 +26,6 @@ import java.net.MalformedURLException;
import jcifs.smb.SmbFile;
/**
* @author ebner
*
*/
public class DistributedFile {
private SmbFile smbfile = null;

View File

@@ -17,57 +17,32 @@
*
*/
package ch.psi.fda.core.loops;
package ch.psi.fda.core.loops.otf;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeoutException;
import java.util.logging.Logger;
//import jcifs.smb.SmbException;
//import jcifs.smb.SmbFile;
import com.google.common.eventbus.EventBus;
import ch.psi.fda.core.Action;
import ch.psi.fda.core.ActionLoop;
import ch.psi.fda.core.Sensor;
import ch.psi.fda.core.actors.OTFActuator;
import ch.psi.fda.core.messages.ComponentMetadata;
import ch.psi.fda.core.messages.DataMessage;
import ch.psi.fda.core.messages.DataMessageMetadata;
import ch.psi.fda.core.messages.DataQueue;
import ch.psi.fda.core.messages.EndOfStreamMessage;
import ch.psi.fda.core.messages.Message;
import ch.psi.fda.core.sensors.MillisecondTimestampSensor;
import ch.psi.fda.core.sensors.OTFNamedChannelSensor;
import ch.psi.fda.core.sensors.OTFReadbackSensor;
import ch.psi.fda.core.sensors.OTFScalerChannelSensor;
import ch.psi.jcae.ChannelException;
import ch.psi.jcae.ChannelService;
import ch.psi.fda.core.messages.Metadata;
import ch.psi.fda.core.sensors.TimestampSensor;
/**
* ActionLoop that is implementing the OTF Scan logic.
* While executing the loop a full OTF scan procedure is executed.
* @author ebner
*
*/
public class OTFLoop implements ActionLoop {
// Get Logger
private static Logger logger = Logger.getLogger(OTFLoop.class.getName());
/**
@@ -76,7 +51,6 @@ public class OTFLoop implements ActionLoop {
*/
private boolean dataGroup = false;
// Constants
/**
* Maximum number of monitored channels
*/
@@ -112,7 +86,7 @@ public class OTFLoop implements ActionLoop {
/**
* Bean holding all OTF channels and functionality.
*/
private OTFBean obean;
private TemplateOTF obean;
/**
* List of actions that are executed at the beginning of the loop.
@@ -123,11 +97,6 @@ public class OTFLoop implements ActionLoop {
*/
private List<Action> postActions;
/**
* Special OTF Actuator
*/
private OTFActuator actor = null;
/**
* List of sensors of this loop
*/
@@ -142,40 +111,36 @@ public class OTFLoop implements ActionLoop {
*/
private int executionCount;
/**
* Data queue sensor data is posted to. A message consists of a list of data objects
* that are read out of the sensors of this loop.
*/
private BlockingQueue<Message> dataQueue;
/**
* Flag that indicates that the loop was requested to abort.
*/
private volatile boolean abort = false;
private ChannelService cservice;
private String id;
private String name; // name of the motor channel
private String readback; // name of the encoder channel
private double start;
private double end;
private double stepSize;
private double integrationTime;
private double additionalBacklash;
private final EventBus eventbus;
private List<Metadata> metadata;
/**
* Constructor
* @param channelPrefix Prefix of the OTF related records, e.g. MTEST-HW3-OTF
* @param server NFS server the OTF C Logic should put its data to
* @param share Share on NFS server to put the OTF C Logic data
* @param smbShare SMB share to get the data written by the OTF C Logic
* @param zigZag Operate loop in zig zag mode
*/
public OTFLoop(ChannelService s, String channelPrefix, String server, String share, String smbShare, boolean zigZag){
cservice = s;
// Initialize connection to the OTF records
try {
this.obean = new OTFBean();
Map<String,String> m = new HashMap<>();
m.put("PREFIX", channelPrefix);
s.createAnnotatedChannels(obean, m);
} catch (ChannelException | TimeoutException e) {
throw new IllegalArgumentException("Unable to connect to the OTF channels",e);
} catch (InterruptedException e) {
throw new RuntimeException("Unable to connect to the OTF channels",e);
}
public OTFLoop(TemplateOTF obean, String server, String share, String smbShare, boolean zigZag){
this.eventbus = new EventBus();
this.obean = obean;
// Store loop configuration
this.server = server;
@@ -187,13 +152,20 @@ public class OTFLoop implements ActionLoop {
this.preActions = new ArrayList<Action>();
this.postActions = new ArrayList<Action>();
this.sensors = new ArrayList<Sensor>();
this.dataQueue = new LinkedBlockingQueue<Message>(2000);
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Action#execute()
*/
public void setActuator(String id, String name, String readback, double start, double end, double stepSize, double integrationTime, double additionalBacklash){
this.id = id;
this.name = name;
this.readback = readback;
this.start = start;
this.end = end;
this.stepSize = stepSize;
this.integrationTime = integrationTime;
this.additionalBacklash = additionalBacklash;
}
@Override
public void execute() throws InterruptedException {
@@ -218,15 +190,12 @@ public class OTFLoop implements ActionLoop {
// Issue end of loop control message
dataQueue.put(new EndOfStreamMessage(dataGroup));
eventbus.post(new EndOfStreamMessage(dataGroup));
// Increase execution count
executionCount++;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Action#abort()
*/
@Override
public void abort() {
// Abort otf scan logic
@@ -235,9 +204,6 @@ public class OTFLoop implements ActionLoop {
abort=true;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.ActionLoop#prepare()
*/
@Override
public void prepare() {
executionCount = 0;
@@ -245,14 +211,10 @@ public class OTFLoop implements ActionLoop {
// Set abort flag to false
abort=false;
// Check whether actor is set for the loop
if(actor == null){
throw new IllegalStateException("No actor specified for this loop");
}
// list with all monitored channels
List<String> monitoredChannels = new ArrayList<String>();
dataIndexes = new ArrayList<Integer>();
dataIndexes.add(1); // The first one is always the readback of the motor
int channelCount =0;
for(Sensor s: sensors){
if(s instanceof OTFNamedChannelSensor){
@@ -275,12 +237,12 @@ public class OTFLoop implements ActionLoop {
}
dataIndexes.add(2+so.getIndex()); // scalers follow directly after the readback
}
else if (s instanceof MillisecondTimestampSensor){
else if (s instanceof TimestampSensor){
dataIndexes.add(2+numberOfScalerChannels+numberOfMonitoredChannels);
}
else if (s instanceof OTFReadbackSensor){
dataIndexes.add(1);
}
// else if (s instanceof OTFReadbackSensor){
// dataIndexes.add(1);
// }
else{
throw new IllegalArgumentException("Sensor type "+s.getClass()+" is not supported by this loop");
}
@@ -291,23 +253,23 @@ public class OTFLoop implements ActionLoop {
obean.resetToDefaults();
// Set actor properties
obean.setMotor(actor.getName());
obean.setMotor(this.name);
obean.waitUntilMotorOk(timeout);
obean.setBegin(actor.getStart());
obean.setEnd(actor.getEnd());
obean.setStepSize(actor.getStepSize());
obean.setIntegrationTime(actor.getIntegrationTime());
obean.setBegin(this.start);
obean.setEnd(this.end);
obean.setStepSize(this.stepSize);
obean.setIntegrationTime(this.integrationTime);
// Override encoder if specified
if(actor.getReadback()!=null){
if(this.readback!=null){
obean.setUseEncoder(true);
obean.setEncoder(actor.getReadback());
obean.setEncoder(this.readback);
obean.waitUntilEncoderOk(timeout);
}
// Set user backlash
obean.setUserBacklash(actor.getAdditionalBacklash());
obean.setUserBacklash(this.additionalBacklash);
// NFS settings
@@ -325,9 +287,7 @@ public class OTFLoop implements ActionLoop {
// Set monitored channels
obean.setMonitoredChannels(monitoredChannels.toArray(new String[monitoredChannels.size()]));
}
catch(ChannelException | ExecutionException | TimeoutException e){
throw new RuntimeException("Unable to set OTF configuration parameters",e);
} catch (InterruptedException e) {
catch(Exception e){
throw new RuntimeException("Unable to set OTF configuration parameters",e);
}
@@ -354,61 +314,29 @@ public class OTFLoop implements ActionLoop {
throw new RuntimeException("Unable to access share (temporary files)",e);
}
metadata = new ArrayList<>();
metadata.add(new Metadata(id)); // Id of the readback of the motor
// Build up data message metadata based on the sensors currently registered.
for(Sensor s: sensors){
metadata.add(new Metadata(s.getId()));
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.ActionLoop#cleanup()
*/
@Override
public void cleanup() {
// TODO Auto-generated method stub
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Action#destroy()
*/
@Override
public void destroy() {
// Close all connections used by the OTFBean
try {
cservice.destroyAnnotatedChannels(obean);
} catch (ChannelException e) {
throw new RuntimeException("Unable to destroy channels",e);
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.ActionLoop#getPreActions()
*/
@Override
public List<Action> getPreActions() {
return preActions;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.ActionLoop#getPostActions()
*/
@Override
public List<Action> getPostActions() {
return postActions;
}
/**
* The structure of the data message depends on the sensors registered at this loop
* at the time this method is called.
* @return the data queue and the metadata of the data messages
*/
public DataQueue getDataQueue() {
DataMessageMetadata m = new DataMessageMetadata();
// Build up data message metadata based on the sensors currently registered.
for(Sensor s: sensors){
m.getComponents().add(new ComponentMetadata(s.getId()));
}
return new DataQueue(dataQueue, m);
}
/**
* Collect data written by the OTFScan logic
* @param dataSet
@@ -453,7 +381,7 @@ public class OTFLoop implements ActionLoop {
continue;
}
DataMessage message = new DataMessage();
DataMessage message = new DataMessage(metadata);
// Add data to dataset
String[] tokens = line.split("\t");
@@ -477,7 +405,7 @@ public class OTFLoop implements ActionLoop {
message.getData().add(new Double(0));
}
}
dataQueue.put(message);
eventbus.post(message);
}
}
}
@@ -491,43 +419,21 @@ public class OTFLoop implements ActionLoop {
}
// Getter functions for variable parts
/**
* @return the sensors
*/
public List<Sensor> getSensors() {
return sensors;
}
/**
* @return the actor
*/
public OTFActuator getActor() {
return actor;
}
/**
* @param actor the actor to set
*/
public void setActor(OTFActuator actor) {
this.actor = actor;
}
/**
* @return the dataGroup
*/
public boolean isDataGroup() {
return dataGroup;
}
/**
* @param dataGroup the dataGroup to set
*/
public void setDataGroup(boolean dataGroup) {
this.dataGroup = dataGroup;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.ActionLoop#getEventBus()
*/
@Override
public EventBus getEventBus() {
return eventbus;
}
}

View File

@@ -17,7 +17,7 @@
*
*/
package ch.psi.fda.core.sensors;
package ch.psi.fda.core.loops.otf;
import ch.psi.fda.core.Sensor;
@@ -49,9 +49,6 @@ public class OTFNamedChannelSensor implements Sensor {
this.name = name;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Sensor#read()
*/
@Override
public Object read() {
// Always return 0 if read() method is called.
@@ -65,20 +62,8 @@ public class OTFNamedChannelSensor implements Sensor {
return name;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Sensor#getId()
*/
@Override
public String getId() {
return id;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Sensor#destroy()
*/
@Override
public void destroy() {
// Nothing to be done
}
}

View File

@@ -17,14 +17,13 @@
*
*/
package ch.psi.fda.core.sensors;
package ch.psi.fda.core.loops.otf;
import ch.psi.fda.core.Sensor;
/**
* Sensor to read out a scaler channel. This sensor can only be used within the
* OTFLoop. If it is used in other loops, the read value will always be 0.
* @author ebner
*
*/
public class OTFScalerChannelSensor implements Sensor {
@@ -49,12 +48,8 @@ public class OTFScalerChannelSensor implements Sensor {
this.index = index;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Sensor#read()
*/
@Override
public Object read() {
// Always return 0 if read() method is called.
return 0d;
}
@@ -65,20 +60,8 @@ public class OTFScalerChannelSensor implements Sensor {
return index;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Sensor#getId()
*/
@Override
public String getId() {
return id;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Sensor#destroy()
*/
@Override
public void destroy() {
// Nothing to be done
}
}

View File

@@ -17,22 +17,22 @@
*
*/
package ch.psi.fda.core.loops;
package ch.psi.fda.core.loops.otf;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import ch.psi.jcae.annotation.CaChannel;
import ch.psi.jcae.Channel;
import ch.psi.jcae.ChannelException;
import ch.psi.jcae.annotation.CaChannel;
/**
* Bean holding all OTF channels and functionality
* @author ebner
*
*/
public class OTFBean {
public class TemplateOTF {
public enum Status { SETUP, INACTIVE, INITIALIZE, ACTIVE, STOP, FAULT, ERROR };
public enum Command { NONE, START, STOP };
@@ -211,7 +211,7 @@ public class OTFBean {
throw new RuntimeException("OTFSCAN failed with message: "+message.getValue());
}
} catch (ChannelException | ExecutionException | TimeoutException e) {
} catch (ExecutionException | ChannelException | TimeoutException e) {
throw new RuntimeException("An error occurred while waiting for the OTF logic to finish.", e);
}
}
@@ -230,7 +230,7 @@ public class OTFBean {
throw new RuntimeException("OTFSCAN failed with message: "+message.getValue());
}
} catch (ChannelException | ExecutionException | TimeoutException e) {
} catch (ExecutionException | ChannelException | TimeoutException e) {
throw new RuntimeException("An error occurred while waiting for the OTF logic to finish.", e);
}
@@ -240,10 +240,11 @@ public class OTFBean {
/**
* Reset OTFScan records to defaults
* @throws TimeoutException, ChannelException, ExecutionException
* @throws CAException
* @throws InterruptedException
*/
public void resetToDefaults() throws ChannelException , ExecutionException , TimeoutException, InterruptedException{
public void resetToDefaults() throws InterruptedException{
try{
setMonitoredChannels(new String[]{});
setMotor("");
begin.setValue(0d);
@@ -263,219 +264,254 @@ public class OTFBean {
// setNfsShare("");
waitUntilMotorNotOk(timeoutMotorOk);
}
catch(ExecutionException | ChannelException e){
throw new RuntimeException(e);
}
}
/**
* Get motor of the OTFScan axis
* @return Name of the OTF motor
* @throws ExecutionException
* @throws TimeoutException
* @throws TimeoutException, ChannelException, ExecutionException
* @throws CAException
*/
public String getMotor() throws ChannelException, InterruptedException, TimeoutException, ExecutionException {
return(this.motor.getValue());
public String getMotor() throws InterruptedException {
try {
return(this.motor.getValue());
} catch (TimeoutException | ChannelException | ExecutionException e) {
throw new RuntimeException(e);
}
}
/**
* Set motor of the OTFScan axis
* @param motor
* @throws ChannelException
* @throws ExecutionException
* @throws TimeoutException, ChannelException, ExecutionException
* @throws CAException
*/
public void setMotor(String motor) throws InterruptedException, ExecutionException, ChannelException {
this.motor.setValue(motor);
public void setMotor(String motor) throws InterruptedException {
try{
this.motor.setValue(motor);
} catch (ChannelException | ExecutionException e) {
throw new RuntimeException(e);
}
}
/**
* Get encoder of the OTFScan axis
* @return Name of the used encoder
* @throws ExecutionException
* @throws ChannelException
* @throws TimeoutException
* @throws TimeoutException, ChannelException, ExecutionException
* @throws CAException
*/
public String getEncoder() throws InterruptedException, TimeoutException, ChannelException, ExecutionException {
return(this.encoder.getValue());
public String getEncoder() throws InterruptedException {
try{
return(this.encoder.getValue());
} catch (TimeoutException | ChannelException | ExecutionException e) {
throw new RuntimeException(e);
}
}
/**
* Set encoder to use of the OTFScan axis
* @param encoder
* @throws ChannelException
* @throws ExecutionException
* @throws TimeoutException, ChannelException, ExecutionException
* @throws CAException
*/
public void setEncoder(String encoder) throws InterruptedException, ExecutionException, ChannelException {
this.encoder.setValue(encoder);
public void setEncoder(String encoder) throws InterruptedException {
try{
this.encoder.setValue(encoder);
} catch (ChannelException | ExecutionException e) {
throw new RuntimeException(e);
}
}
/**
* Get begin position of the scan
* @return Begin position scan
* @throws ExecutionException
* @throws ChannelException
* @throws TimeoutException
* @throws TimeoutException, ChannelException, ExecutionException
* @throws CAException
*/
public Double getBegin() throws InterruptedException, TimeoutException, ChannelException, ExecutionException {
return(this.begin.getValue());
public Double getBegin() throws InterruptedException {
try{
return(this.begin.getValue());
} catch (TimeoutException | ChannelException | ExecutionException e) {
throw new RuntimeException(e);
}
}
/**
* Set begin position of scan
* @param begin
* @throws ExecutionException
* @throws ChannelException
* @throws TimeoutException
* @throws Exception
*/
public void setBegin(Double begin) throws InterruptedException, TimeoutException, ChannelException, ExecutionException {
if(begin==null){
throw new IllegalArgumentException("Begin position must not be null");
public void setBegin(Double begin) throws InterruptedException {
try{
if(begin==null){
throw new IllegalArgumentException("Begin position must not be null");
}
if(begin < beginMin.getValue() || begin > beginMax.getValue()){
throw new IllegalArgumentException("Cannot set begin value to "+begin+ ". Value is outside range [min: "+beginMin.getValue()+" max: "+beginMax.getValue()+"]");
}
this.begin.setValue(begin);
} catch (TimeoutException | ChannelException | ExecutionException e) {
throw new RuntimeException(e);
}
if(begin < beginMin.getValue() || begin > beginMax.getValue()){
throw new IllegalArgumentException("Cannot set begin value to "+begin+ ". Value is outside range [min: "+beginMin.getValue()+" max: "+beginMax.getValue()+"]");
}
this.begin.setValue(begin);
}
/**
* Get minimum value of the begin position
* @return Min value for begin
* @throws ExecutionException
* @throws ChannelException
* @throws TimeoutException
* @throws TimeoutException, ChannelException, ExecutionException
* @throws CAException
*/
public Double getMinBegin() throws InterruptedException, TimeoutException, ChannelException, ExecutionException {
return(this.beginMin.getValue());
public Double getMinBegin() throws InterruptedException {
try{
return(this.beginMin.getValue());
} catch (TimeoutException | ChannelException | ExecutionException e) {
throw new RuntimeException(e);
}
}
/**
* Get maximum value of the begin position
* @return Max value for begin
* @throws ExecutionException
* @throws ChannelException
* @throws TimeoutException
* @throws TimeoutException, ChannelException, ExecutionException
* @throws CAException
*/
public Double getMaxBegin() throws InterruptedException, TimeoutException, ChannelException, ExecutionException {
return(this.beginMax.getValue());
public Double getMaxBegin() throws InterruptedException {
try{
return(this.beginMax.getValue());
} catch (TimeoutException | ChannelException | ExecutionException e) {
throw new RuntimeException(e);
}
}
/**
* Get end position of the scan
* @return End position scan
* @throws ExecutionException
* @throws ChannelException
* @throws TimeoutException
* @throws TimeoutException, ChannelException, ExecutionException
* @throws CAException
*/
public Double getEnd() throws InterruptedException, TimeoutException, ChannelException, ExecutionException {
return(this.end.getValue());
public Double getEnd() throws InterruptedException {
try{
return(this.end.getValue());
} catch (TimeoutException | ChannelException | ExecutionException e) {
throw new RuntimeException(e);
}
}
/**
* Set end positon of scan
* @param end
* @throws ExecutionException
* @throws ChannelException
* @throws TimeoutException
* @throws TimeoutException, ChannelException, ExecutionException
* @throws CAException
*/
public void setEnd(Double end) throws InterruptedException, TimeoutException, ChannelException, ExecutionException {
if(end==null){
throw new IllegalArgumentException("End position must not be null");
public void setEnd(Double end) throws InterruptedException {
try{
if(end==null){
throw new IllegalArgumentException("End position must not be null");
}
if(end < endMin.getValue() || end > endMax.getValue()){
throw new IllegalArgumentException("Cannot set end value to "+end+ ". Value is outside range [min: "+endMin.getValue()+" max: "+endMax.getValue()+"]");
}
this.end.setValue(end);
} catch (TimeoutException | ChannelException | ExecutionException e) {
throw new RuntimeException(e);
}
if(end < endMin.getValue() || end > endMax.getValue()){
throw new IllegalArgumentException("Cannot set end value to "+end+ ". Value is outside range [min: "+endMin.getValue()+" max: "+endMax.getValue()+"]");
}
this.end.setValue(end);
}
/**
* Get minimum value of end position
* @return Min value for end
* @throws ExecutionException
* @throws ChannelException
* @throws TimeoutException
* @throws TimeoutException, ChannelException, ExecutionException
* @throws CAException
*/
public Double getMinEnd() throws InterruptedException, TimeoutException, ChannelException, ExecutionException {
return(this.endMin.getValue());
public Double getMinEnd() throws InterruptedException {
try{
return(this.endMin.getValue());
} catch (TimeoutException | ChannelException | ExecutionException e) {
throw new RuntimeException(e);
}
}
/**
* Get maximum value of end position
* @return Max value for end
* @throws TimeoutException, ChannelException, ExecutionException
* @throws CAException
*/
public Double getMaxEnd() throws TimeoutException, ChannelException, ExecutionException, InterruptedException {
return(this.endMax.getValue());
public Double getMaxEnd() throws InterruptedException {
try{
return(this.endMax.getValue());
} catch (TimeoutException | ChannelException | ExecutionException e) {
throw new RuntimeException(e);
}
}
/**
* Get scan step size
* @return Step size
* @throws TimeoutException, ChannelException, ExecutionException
* @throws CAException
*/
public Double getStepSize() throws TimeoutException, ChannelException, ExecutionException, InterruptedException {
return(this.stepSize.getValue());
public Double getStepSize() throws InterruptedException {
try{
return(this.stepSize.getValue());
} catch (TimeoutException | ChannelException | ExecutionException e) {
throw new RuntimeException(e);
}
}
/**
* Set step size of scan
* @param stepSize
* @throws TimeoutException, ChannelException, ExecutionException
* @throws CAException
*/
public void setStepSize(Double stepSize) throws TimeoutException, ChannelException, ExecutionException, InterruptedException {
if(integrationTime==null){
throw new IllegalArgumentException("Step size must not be null");
public void setStepSize(Double stepSize) throws InterruptedException {
try{
if(integrationTime==null){
throw new IllegalArgumentException("Step size must not be null");
}
// Check if step size is greater than min step size
if(stepSizeMin.getValue() != 0 && stepSize < stepSizeMin.getValue()){
throw new IllegalArgumentException("Step size value ["+stepSize+"] is less than minimum step size ["+stepSizeMin.getValue()+"]!");
}
this.stepSize.setValue(stepSize);
// TODO WORKAROUND - Wait to "ensure" that step size related fields are updated (i.e. min/max integration time)
Thread.sleep(1);
} catch (TimeoutException | ChannelException | ExecutionException e) {
throw new RuntimeException(e);
}
// Check if step size is greater than min step size
if(stepSizeMin.getValue() != 0 && stepSize < stepSizeMin.getValue()){
throw new IllegalArgumentException("Step size value ["+stepSize+"] is less than minimum step size ["+stepSizeMin.getValue()+"]!");
}
this.stepSize.setValue(stepSize);
// TODO WORKAROUND - Wait to "ensure" that step size related fields are updated (i.e. min/max integration time)
Thread.sleep(1);
}
/**
* Get minimum integration time
* @return Min value for step size
* @throws TimeoutException, ChannelException, ExecutionException
* @throws CAException
*/
public double getMinStepSize() throws TimeoutException, ChannelException, ExecutionException, InterruptedException {
return(this.stepSizeMin.getValue());
public double getMinStepSize() throws InterruptedException {
try{
return(this.stepSizeMin.getValue());
} catch (TimeoutException | ChannelException | ExecutionException e) {
throw new RuntimeException(e);
}
}
/**
* Get scan integration time (time that is spend in one step)
* @return Integration time
* @throws TimeoutException, ChannelException, ExecutionException
* @throws CAException
*/
public Double getIntegrationTime() throws TimeoutException, ChannelException, ExecutionException, InterruptedException {
return(this.integrationTime.getValue());
public Double getIntegrationTime() throws InterruptedException {
try{
return(this.integrationTime.getValue());
} catch (TimeoutException | ChannelException | ExecutionException e) {
throw new RuntimeException(e);
}
}
/**
* Set integration time of scan
* @param integrationTime
* @throws TimeoutException, ChannelException, ExecutionException
* @throws CAException
*/
public void setIntegrationTime(Double integrationTime) throws TimeoutException, ChannelException, ExecutionException, InterruptedException {
public void setIntegrationTime(Double integrationTime) throws InterruptedException {
try{
if(integrationTime==null){
throw new IllegalArgumentException("Integration time must not be null");
}
@@ -498,108 +534,155 @@ public class OTFBean {
}
this.integrationTime.setValue(integrationTime);
} catch (TimeoutException | ChannelException | ExecutionException e) {
throw new RuntimeException(e);
}
}
/**
* Get minimum integration time
* @return Min value for integration time
* @throws TimeoutException, ChannelException, ExecutionException
* @throws CAException
*/
public Double getMinIntegrationTime() throws TimeoutException, ChannelException, ExecutionException, InterruptedException {
public Double getMinIntegrationTime() throws InterruptedException {
try{
return(this.integrationTimeMin.getValue());
} catch (TimeoutException | ChannelException | ExecutionException e) {
throw new RuntimeException(e);
}
}
/**
* Get maximum integration time
* @return Max value for integration time
* @throws TimeoutException, ChannelException, ExecutionException
* @throws CAException
*/
public Double getMaxIntegrationTime() throws TimeoutException, ChannelException, ExecutionException, InterruptedException {
public Double getMaxIntegrationTime() throws InterruptedException {
try{
return(this.integrationTimeMax.getValue());
} catch (TimeoutException | ChannelException | ExecutionException e) {
throw new RuntimeException(e);
}
}
/**
* Get additional user defined backlash
* @return User backlash
* @throws TimeoutException, ChannelException, ExecutionException
* @throws CAException
*/
public Double getUserBacklash() throws TimeoutException, ChannelException, ExecutionException, InterruptedException {
public Double getUserBacklash() throws InterruptedException {
try{
return(this.userBacklash.getValue());
} catch (TimeoutException | ChannelException | ExecutionException e) {
throw new RuntimeException(e);
}
}
/**
* Set additional user defined backlash
* @param userBacklash
* @throws TimeoutException, ChannelException, ExecutionException
* @throws CAException
*/
public void setUserBacklash(Double userBacklash) throws TimeoutException, ChannelException, ExecutionException, InterruptedException {
if(userBacklash==null){
throw new IllegalArgumentException("User backlash must not be null");
public void setUserBacklash(Double userBacklash) throws InterruptedException {
try{
if(userBacklash==null){
throw new IllegalArgumentException("User backlash must not be null");
}
this.userBacklash.setValue(userBacklash);
} catch (ChannelException | ExecutionException e) {
throw new RuntimeException(e);
}
this.userBacklash.setValue(userBacklash);
}
/**
* Get the current NFS server the data is written to
* @return Name of NFS server
* @throws TimeoutException, ChannelException, ExecutionException
* @throws CAException
*/
public String getNfsServer() throws TimeoutException, ChannelException, ExecutionException, InterruptedException {
public String getNfsServer() throws InterruptedException {
try{
return(this.nfsServer.getValue());
} catch (TimeoutException | ChannelException | ExecutionException e) {
throw new RuntimeException(e);
}
}
/**
* Set name of the NFS server the data is written to
* @param nfsServer
* @throws TimeoutException, ChannelException, ExecutionException
* @throws CAException
*/
public void setNfsServer(String nfsServer) throws TimeoutException, ChannelException, ExecutionException, InterruptedException {
public void setNfsServer(String nfsServer) throws InterruptedException {
try{
this.nfsServer.setValue(nfsServer);
} catch (ChannelException | ExecutionException e) {
throw new RuntimeException(e);
}
}
/**
* Get the NFS share the data is written to
* @return Name of NFS share
* @throws TimeoutException, ChannelException, ExecutionException
* @throws CAException
*/
public String getNfsShare() throws TimeoutException, ChannelException, ExecutionException, InterruptedException {
return(this.nfsShare.getValue());
public String getNfsShare() throws InterruptedException {
try{
return(this.nfsShare.getValue());
} catch (TimeoutException | ChannelException | ExecutionException e) {
throw new RuntimeException(e);
}
}
/**
* Set name of the NFS share the data is written to
* @param nfsShare
* @throws TimeoutException, ChannelException, ExecutionException
* @throws CAException
*/
public void setNfsShare(String nfsShare) throws TimeoutException, ChannelException, ExecutionException, InterruptedException {
this.nfsShare.setValue(nfsShare);
public void setNfsShare(String nfsShare) throws InterruptedException {
try{
this.nfsShare.setValue(nfsShare);
} catch (ChannelException | ExecutionException e) {
throw new RuntimeException(e);
}
}
/**
* Get the name of the data file
* @return Name of data file name
* @throws TimeoutException, ChannelException, ExecutionException
* @throws CAException
*/
public String getFileName() throws TimeoutException, ChannelException, ExecutionException, InterruptedException {
public String getFileName() throws InterruptedException {
try{
return(this.fileName.getValue());
} catch (TimeoutException | ChannelException | ExecutionException e) {
throw new RuntimeException(e);
}
}
/**
* Set name of the data file
* @param filename
* @throws TimeoutException, ChannelException, ExecutionException
* @throws CAException
*/
public void setFileName(String filename) throws TimeoutException, ChannelException, ExecutionException, InterruptedException {
this.fileName.setValue(filename);
public void setFileName(String filename) throws InterruptedException {
try{
this.fileName.setValue(filename);
} catch (ChannelException | ExecutionException e) {
throw new RuntimeException(e);
}
}
/**
* Get File name formate
* @return Get format for file name
* @throws TimeoutException, ChannelException, ExecutionException
* @throws CAException
*/
public String getFileNameFormat() throws TimeoutException, ChannelException, ExecutionException, InterruptedException {
return(this.fileNameFormat.getValue());
public String getFileNameFormat() throws InterruptedException {
try{
return(this.fileNameFormat.getValue());
} catch (TimeoutException | ChannelException | ExecutionException e) {
throw new RuntimeException(e);
}
}
/**
@@ -607,109 +690,157 @@ public class OTFBean {
* @param fileNameFormat
* @throws Exception
*/
public void setFileNameFormat(String fileNameFormat) throws TimeoutException, ChannelException, ExecutionException, InterruptedException {
this.fileNameFormat.setValue(fileNameFormat);
public void setFileNameFormat(String fileNameFormat) throws InterruptedException {
try{
this.fileNameFormat.setValue(fileNameFormat);
} catch (ChannelException | ExecutionException e) {
throw new RuntimeException(e);
}
}
/**
* Get value of the IOC based file name counter
* @return File counter
* @throws TimeoutException, ChannelException, ExecutionException
* @throws CAException
*/
public int getFileCounter() throws TimeoutException, ChannelException, ExecutionException, InterruptedException {
public int getFileCounter() throws InterruptedException {
try{
return(this.fileCount.getValue());
} catch (TimeoutException | ChannelException | ExecutionException e) {
throw new RuntimeException(e);
}
}
/**
* Reset the IOC based file counter
* @throws TimeoutException, ChannelException, ExecutionException
* @throws CAException
*/
public void resetFileCounter() throws TimeoutException, ChannelException, ExecutionException, InterruptedException {
public void resetFileCounter() throws InterruptedException {
try{
this.resetFileCounter.setValue(1);
} catch (ChannelException | ExecutionException e) {
throw new RuntimeException(e);
}
}
/**
* Get if append file option is activated
* @return Append file flag
* @throws TimeoutException, ChannelException, ExecutionException
* @throws CAException
*/
public boolean isAppendFile() throws TimeoutException, ChannelException, ExecutionException, InterruptedException {
public boolean isAppendFile() throws InterruptedException {
try{
return(this.appendFile.getValue());
} catch (TimeoutException | ChannelException | ExecutionException e) {
throw new RuntimeException(e);
}
}
/**
* Set whether to append the specified file if the file exists
* @param append
* @throws TimeoutException, ChannelException, ExecutionException
* @throws CAException
*/
public void setAppendFile(boolean append) throws TimeoutException, ChannelException, ExecutionException, InterruptedException {
public void setAppendFile(boolean append) throws InterruptedException {
try{
this.appendFile.setValue(append);
} catch (ChannelException | ExecutionException e) {
throw new RuntimeException(e);
}
}
/**
* Get if file name generation is on or off
* @return File name generation flag
* @throws TimeoutException, ChannelException, ExecutionException
* @throws CAException
*/
public boolean isFileNameGeneration() throws TimeoutException, ChannelException, ExecutionException, InterruptedException {
public boolean isFileNameGeneration() throws InterruptedException {
try{
return(this.fileNameGeneration.getValue());
} catch (TimeoutException | ChannelException | ExecutionException e) {
throw new RuntimeException(e);
}
}
/**
* Set Whether the file name should be generated out of the file name format and the file counter
* @param generation
* @throws TimeoutException, ChannelException, ExecutionException
* @throws CAException
*/
public void setFileNameGeneration(boolean generation) throws TimeoutException, ChannelException, ExecutionException, InterruptedException {
this.fileNameGeneration.setValue(generation);
public void setFileNameGeneration(boolean generation) throws InterruptedException {
try{
this.fileNameGeneration.setValue(generation);
} catch (ChannelException | ExecutionException e) {
throw new RuntimeException(e);
}
}
/**
* Get if ZigZag scan option is on or off
* @return ZigZag flag
* @throws TimeoutException, ChannelException, ExecutionException
* @throws CAException
*/
public boolean isZigZag() throws TimeoutException, ChannelException, ExecutionException, InterruptedException {
return(this.zigZag.getValue());
public boolean isZigZag() throws InterruptedException {
try{
return(this.zigZag.getValue());
} catch (TimeoutException | ChannelException | ExecutionException e) {
throw new RuntimeException(e);
}
}
/**
* Set ZigZag scan mode on/off
* @param zigZag ZigZag mode on = true, ZigZag mode off = false
* @throws TimeoutException, ChannelException, ExecutionException
* @throws CAException
*/
public void setZigZag(boolean zigZag) throws TimeoutException, ChannelException, ExecutionException, InterruptedException {
this.zigZag.setValue(zigZag);
public void setZigZag(boolean zigZag) throws InterruptedException {
try{
this.zigZag.setValue(zigZag);
} catch (ChannelException | ExecutionException e) {
throw new RuntimeException(e);
}
}
/**
* Get whether encoder is used
*/
public boolean isUseEncoder() throws TimeoutException, ChannelException, ExecutionException, InterruptedException {
return(this.useEncoder.getValue());
public boolean isUseEncoder() throws InterruptedException {
try{
return(this.useEncoder.getValue());
} catch (TimeoutException | ChannelException | ExecutionException e) {
throw new RuntimeException(e);
}
}
/**
* Set flag to use encoder
* @throws TimeoutException, ChannelException, ExecutionException
* @throws CAException
*/
public void setUseEncoder(boolean flag) throws TimeoutException, ChannelException, ExecutionException, InterruptedException {
public void setUseEncoder(boolean flag) throws InterruptedException {
try{
this.useEncoder.setValue(flag);
} catch (ChannelException | ExecutionException e) {
throw new RuntimeException(e);
}
}
/**
* Get the channels that are currently monitored by the OTFScan logic
* @return Names of the monitored channels
* @throws TimeoutException, ChannelException, ExecutionException
* @throws CAException
*/
public String[] getMonitoredChannels() throws TimeoutException, ChannelException, ExecutionException, InterruptedException {
String[] values = new String[this.monitoredChannels.size()];
for(int i=0; i<this.monitoredChannels.size();i++){
values[i] = monitoredChannels.get(i).getValue();
public String[] getMonitoredChannels() throws InterruptedException {
try{
String[] values = new String[this.monitoredChannels.size()];
for(int i=0; i<this.monitoredChannels.size();i++){
values[i] = monitoredChannels.get(i).getValue();
}
return(values);
} catch (TimeoutException | ChannelException | ExecutionException e) {
throw new RuntimeException(e);
}
return(values);
}
/**
@@ -717,85 +848,117 @@ public class OTFBean {
* Note: As OTF only supports 8 channels to be monitored, only the first 8
* values of the passed channelNames are considered.
* @param values Array of channel names to be monitored
* @throws TimeoutException, ChannelException, ExecutionException
* @throws CAException
*/
public void setMonitoredChannels(String[] values) throws TimeoutException, ChannelException, ExecutionException, InterruptedException {
public void setMonitoredChannels(String[] values) throws InterruptedException {
if(values.length>monitoredChannels.size()){
throw new IllegalArgumentException("Only up to "+monitoredChannels.size()+" monitored channels are supported by OTF");
}
for(int i=0; i<this.monitoredChannels.size(); i++){
if(values != null && i<values.length){
this.monitoredChannels.get(i).setValue(values[i]);
try{
if(values.length>monitoredChannels.size()){
throw new IllegalArgumentException("Only up to "+monitoredChannels.size()+" monitored channels are supported by OTF");
}
else{
this.monitoredChannels.get(i).setValue("");
for(int i=0; i<this.monitoredChannels.size(); i++){
if(values != null && i<values.length){
this.monitoredChannels.get(i).setValue(values[i]);
}
else{
this.monitoredChannels.get(i).setValue("");
}
}
} catch (ChannelException | ExecutionException e) {
throw new RuntimeException(e);
}
}
/**
* Returns whether an scan is running
* @return Running flag
* @throws TimeoutException, ChannelException, ExecutionException
* @throws CAException
*/
public boolean isRunning() throws TimeoutException, ChannelException, ExecutionException, InterruptedException {
return(running.getValue());
public boolean isRunning() throws InterruptedException {
try{
return(running.getValue());
} catch (TimeoutException | ChannelException | ExecutionException e) {
throw new RuntimeException(e);
}
}
/**
* Get status of the scan
* @return Status of the scan
* @throws TimeoutException, ChannelException, ExecutionException
* @throws CAException
*/
public Status getStatus() throws TimeoutException, ChannelException, ExecutionException, InterruptedException {
return(Status.values()[this.status.getValue()]);
public Status getStatus() throws InterruptedException {
try{
return(Status.values()[this.status.getValue()]);
} catch (TimeoutException | ChannelException | ExecutionException e) {
throw new RuntimeException(e);
}
}
/**
* Get the (error) message from the OTF records
* @return Message from OTF C logic
* @throws TimeoutException, ChannelException, ExecutionException
* @throws CAException
*/
public String getMessage() throws TimeoutException, ChannelException, ExecutionException, InterruptedException {
return(message.getValue());
public String getMessage() throws InterruptedException {
try{
return(message.getValue());
} catch (TimeoutException | ChannelException | ExecutionException e) {
throw new RuntimeException(e);
}
}
/**
* Check whether the specified motor is recognized as ok (i.e. it is registered as OTFScan motor)
* @return Flag whether motor is ok
* @throws TimeoutException, ChannelException, ExecutionException
* @throws CAException
*/
public boolean isMotorOk() throws TimeoutException, ChannelException, ExecutionException, InterruptedException {
return(motorOk.getValue());
public boolean isMotorOk() throws InterruptedException {
try{
return(motorOk.getValue());
} catch (TimeoutException | ChannelException | ExecutionException e) {
throw new RuntimeException(e);
}
}
/**
* Wait until the motor flag goes to ok
* @param timeout Timout in milliseconds
*
* @throws TimeoutException, ChannelException, ExecutionException If motor ok flag does not switch to ok within the specified timeout
* @throws CAException If motor ok flag does not switch to ok within the specified timeout
*/
public void waitUntilMotorOk(long timeout) throws TimeoutException, ChannelException, ExecutionException, InterruptedException {
public void waitUntilMotorOk(long timeout) throws InterruptedException {
try{
motorOk.waitForValue(true, timeout);
} catch (TimeoutException | ChannelException | ExecutionException e) {
throw new RuntimeException(e);
}
}
/**
* Wait until the motor flag goes to not ok
* @param timeout Timout in milliseconds
*
* @throws TimeoutException, ChannelException, ExecutionException If motor ok flag does not switch to ok within the specified timeout
* @throws CAException If motor ok flag does not switch to ok within the specified timeout
*/
public void waitUntilMotorNotOk(long timeout) throws TimeoutException, ChannelException, ExecutionException, InterruptedException {
public void waitUntilMotorNotOk(long timeout) throws InterruptedException {
try{
motorOk.waitForValue(false, timeout);
} catch (TimeoutException | ChannelException | ExecutionException e) {
throw new RuntimeException(e);
}
}
public void waitUntilEncoderOk(long timeout) throws TimeoutException, ChannelException, ExecutionException, InterruptedException {
public void waitUntilEncoderOk(long timeout) throws InterruptedException {
try{
if(!useEncoder.getValue()){
return;
}
encoderOk.waitForValue(true, timeout);
} catch (TimeoutException | ChannelException | ExecutionException e) {
throw new RuntimeException(e);
}
}
}

View File

@@ -19,8 +19,10 @@
package ch.psi.fda.core.manipulator;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.TimeoutException;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
@@ -30,25 +32,16 @@ import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import ch.psi.fda.core.Manipulation;
import ch.psi.fda.core.messages.DataMessage;
import ch.psi.fda.core.messages.DataMessageMetadata;
import ch.psi.fda.core.messages.Metadata;
import ch.psi.fda.core.scripting.JythonParameterMapping;
import ch.psi.fda.core.scripting.JythonParameterMappingChannel;
import ch.psi.fda.core.scripting.JythonParameterMappingGlobalVariable;
import ch.psi.fda.core.scripting.JythonParameterMappingID;
import ch.psi.jcae.Channel;
import ch.psi.jcae.ChannelDescriptor;
import ch.psi.jcae.ChannelException;
import ch.psi.jcae.ChannelService;
/**
* Manipulation
* @author ebner
*/
public class JythonManipulation implements Manipulation{
// Get Logger
private static Logger logger = Logger.getLogger(JythonManipulation.class.getName());
/**
@@ -92,20 +85,24 @@ public class JythonManipulation implements Manipulation{
* Component index of the script parameter. The sequence of the indexes in this array correspond to the script
* parameter position, i.e. the first index corresponds to the first parameter.
*/
private Integer[] parameterIndex;
// private Integer[] parameterIndex;
private List<String> parameterIds = new ArrayList<>();
/**
* Parameter array of the entry function
*/
private String[] parameter;
private ChannelService cservice;
/**
* Jython entry call
*/
private String jythonCall;
public JythonManipulation(ChannelService s, String id, String script, List<JythonParameterMapping> mapping){
this(s, id, script, mapping, false);
private Map<String,Object> gvariables = new HashMap<String,Object>();
public JythonManipulation(String id, String script, List<JythonParameterMapping> mapping){
this(id, script, mapping, false);
}
/**
@@ -114,12 +111,11 @@ public class JythonManipulation implements Manipulation{
* @param script
* @param mapping
*/
public JythonManipulation(ChannelService s, String id, String script, List<JythonParameterMapping> mapping, boolean returnArray){
public JythonManipulation(String id, String script, List<JythonParameterMapping> mapping, boolean returnArray){
this.id = id;
this.script = script;
this.mapping = mapping;
this.returnArray = returnArray;
this.cservice = s;
}
/**
@@ -144,7 +140,7 @@ public class JythonManipulation implements Manipulation{
@Override
public void initialize(DataMessageMetadata metadata){
public void initialize(List<Metadata> metadata){
// Workaround for Jython memory leak
// http://blog.hillbrecht.de/2009/07/11/jython-memory-leakout-of-memory-problem/
@@ -178,7 +174,8 @@ public class JythonManipulation implements Manipulation{
// Determine component index of the needed parameters
// If the component index of the parameter cannot be determined an IllegalArgumentException is thrown
parameterIndex = new Integer[parameter.length];
// parameterIndex = new Integer[parameter.length];
parameterIds = new ArrayList<>();
for(int i=0;i<parameter.length; i++){
String p = parameter[i];
p = p.trim();
@@ -189,26 +186,19 @@ public class JythonManipulation implements Manipulation{
if(jpm instanceof JythonParameterMappingID){
JythonParameterMappingID pm = (JythonParameterMappingID)jpm;
// Mapping for parameter found, determine index of the corresponding component
parameterIndex[i] = metadata.getIndex(pm.getRefid());
// parameterIndex[i] = metadata.getIndex(pm.getRefid());
parameterIds.add(pm.getRefid());
}
else if (jpm instanceof JythonParameterMappingChannel){
JythonParameterMappingChannel pm = (JythonParameterMappingChannel)jpm;
parameterIndex[i] = null;
Channel<?> cb;
try {
cb = cservice.createChannel(new ChannelDescriptor<>(pm.getType(), pm.getChannel(), true));
} catch (ChannelException | TimeoutException e) {
throw new IllegalArgumentException("Unable to establish channel: "+pm.getChannel(), e);
} catch (InterruptedException e) {
throw new RuntimeException("Unable to establish channel: "+pm.getChannel(), e);
}
engine.put(pm.getVariable(), cb);
JythonParameterMappingChannel<?> pm = (JythonParameterMappingChannel<?>) jpm;
// parameterIndex[i] = null;
parameterIds.add(null);
engine.put(pm.getVariable(), pm.getChannel());
}
else if (jpm instanceof JythonParameterMappingGlobalVariable){
JythonParameterMappingGlobalVariable pm = (JythonParameterMappingGlobalVariable)jpm;
parameterIndex[i] = null;
parameterIds.add(null);
// parameterIndex[i] = null;
engine.put(pm.getVariable(), pm.getGlobalVariable());
}
@@ -235,16 +225,23 @@ public class JythonManipulation implements Manipulation{
buffer.setCharAt(buffer.length()-1, ')');
jythonCall = buffer.toString();
}
@Override
public Object execute(DataMessage message){
// Set global variables - WORKAROUND gvariables
// This block is not in initialization as we want to assure that all invocations
// of this manipulation will get the same value (i.e. to prevent inconsistent behaviour
// if variable was changed during an execution of the manipulation)
for(String k: gvariables.keySet()){
engine.put(k, gvariables.get(k));
}
// Manipulate data
for(int i=0;i<parameterIndex.length;i++){
if(parameterIndex[i] != null){
engine.put(parameter[i], message.getData().get(parameterIndex[i]));
for(int i=0;i<parameterIds.size();i++){
if(parameterIds.get(i) != null){
engine.put(parameter[i], message.getData(parameterIds.get(i)));
}
}
@@ -264,7 +261,8 @@ public class JythonManipulation implements Manipulation{
return(((Integer)r).doubleValue());
}
else{
return Double.NaN;
// return Double.NaN;
return r;
}
}
} catch (ScriptException e) {
@@ -273,4 +271,13 @@ public class JythonManipulation implements Manipulation{
return Double.NaN;
}
}
/**
* Workaround to put variables into the jython engine.
* @param name
* @param value
*/
public void setVariable(String name, Object value){
gvariables.put(name, value);
}
}

View File

@@ -1,123 +0,0 @@
/**
*
* Copyright 2010 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 <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.manipulator;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import ch.psi.fda.core.messages.ComponentMetadata;
import ch.psi.fda.core.messages.DataMessage;
import ch.psi.fda.core.messages.DataMessageMetadata;
import ch.psi.fda.core.messages.DataQueue;
import ch.psi.fda.core.messages.EndOfStreamMessage;
import ch.psi.fda.core.messages.Message;
/**
* @author ebner
*
*/
public class Manipulator implements Runnable{
/**
* Outgoing data queue
*/
private final DataQueue outQueue;
/**
* Incomming data queue
*/
private final DataQueue queue;
/**
* List of manipulations
*/
private final List<Manipulation> manipulations;
/**
* Constructor
* @param queue
* @param manipulations
*/
// TODO need to support multiple (a list of) manipulation(s)
public Manipulator(DataQueue queue, List<Manipulation> manipulations){
this.manipulations = manipulations;
// Create outgoing data metadata
DataMessageMetadata dmetadata = queue.getDataMessageMetadata().clone();
// Initialize manipulations and create outgoing metadata
for(Manipulation manipulation: this.manipulations){
// Initialize manipulation
// manipulation.initialize(queue.getDataMessageMetadata());
manipulation.initialize(dmetadata);
// Add manipulation id to metadata
dmetadata.getComponents().add(new ComponentMetadata(manipulation.getId(),0)); // Calculated component always belongs to lowes dimension
}
this.queue = queue;
this.outQueue = new DataQueue(new LinkedBlockingQueue<Message>(1000) , dmetadata ); // Create bounded queue to prevent running out of memory ...
}
/**
* @return the outQueue
*/
public DataQueue getOutQueue() {
return outQueue;
}
/* (non-Javadoc)
* @see java.lang.Runnable#run()
*/
@Override
public void run() {
try{
// Dispatch Messages
Message message = queue.getQueue().take();
while(!(message instanceof EndOfStreamMessage)){
if(message instanceof DataMessage){
DataMessage dm = (DataMessage) message;
for(Manipulation manipulation: manipulations){
dm.getData().add(manipulation.execute(dm));
}
}
// Put message to outgoing queue ...
outQueue.getQueue().put(message);
// Read next message
message = queue.getQueue().take();
}
// Write end of stream message
outQueue.getQueue().put(message);
} catch (InterruptedException e) {
// TODO Stop loop and exit logic instead of throwing an Exception
throw new RuntimeException("Data manipulator was interrupted while writing data to file",e);
}
}
}

View File

@@ -19,11 +19,11 @@
package ch.psi.fda.core.messages;
/**
* A control message that is not holding any data but
* control information (like end of loop, etc.)
* @author ebner
*
*/
public abstract class ControlMessage extends Message {
public abstract class ControlMessage extends Message{
private static final long serialVersionUID = 1L;
}

View File

@@ -24,35 +24,57 @@ import java.util.List;
/**
* Message holding data
* @author ebner
*
*/
public class DataMessage extends Message {
public class DataMessage extends Message{
/**
* Data payload of the message
*/
private List<Object> data;
private static final long serialVersionUID = 1L;
/**
* Constructor - Create message object with data payload
*/
public DataMessage(){
private final List<Object> data;
private List<Metadata> metadata;
// public DataMessage(){
// this.data = new ArrayList<Object>();
// this.metadata = new ArrayList<>();
// }
//
public DataMessage(List<Metadata> metadata){
this.data = new ArrayList<Object>();
this.metadata = metadata;
}
/**
* Get data object of the message
* @return Data object of the message
*/
public List<Object> getData(){
return(data);
}
public List<Metadata> getMetadata(){
return metadata;
}
public void setMetadata(List<Metadata> metadata){
this.metadata = metadata;
}
// Utility functions
@SuppressWarnings("unchecked")
public <T> T getData(String id){
int i=0;
for(Metadata m: metadata){
if(m.getId().equals(id)){
return (T) data.get(i);
}
i++;
}
throw new IllegalArgumentException("No data found for id: "+id);
}
public Metadata getMetadata(String id){
for(Metadata m: metadata){
if(m.getId().equals(id)){
return m;
}
}
throw new IllegalArgumentException("No data found for id: "+id);
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
StringBuffer b = new StringBuffer();

View File

@@ -1,81 +0,0 @@
/**
*
* Copyright 2010 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 <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.messages;
import java.util.ArrayList;
import java.util.List;
/**
* Structure to hold the metadata of a component of a message.
* @author ebner
*
*/
public class DataMessageMetadata {
/**
* List of the metadata of the message components
*/
private List<ComponentMetadata> components;
/**
* Default constructor
*/
public DataMessageMetadata(){
components = new ArrayList<ComponentMetadata>();
}
/**
* @return the list of component metadata of a message described by this object.
*/
public List<ComponentMetadata> getComponents() {
return components;
}
/**
* Get the index of the component with the specified Id
* @param componentId Id of the component to look for
* @return Index of the component
* @throws IllegalArgumentException There is no component with the specified Id
*/
public int getIndex(String componentId) throws IllegalArgumentException {
for(int i=0;i<components.size();i++){
ComponentMetadata c =components.get(i);
if(c.getId().equals(componentId)){
return(i);
}
}
throw new IllegalArgumentException("There is no message component with Id "+ componentId);
}
/**
* Clone data structure
* @return Cloned data structure
*/
public DataMessageMetadata clone(){
DataMessageMetadata metadata = new DataMessageMetadata();
for(int i=0;i<components.size();i++){
ComponentMetadata c =components.get(i);
metadata.getComponents().add(new ComponentMetadata(c.getId(), c.getDimension()));
}
return(metadata);
}
}

View File

@@ -1,66 +0,0 @@
/**
*
* Copyright 2010 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 <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.messages;
import java.util.concurrent.BlockingQueue;
/**
* Container holding for holding a queue and the metadata of the
* data messages of that queue.
* @author ebner
*
*/
public class DataQueue {
/**
* Queue serving the messages
*/
private final BlockingQueue<Message> queue;
/**
* Metadata of the data messages of the queue
*/
private final DataMessageMetadata dataMessageMetadata;
/**
* Constructor
* @param queue Data queue
* @param dataMessageMetadata Metadata of the data messages of the queue
*/
public DataQueue(BlockingQueue<Message> queue, DataMessageMetadata dataMessageMetadata){
this.queue = queue;
this.dataMessageMetadata = dataMessageMetadata;
}
/**
* @return the queue
*/
public BlockingQueue<Message> getQueue() {
return queue;
}
/**
* @return the metadata
*/
public DataMessageMetadata getDataMessageMetadata() {
return dataMessageMetadata;
}
}

View File

@@ -22,11 +22,10 @@ package ch.psi.fda.core.messages;
/**
* Message that is send at the end of the action loop inside an ActionLoop implementation
* of just to indicate that a particular stream has finished
* @author ebner
*
*/
public class EndOfStreamMessage extends ControlMessage{
public class EndOfStreamMessage extends ControlMessage {
private static final long serialVersionUID = 1L;
/**
* Intersect flag - flag to indicate that stream should be intersected
@@ -42,16 +41,10 @@ public class EndOfStreamMessage extends ControlMessage{
this.iflag = iflag;
}
/**
* @return the iflag
*/
public boolean isIflag(){
return(iflag);
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "Message[ c message: end of stream ]";

View File

@@ -19,10 +19,11 @@
package ch.psi.fda.core.messages;
import java.io.Serializable;
/**
* Message that can be put to the data queue
* @author ebner
*
*/
public abstract class Message {
public abstract class Message implements Serializable{
private static final long serialVersionUID = 1L;
}

View File

@@ -19,64 +19,40 @@
package ch.psi.fda.core.messages;
import java.io.Serializable;
/**
* Metadata of a component of a message. Each component has a global id.
* Optionally the component can also belong to a dimension. However, depending on the
* view the number of the dimension might vary. Therefore the dimension number
* might change during the lifetime of a message (component).
*
* @author ebner
*
*/
public class ComponentMetadata {
/**
* Global id of the component
*/
public class Metadata implements Serializable{
private static final long serialVersionUID = 1L;
private final String id;
private int dimension;
/**
* Dimension of the component (optional)
*/
private final int dimension;
/**
* Default constructor - Create component metadata
* @param id Global id of the component
*/
public ComponentMetadata(String id){
public Metadata(String id){
this.id = id;
this.dimension = 0;
}
/**
* Constructor that initializes id and the dimension number
* @param id
* @param dimension
*/
public ComponentMetadata(String id, int dimension){
public Metadata(String id, int dimension){
this.id = id;
this.dimension = dimension;
}
/**
* @return the dimension
*/
public void setDimension(int dimension){
this.dimension = dimension;
}
public int getDimension() {
return dimension;
}
/**
* @return the id
*/
public String getId() {
return id;
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "Component Metadata[id="+id+" dimension="+dimension+"]";
}
}

View File

@@ -21,11 +21,9 @@ package ch.psi.fda.core.messages;
/**
* Message that is send at the end of the action loop inside an ActionLoop implementation
* @author ebner
*
*/
public class StreamDelimiterMessage extends ControlMessage{
private static final long serialVersionUID = 1L;
/**
* Number of the dimension this delimiter belongs to.
*/
@@ -38,7 +36,6 @@ public class StreamDelimiterMessage extends ControlMessage{
private final boolean iflag;
/**
* Constructor
* @param number Number of the dimension this delimiter belongs to
*/
public StreamDelimiterMessage(int number){
@@ -46,7 +43,6 @@ public class StreamDelimiterMessage extends ControlMessage{
}
/**
* Constructor
* @param number
* @param iflag Flag to indicate that data is grouped
*/
@@ -55,23 +51,14 @@ public class StreamDelimiterMessage extends ControlMessage{
this.iflag = iflag;
}
/**
* @return the number
*/
public int getNumber() {
return number;
}
/**
* @return the iflag
*/
public boolean isIflag(){
return iflag;
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
// TODO Auto-generated method stub

View File

@@ -1,75 +0,0 @@
/**
*
* Copyright 2010 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 <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.scripting;
import java.util.HashMap;
/**
* Singleton dictionary class
*
* @author ebner
*
*/
public class JythonGlobalVariableDictionary {
private static JythonGlobalVariableDictionary instance = new JythonGlobalVariableDictionary();
private HashMap<String, JythonGlobalVariable> dictionary = new HashMap<String, JythonGlobalVariable>();
/**
* Private constructor
*/
private JythonGlobalVariableDictionary(){
}
/**
* Get singleton instance of the dictionary
* @return
*/
public static JythonGlobalVariableDictionary getInstance(){
return instance;
}
/**
* Get variable from dictionary. If the variable does not exist it will be created.
* @param name
* @return
*/
public JythonGlobalVariable getVariable(String name){
JythonGlobalVariable variable;
if(dictionary.containsKey(name)){
variable = dictionary.get(name);
}
else{
variable = new JythonGlobalVariable();
variable.setName(name);
dictionary.put(name, variable);
}
return variable;
}
/**
* Clear variable dictionary
*/
public void clear(){
dictionary.clear();
}
}

View File

@@ -19,57 +19,24 @@
package ch.psi.fda.core.scripting;
import ch.psi.jcae.Channel;
/**
* Mapping of a script parameter to a channel bean.
* @author ebner
*
*/
public class JythonParameterMappingChannel extends JythonParameterMapping {
public class JythonParameterMappingChannel<T> extends JythonParameterMapping {
/**
* Id of the component to map to this variable
*/
private String channel;
private Class<?> type;
private Channel<T> channel;
/**
* Constructor accepting varible/id pair
* @param variable
* @param channel
* @param type
*/
public JythonParameterMappingChannel(String variable, String channel, Class<?> type){
public JythonParameterMappingChannel(String variable, Channel<T> channel){
super(variable);
this.channel = channel;
this.type = type;
}
/**
* @return the channel
*/
public String getChannel() {
public Channel<T> getChannel() {
return channel;
}
/**
* @param channel
*/
public void setChannel(String channel) {
this.channel = channel;
}
/**
* @return the type
*/
public Class<?> getType() {
return type;
}
/**
* @param type the type to set
*/
public void setType(Class<?> type) {
this.type = type;
}
}

View File

@@ -1,148 +0,0 @@
/**
*
* Copyright 2010 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 <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.sensors;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import java.util.logging.Logger;
import ch.psi.fda.core.EngineConfiguration;
import ch.psi.fda.core.Sensor;
import ch.psi.jcae.Channel;
import ch.psi.jcae.ChannelDescriptor;
import ch.psi.jcae.ChannelException;
import ch.psi.jcae.ChannelService;
/**
* Scalar sensor that reads a double form a Channel Access channel
* @author ebner
*
*/
public class ChannelAccessDoubleArraySensor implements Sensor {
// Get Logger
private static Logger logger = Logger.getLogger(ChannelAccessDoubleArraySensor.class.getName());
/**
* Channel Access channel of this sensor
*/
private final Channel<double[]> channel;
/**
* Number of elements to read from the waveform
*/
private final int numberOfElements;
/**
* Global id of the sensor
*/
private final String id;
/**
* Constructor
* @param id Global id of the sensor
* @param channelName Name of the Channel Access channel of this sensor
* @param numberOfElements Number of elements to read out of the waveform
*/
public ChannelAccessDoubleArraySensor(ChannelService s, String id, String channelName, int numberOfElements){
try {
this.channel = s.createChannel(new ChannelDescriptor<>(double[].class, channelName, false, numberOfElements));
this.numberOfElements = numberOfElements;
this.id = id;
} catch (ChannelException | TimeoutException e) {
// Convert Exception into unchecked RuntimeException
throw new IllegalArgumentException("Unable to initialize sensor channel [name:"+channelName+"]",e);
} catch (InterruptedException e) {
throw new RuntimeException("Unable to initialize sensor channel [name:"+channelName+"]",e);
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Sensor#readout()
*/
@Override
public Object read() throws InterruptedException {
logger.finest("Read sensor "+channel.getName());
double[] v;
try {
// v = channel.getValue(numberOfElements);
v = channel.getValue();
} catch (IllegalStateException e) {
// Only fail during data acquisition if fail on error sensor flag is on true. Otherwise
// return NaN (Not a Number)
if(EngineConfiguration.getInstance().isFailOnSensorError()){
throw e;
}
v = new double[numberOfElements];
for(int i =0;i<v.length;i++){
v[i] = Double.NaN;
}
} catch (ChannelException | TimeoutException | ExecutionException e) {
// Only fail during data acquisition if fail on error sensor flag is on true. Otherwise
// return NaN (Not a Number)
if(EngineConfiguration.getInstance().isFailOnSensorError()){
// Convert Exception into unchecked RuntimeException
throw new RuntimeException("Unable to get value from channel [name:"+channel.getName()+"]",e);
}
v = new double[numberOfElements];
for(int i =0;i<v.length;i++){
v[i] = Double.NaN;
}
// } catch (InterruptedException e) {
// // Only fail during data acquisition if fail on error sensor flag is on true. Otherwise
// // return NaN (Not a Number)
// if(EngineConfiguration.getInstance().isFailOnSensorError()){
// throw new RuntimeException("Unable to get value from channel [name:"+channel.getName()+"]",e);
// }
//
// v = new double[numberOfElements];
// for(int i =0;i<v.length;i++){
// v[i] = Double.NaN;
// }
}
return(v);
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Sensor#getId()
*/
@Override
public String getId() {
return id;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Sensor#destroy()
*/
@Override
public void destroy() {
// Destroy channel
try {
logger.finest("Destroy sensor channel: "+channel.getName());
channel.destroy();
} catch (ChannelException e) {
throw new RuntimeException("Unable to destroy channel ["+channel.getName()+"]",e);
}
}
}

View File

@@ -1,135 +0,0 @@
/**
*
* Copyright 2010 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 <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.sensors;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import java.util.logging.Logger;
import ch.psi.fda.core.EngineConfiguration;
import ch.psi.fda.core.Sensor;
import ch.psi.jcae.Channel;
import ch.psi.jcae.ChannelDescriptor;
import ch.psi.jcae.ChannelException;
import ch.psi.jcae.ChannelService;
/**
* Scalar sensor that reads a double form a Channel Access channel
* @author ebner
*
*/
public class ChannelAccessDoubleSensor implements Sensor {
// Get Logger
private static Logger logger = Logger.getLogger(ChannelAccessDoubleSensor.class.getName());
/**
* Channel Access channel of this sensor
*/
private Channel<Double> channel;
/**
* Global id of the sensor
*/
private final String id;
/**
* Constructor
* @param id Global id of the sensor
* @param channelName Name of the Channel Access channel of this sensor
*/
public ChannelAccessDoubleSensor(ChannelService s, String id, String channelName){
try {
channel = s.createChannel(new ChannelDescriptor<>(Double.class, channelName, false));
this.id = id;
} catch (ChannelException | TimeoutException e) {
// Convert Exception into unchecked RuntimeException
throw new IllegalArgumentException("Unable to initialize sensor channel [name:"+channelName+"]",e);
} catch (InterruptedException e) {
throw new RuntimeException("Unable to initialize sensor channel [name:"+channelName+"]",e);
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Sensor#readout()
*/
@Override
public Object read() throws InterruptedException {
logger.finest("Read sensor "+channel.getName());
Double v;
try {
v = channel.getValue();
} catch (IllegalStateException e) {
// Only fail during data acquisition if fail on error sensor flag is on true. Otherwise
// return NaN (Not a Number)
if(EngineConfiguration.getInstance().isFailOnSensorError()){
throw e;
}
v = Double.NaN;
} catch (ChannelException | TimeoutException | ExecutionException e) {
// Only fail during data acquisition if fail on error sensor flag is on true. Otherwise
// return NaN (Not a Number)
if(EngineConfiguration.getInstance().isFailOnSensorError()){
// Convert Exception into unchecked RuntimeException
throw new RuntimeException("Unable to get value from channel [name:"+channel.getName()+"]",e);
}
v = Double.NaN;
// } catch (InterruptedException e) {
// if(EngineConfiguration.getInstance().isFailOnSensorError()){
// throw new RuntimeException("Unable to get value from channel [name:"+channel.getName()+"]",e);
// }
// v = Double.NaN;
}
return(v);
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Sensor#getId()
*/
@Override
public String getId() {
return id;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Sensor#destroy()
*/
@Override
public void destroy() {
// Destroy channel
try {
logger.finest("Destroy sensor channel: "+channel.getName());
channel.destroy();
} catch (ChannelException e) {
throw new RuntimeException("Unable to destroy channel ["+channel.getName()+"]",e);
}
}
/**
* Get channel object of sensor
* @return
*/
public Channel<Double> getChannel(){
return channel;
}
}

View File

@@ -0,0 +1,72 @@
/**
*
* Copyright 2010 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 <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.sensors;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import java.util.logging.Logger;
import ch.psi.fda.core.Sensor;
import ch.psi.jcae.Channel;
import ch.psi.jcae.ChannelException;
/**
* Channel Access sensor capable of reading a channel access channel
*/
public class ChannelAccessSensor<T> implements Sensor {
private static Logger logger = Logger.getLogger(ChannelAccessSensor.class.getName());
private Channel<T> channel;
private final String id;
private boolean failOnSensorError = true;
public ChannelAccessSensor(String id, Channel<T> channel){
this.id = id;
this.channel = channel;
}
public ChannelAccessSensor(String id, Channel<T> channel, boolean failOnSensorError){
this.id = id;
this.channel = channel;
this.failOnSensorError = failOnSensorError;
}
@Override
public Object read() throws InterruptedException {
logger.finest("Read sensor "+channel.getName());
T v;
try {
v = channel.getValue();
} catch (TimeoutException | ChannelException | ExecutionException e) {
if(failOnSensorError){
throw new RuntimeException("Unable to get value from channel [name:"+channel.getName()+"]",e);
}
v = null;
}
return(v);
}
@Override
public String getId() {
return id;
}
}

View File

@@ -1,129 +0,0 @@
/**
*
* Copyright 2010 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 <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.sensors;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import java.util.logging.Logger;
import ch.psi.fda.core.EngineConfiguration;
import ch.psi.fda.core.Sensor;
import ch.psi.jcae.Channel;
import ch.psi.jcae.ChannelDescriptor;
import ch.psi.jcae.ChannelException;
import ch.psi.jcae.ChannelService;
/**
* Scalar sensor that reads a double form a Channel Access channel
* @author ebner
*
*/
public class ChannelAccessStringSensor implements Sensor {
// Get Logger
private static Logger logger = Logger.getLogger(ChannelAccessStringSensor.class.getName());
/**
* Channel Access channel of this sensor
*/
private Channel<String> channel;
/**
* Global id of the sensor
*/
private final String id;
/**
* Constructor
* @param id Global id of the sensor
* @param channelName Name of the Channel Access channel of this sensor
*/
public ChannelAccessStringSensor(ChannelService s, String id, String channelName){
try {
channel = s.createChannel(new ChannelDescriptor<String>(String.class, channelName, false));
this.id = id;
} catch (InterruptedException e) {
throw new RuntimeException("Unable to initialize sensor channel [name:"+channelName+"]",e);
} catch (ChannelException e) {
throw new IllegalArgumentException("Unable to initialize sensor channel [name:"+channelName+"]",e);
} catch (TimeoutException e) {
throw new IllegalArgumentException("Unable to initialize sensor channel [name:"+channelName+"]",e);
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Sensor#readout()
*/
@Override
public Object read() throws InterruptedException {
logger.finest("Read sensor "+channel.getName());
String v;
try {
v = channel.getValue();
} catch (IllegalStateException e) {
// Only fail during data acquisition if fail on error sensor flag is on true. Otherwise
// return NaN (Not a Number)
if(EngineConfiguration.getInstance().isFailOnSensorError()){
throw e;
}
v = null;
} catch (TimeoutException | ExecutionException |ChannelException e) {
// Only fail during data acquisition if fail on error sensor flag is on true. Otherwise
// return NaN (Not a Number)
if(EngineConfiguration.getInstance().isFailOnSensorError()){
// Convert Exception into unchecked RuntimeException
throw new RuntimeException("Unable to get value from channel [name:"+channel.getName()+"]",e);
}
v = null;
// } catch (InterruptedException e) {
// if(EngineConfiguration.getInstance().isFailOnSensorError()){
// throw new RuntimeException("Unable to get value from channel [name:"+channel.getName()+"]",e);
// }
// v = null;
}
return(v);
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Sensor#getId()
*/
@Override
public String getId() {
return id;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Sensor#destroy()
*/
@Override
public void destroy() {
// Destroy channel
try {
logger.finest("Destroy sensor channel: "+channel.getName());
channel.destroy();
} catch (ChannelException e) {
throw new RuntimeException("Unable to destroy channel ["+channel.getName()+"]",e);
}
}
}

View File

@@ -1,90 +1,39 @@
/**
*
* Copyright 2010 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 <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.sensors;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
import ch.psi.fda.core.Action;
import ch.psi.fda.core.Sensor;
/**
* Complex sensor that complements an other sensor with pre and post actions.
* Before reading out the complemented sensor the pre actions are executed. After the
* readout the post actions.
*
* @author ebner
*
*/
public class ComplexSensor implements Sensor {
// Get Logger
private static Logger logger = Logger.getLogger(ComplexSensor.class.getName());
/**
* Id of the sensor
*/
private String id;
/**
* Sensor to complement
*/
private final Sensor sensor;
/**
* Actions that are executed directly before the first step of this actor
*/
private final List<Action> preActions;
/**
* Actions that are executed directly after the last step of this actor
*/
private final List<Action> postActions;
/**
* Constructor
*/
public ComplexSensor(String id, Sensor sensor){
this.id = id;
this.sensor = sensor;
this.preActions = new ArrayList<Action>();
this.postActions = new ArrayList<Action>();
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Sensor#read()
*/
@Override
public Object read() throws InterruptedException {
// Execute pre actions
logger.finest("Execute pre actions");
for(Action action: preActions){
action.execute();
}
// Readout sensor
Object value = sensor.read();
// Execute post actions
logger.finest("Execute post actions");
for(Action action: postActions){
action.execute();
@@ -93,44 +42,15 @@ public class ComplexSensor implements Sensor {
return value;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Sensor#getId()
*/
@Override
public String getId() {
return id;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Sensor#destroy()
*/
@Override
public void destroy() {
// Destroy preActions
for(Action a: preActions){
a.destroy();
}
sensor.destroy();
// Destroy postActions
for(Action a: postActions){
a.destroy();
}
}
/**
* @return the preActions
*/
public List<Action> getPreActions() {
return preActions;
}
/**
* @return the postActions
*/
public List<Action> getPostActions() {
return postActions;
}
}
}

View File

@@ -1,70 +0,0 @@
/**
*
* Copyright 2010 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 <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.sensors;
import ch.psi.fda.core.Sensor;
/**
* Sensor to read actuator readback. This sensor must only be used within the
* OTFLoop. If it is used in other loops, the read value will always be 0.
* @author ebner
*
*/
public class OTFReadbackSensor implements Sensor {
/**
* Global id of the sensor
*/
private final String id;
/**
* Constructor
* @param id Global id of the sensor
*/
public OTFReadbackSensor(String id){
this.id = id;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Sensor#read()
*/
@Override
public Object read() {
// Always return 0 if read() method is called.
return 0d;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Sensor#getId()
*/
@Override
public String getId() {
return id;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Sensor#destroy()
*/
@Override
public void destroy() {
// Nothing to be done
}
}

View File

@@ -22,48 +22,25 @@ package ch.psi.fda.core.sensors;
import ch.psi.fda.core.Sensor;
/**
* Get the current time in milliseconds
* @author ebner
*
* Sensor to read the current time in milliseconds
*/
public class MillisecondTimestampSensor implements Sensor {
public class TimestampSensor implements Sensor {
/**
* Global id of the sensor
*/
private final String id;
private final String id; // Global id of the sensor
/**
* Constructor
* @param id Global id of the sensor
*/
public MillisecondTimestampSensor(String id){
public TimestampSensor(String id){
this.id = id;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Sensor#read()
*/
@Override
public Object read() {
// Return current time in milliseconds
return new Double(System.currentTimeMillis());
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Sensor#getId()
*/
@Override
public String getId() {
return id;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Sensor#destroy()
*/
@Override
public void destroy() {
// Nothing to be done
}
}

View File

@@ -19,18 +19,6 @@
package ch.psi.fda.deserializer;
import ch.psi.fda.core.messages.DataQueue;
/**
* Data deserializer
* @author ebner
*
*/
public interface DataDeserializer extends Runnable {
/**
* Get data queue of deserializer
* @return data queue of deserializer
*/
public DataQueue getQueue();
public interface DataDeserializer {
public void read();
}

View File

@@ -9,45 +9,40 @@ import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.logging.Logger;
import ch.psi.fda.core.messages.ComponentMetadata;
import com.google.common.eventbus.EventBus;
import ch.psi.fda.core.messages.DataMessage;
import ch.psi.fda.core.messages.DataMessageMetadata;
import ch.psi.fda.core.messages.DataQueue;
import ch.psi.fda.core.messages.EndOfStreamMessage;
import ch.psi.fda.core.messages.Message;
import ch.psi.fda.core.messages.Metadata;
import ch.psi.fda.core.messages.StreamDelimiterMessage;
/**
* Deserializer MDA file
* TODO Need to be optimized as currently the while file is read into memory when creating this object.
*/
public class DataDeserializerMDA implements DataDeserializer {
private static Logger logger = Logger.getLogger(DataDeserializerMDA.class.getName());
private DataQueue queue;
private EventBus bus;
private RecursiveReturnContainer c;
public DataDeserializerMDA(File file){
public DataDeserializerMDA(EventBus b, File file){
this.bus = b;
try {
RecursiveReturnContainer c = read(new FileInputStream(file));
this.queue = new DataQueue(new LinkedBlockingQueue<Message>(), c.getMetadata());
// Add data to queue
for(Message m: c.getMessage()){
queue.getQueue().put(m);
}
queue.getQueue().put(new EndOfStreamMessage());
try{
c = read(new FileInputStream(file));
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
public RecursiveReturnContainer read(InputStream in) throws IOException {
private RecursiveReturnContainer read(InputStream in) throws IOException {
logger.fine("Read MDA input stream");
XDRInputStream x = new XDRInputStream(in);
@@ -218,7 +213,7 @@ public class DataDeserializerMDA implements DataDeserializer {
logger.fine("MDA - number of triggers:: "+ numberOfTriggers);
List<ComponentMetadata> componentMetadataList = new ArrayList<ComponentMetadata>();
List<Metadata> componentMetadataList = new ArrayList<>();
/**
* Read positioners metadata
*/
@@ -234,7 +229,7 @@ public class DataDeserializerMDA implements DataDeserializer {
String positionerName = x.readString();
logger.fine("MDA - positioner name:: "+positionerName);
// MDA starts at dimension number 1 we start at 0
componentMetadataList.add(new ComponentMetadata(positionerName,scanRank-1));
componentMetadataList.add(new Metadata(positionerName,scanRank-1));
}
length = x.readInt();
@@ -288,7 +283,7 @@ public class DataDeserializerMDA implements DataDeserializer {
String detectorName = x.readString();
logger.fine("MDA - detector name:: "+detectorName);
// MDA starts at dimension number 1 we start at 0
componentMetadataList.add(new ComponentMetadata(detectorName, scanRank-1));
componentMetadataList.add(new Metadata(detectorName, scanRank-1));
}
length = x.readInt();
@@ -372,7 +367,7 @@ public class DataDeserializerMDA implements DataDeserializer {
RecursiveReturnContainer cont = new RecursiveReturnContainer();
// Update component metadata
cont.getMetadata().getComponents().addAll(componentMetadataList);
cont.getMetadata().addAll(componentMetadataList);
if(scanRank > 1){
/**
@@ -389,14 +384,14 @@ public class DataDeserializerMDA implements DataDeserializer {
if(i==0){
// For the first scan of each dimension component data is read and stored
cont.getMetadata().getComponents().addAll(container.getMetadata().getComponents());
cont.getMetadata().addAll(container.getMetadata());
}
logger.fine("Convert data structure [rank="+scanRank+"] ...");
for(Message m: container.getMessage()){
if(m instanceof DataMessage){
// Add own data to message and pass it to container
DataMessage mm = new DataMessage();
DataMessage mm = new DataMessage(new ArrayList<Metadata>()); // Workaround
for(Double[] d: data){
mm.getData().add(d[i]);
}
@@ -424,7 +419,7 @@ public class DataDeserializerMDA implements DataDeserializer {
logger.fine("Convert data structure [rank="+scanRank+"]...");
for(int t = 0; t<npts ; t++){
DataMessage m = new DataMessage();
DataMessage m = new DataMessage(new ArrayList<Metadata>()); // workaround
for(Double[] d: data){
m.getData().add(d[t]);
}
@@ -443,23 +438,19 @@ public class DataDeserializerMDA implements DataDeserializer {
}
/* (non-Javadoc)
* @see java.lang.Runnable#run()
*/
@Override
public void run() {
// TODO Auto-generated method stub
public void read() {
// Add data to queue
for(Message m: c.getMessage()){
if(m instanceof DataMessage){
DataMessage dm = (DataMessage)m;
dm.getMetadata().addAll(c.getMetadata()); // WORKAROUND !!!! ideally the reference to metadata is set while creating the
// data message. Then there would be only one list with one reference. In this case we now have multiple lists!
}
bus.post(m);
}
bus.post(new EndOfStreamMessage());
}
/* (non-Javadoc)
* @see ch.psi.fda.deserializer.DataDeserializer#getQueue()
*/
@Override
public DataQueue getQueue() {
return queue;
}
}
/**
@@ -469,12 +460,12 @@ public class DataDeserializerMDA implements DataDeserializer {
*/
class RecursiveReturnContainer{
private List<Message> message = new ArrayList<Message>();
private DataMessageMetadata metadata = new DataMessageMetadata();
private List<Metadata> metadata = new ArrayList<>();
public List<Message> getMessage() {
return message;
}
public DataMessageMetadata getMetadata() {
public List<Metadata> getMetadata() {
return metadata;
}
}

View File

@@ -25,28 +25,24 @@ import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.logging.Logger;
import ch.psi.fda.core.messages.ComponentMetadata;
import com.google.common.eventbus.EventBus;
import ch.psi.fda.core.messages.DataMessage;
import ch.psi.fda.core.messages.DataMessageMetadata;
import ch.psi.fda.core.messages.DataQueue;
import ch.psi.fda.core.messages.Metadata;
import ch.psi.fda.core.messages.StreamDelimiterMessage;
import ch.psi.fda.core.messages.EndOfStreamMessage;
import ch.psi.fda.core.messages.Message;
/**
* Deserialize file data and put it into the DataQueue
* @author ebner
*
* Deserializer for text files
*/
public class DataDeserializerTXT implements DataDeserializer {
// Get Logger
private static Logger logger = Logger.getLogger(DataDeserializerTXT.class.getName());
private DataQueue queue;
private EventBus bus;
private List<Metadata> metadata;
private File file;
private List<Integer> dindex;
@@ -56,12 +52,14 @@ public class DataDeserializerTXT implements DataDeserializer {
* Default Constructor
* @param file
*/
public DataDeserializerTXT(File file){
public DataDeserializerTXT(EventBus b, File file){
this.bus = b;
this.file = file;
this.dindex = new ArrayList<Integer>();
this.iindex = new ArrayList<Integer>();
DataMessageMetadata metadata;
this.metadata = new ArrayList<>();
try{
// Read metadata
// Open file
@@ -81,11 +79,10 @@ public class DataDeserializerTXT implements DataDeserializer {
String[] dimensions = line.split("\t");
// Create data message metadata
metadata = new DataMessageMetadata();
Integer d = -1;
for(int i=0;i<ids.length;i++){
Integer dimension = Integer.parseInt(dimensions[i]);
metadata.getComponents().add(new ComponentMetadata(ids[i], dimension));
metadata.add(new Metadata(ids[i], dimension));
// Store the first index of the first component
// in each dimension ...
@@ -103,23 +100,10 @@ public class DataDeserializerTXT implements DataDeserializer {
catch(Exception e){
throw new RuntimeException("Unable to read file metadata and initialize data queue",e);
}
this.queue = new DataQueue(new LinkedBlockingQueue<Message>(10000000), metadata);
}
/* (non-Javadoc)
* @see ch.psi.fda.deserializer.DataDeserializer#getQueue()
*/
@Override
public DataQueue getQueue(){
return(queue);
}
/* (non-Javadoc)
* @see java.lang.Runnable#run()
*/
@Override
public void run() {
public void read() {
try{
List<Double> checklist = new ArrayList<Double>(dindex.size());
@@ -146,7 +130,7 @@ public class DataDeserializerTXT implements DataDeserializer {
// Create and populate new data message
String[] data = line.split("\t");
DataMessage message = new DataMessage();
DataMessage message = new DataMessage(metadata);
for (String d : data) {
// Remove spaces at the end and beginning of the value
d = d.trim();
@@ -190,19 +174,16 @@ public class DataDeserializerTXT implements DataDeserializer {
Integer i = iindex.get(t);
if(dindex.get(t)>0){
Double d = (Double) message.getData().get(i);
// if(checklist.get(i)==null){
// checklist.set(i, d);
// }
if(checklist.get(i)!=null &&!checklist.get(i).equals(d)){
// If value changes issue a dimension delimiter message
queue.getQueue().put(new StreamDelimiterMessage(dindex.get(t)-1));
bus.post(new StreamDelimiterMessage(dindex.get(t)-1));
}
checklist.set(i, d);
}
}
// Put message to queue
queue.getQueue().put(message);
bus.post(message);
// TODO Need to detect dimension boundaries
@@ -210,20 +191,15 @@ public class DataDeserializerTXT implements DataDeserializer {
// Add delimiter for all the dimensions
for(int i=dindex.size()-1;i>=0;i--){
queue.getQueue().put(new StreamDelimiterMessage(dindex.get(i)));
bus.post(new StreamDelimiterMessage(dindex.get(i)));
}
// queue.getQueue().put(new DimensionDelimiterMessage(dindex.get(0)-1));
// queue.getQueue().put(new DimensionDelimiterMessage(dindex.get(0)));
// Place end of stream message
queue.getQueue().put(new EndOfStreamMessage());
bus.post(new EndOfStreamMessage());
// Close file
reader.close();
} catch (InterruptedException e) {
throw new RuntimeException("Data deserializer was interrupted while reading the datafile",e);
} catch (IOException e) {
throw new RuntimeException("Data deserializer had a problem reading the specified datafile",e);
}

View File

@@ -17,12 +17,16 @@ public class ProgressPanel extends javax.swing.JPanel {
private static final long serialVersionUID = 1L;
private javax.swing.JButton abortButton;
private javax.swing.JProgressBar progressBar;
/** Creates new form ScanProgressPanel */
public ProgressPanel() {
initComponents();
}
/** This method is called from within the constructor to
/**
* This method is called from within the constructor to
* initialize the form.
*/
private void initComponents() {
@@ -59,8 +63,6 @@ public class ProgressPanel extends javax.swing.JPanel {
);
}
public void addActionListener(ActionListener l){
abortButton.addActionListener(l);
}
@@ -70,9 +72,4 @@ public class ProgressPanel extends javax.swing.JPanel {
progressBar.setValue(100);
abortButton.setEnabled(false);
}
// Variables declaration - do not modify
private javax.swing.JButton abortButton;
private javax.swing.JProgressBar progressBar;
// End of variables declaration
}

View File

@@ -13,31 +13,38 @@ public class ScrollableFlowPanel extends JPanel implements Scrollable {
private static final long serialVersionUID = 1L;
@Override
public void setBounds(int x, int y, int width, int height) {
super.setBounds(x, y, getParent().getWidth(), height);
}
@Override
public Dimension getPreferredSize() {
return new Dimension(getWidth(), getPreferredHeight());
}
@Override
public Dimension getPreferredScrollableViewportSize() {
return super.getPreferredSize();
}
@Override
public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
int hundredth = (orientation == SwingConstants.VERTICAL ? getParent().getHeight() : getParent().getWidth()) / 100;
return (hundredth == 0 ? 1 : hundredth);
}
@Override
public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
return orientation == SwingConstants.VERTICAL ? getParent().getHeight() : getParent().getWidth();
}
@Override
public boolean getScrollableTracksViewportWidth() {
return true;
}
@Override
public boolean getScrollableTracksViewportHeight() {
return false;
}

View File

@@ -33,17 +33,17 @@ import java.util.Enumeration;
import java.util.List;
import java.util.logging.Logger;
import ch.psi.fda.aq.AcquisitionConfiguration;
/**
* @author ebner
*
*/
public class ApplicationConfigurator {
// Get Logger
private static final Logger logger = Logger.getLogger(ApplicationConfigurator.class.getName());
public final static String FDA_HOME_ARGUMENT = "ch.psi.fda.home";
public final static String FDA_CONFIG_FILE_ARGUMENT = "ch.psi.fda.config.file";
private final File home;
private final File configdir;
@@ -89,9 +89,9 @@ public class ApplicationConfigurator {
}
// Set FDA configuration argument -Dch.psi.fda.config.file=...
property = System.getProperty(FDA_CONFIG_FILE_ARGUMENT);
property = System.getProperty(AcquisitionConfiguration.FDA_CONFIG_FILE);
if(property==null){
System.setProperty(FDA_CONFIG_FILE_ARGUMENT, fdaProperties.getAbsolutePath());
System.setProperty(AcquisitionConfiguration.FDA_CONFIG_FILE, fdaProperties.getAbsolutePath());
}
// Set jcae.properties file

View File

@@ -19,11 +19,7 @@
package ch.psi.fda.model;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
@@ -32,13 +28,7 @@ import javax.xml.bind.Marshaller;
import javax.xml.bind.UnmarshalException;
import javax.xml.bind.Unmarshaller;
import javax.xml.namespace.QName;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
@@ -49,83 +39,14 @@ import org.xml.sax.SAXParseException;
import ch.psi.fda.model.v1.Configuration;
/**
* Manage the serialization and deserialization of the model
* @author ebner
*
* Manage the serialization and deserialization of the FDA data model
*/
public class ModelManager {
/**
* Deserialize an instance of a data model of the type Configuration
* Before creating the object model variables will be replaced
* De-serialize an instance of the FDA data model
*
* @param file Scan file
* @param variables Scan variables
* @throws JAXBException Something went wrong while unmarshalling
* @throws SAXException Cannot read model schema file
* @throws ParserConfigurationException
* @throws IOException
* @throws TransformerFactoryConfigurationError
* @throws TransformerException
*/
public static Configuration unmarshall(File file, HashMap<String, String> variables) throws JAXBException, SAXException, IOException,
ParserConfigurationException, TransformerFactoryConfigurationError, TransformerException {
// Load template file
Transformer xformer = TransformerFactory.newInstance().newTransformer(new StreamSource(file));
// Overwrite parameters
for(String key: variables.keySet()){
xformer.setParameter(key, variables.get(key));
}
// Workaround for complex parameters (parameter including xml fragments)
// How the workaround works:
// Because we want to set complex parameters we first have to apply the xslt transformation to the input
// stream and create an other output stream. In the template file the complex parameter must be referenced as follows
// <xsl:value-of select="$var.regions" disable-output-escaping="yes" />
// If it is not done this way the < and > of the tags will be replaced by &lt; and &gt;
// Also if we directly transform to a DOMResult the dom tree would not include the
// nodes added by the parameter but just a text object. Therefor we do the workaround via the StreamResult ...
ByteArrayOutputStream bstream = new ByteArrayOutputStream();
StreamResult sresult = new StreamResult(bstream);
// Perform transformation (using template file also as input source)
xformer.transform(new StreamSource(file), sresult );
// Workaround for complex parameters
ByteArrayInputStream bistream = new ByteArrayInputStream(bstream.toByteArray());
StreamSource bsource = new StreamSource(bistream);
JAXBContext context = JAXBContext.newInstance(Configuration.class);
Unmarshaller u = context.createUnmarshaller();
// Validation
SchemaFactory sf = SchemaFactory.newInstance(javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI);
Source s = new StreamSource(Configuration.class.getResourceAsStream("/model-v1.xsd"));
Schema schema = sf.newSchema(new Source[]{s}); // Use schema reference provided in XML
u.setSchema(schema);
try{
Configuration model = (Configuration) u.unmarshal(bsource, Configuration.class).getValue();
return (model);
}
catch(UnmarshalException e){
// Check
if(e.getLinkedException() instanceof SAXParseException){
throw new RuntimeException("Configuration file does not comply to required model specification\nCause: "+e.getLinkedException().getMessage(), e);
}
throw e;
}
}
/**
* Deserialize an instance of a data model of the type Configuration
* @param file
* @param file File to deserialize
* @throws JAXBException Something went wrong while unmarshalling
* @throws SAXException Cannot read model schema file
*/
@@ -154,7 +75,8 @@ public class ModelManager {
}
/**
* Serialize an instance of a data model of the type Configuration
* Serialize an instance of the FDA data model
*
* @param model Model datastructure
* @param file File to write the model data into
* @throws JAXBException Something went wrong while marshalling model

View File

@@ -0,0 +1,170 @@
/**
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.rest;
import java.util.UUID;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.logging.Logger;
import javax.inject.Inject;
import com.google.common.eventbus.EventBus;
import ch.psi.fda.aq.Acquisition;
import ch.psi.fda.aq.AcquisitionConfiguration;
import ch.psi.fda.model.v1.Configuration;
import ch.psi.jcae.ChannelService;
/**
* Main engine for data acquisition.
*/
public class AcquisitionEngine {
private static final Logger logger = Logger.getLogger(AcquisitionEngine.class.getName());
private AcquisitionConfiguration config;
private ChannelService cservice;
private final ZMQDataService dservice;
/**
* Variable holding the current acquisition
*/
private volatile Acquisition acquisition;
private volatile ExecutionRequest currentRequest;
private ExecutorService eservice;
private BlockingQueue<ExecutionRequest> requests = new LinkedBlockingQueue<>();
@Inject
public AcquisitionEngine(ChannelService cservice, ZMQDataService dservice, AcquisitionConfiguration config) {
this.dservice = dservice;
this.cservice = cservice;
this.config = config;
// Start main execution loop
eservice = Executors.newSingleThreadExecutor();
eservice.execute(new Runnable() {
@Override
public void run() {
try {
while (!Thread.currentThread().isInterrupted()) {
try {
ExecutionRequest r = requests.take();
logger.info("Execute - " + r.getTrackingId());
EventBus ebus = new EventBus();
// Provide tracking id to data service and register the service to the event bus
AcquisitionEngine.this.dservice.setTrackingId(r.getTrackingId());
ebus.register(AcquisitionEngine.this.dservice);
synchronized (AcquisitionEngine.this) { // synchronize access to acquisition object via the AcquisitionEngine object
acquisition = new Acquisition(AcquisitionEngine.this.cservice, AcquisitionEngine.this.config);
currentRequest = r;
}
acquisition.initalize(ebus, r.getConfiguration());
acquisition.execute();
logger.info("" + r.getTrackingId() + " done");
// Cleanup
ebus.unregister(AcquisitionEngine.this.dservice);
} finally {
acquisition.destroy();
synchronized (AcquisitionEngine.this) {
acquisition = null;
currentRequest = null;
}
}
}
} catch (InterruptedException e) {
}
}
});
}
/**
* Submit a scan to be executed. This will generate an execution request which is
* enqueued in the execution queue.
*
* @param configuration
* @return
*/
public String submit(Configuration configuration){
ExecutionRequest r = new ExecutionRequest(UUID.randomUUID().toString(), configuration);
try{
requests.put(r);
} catch (InterruptedException e) {
}
return r.getTrackingId();
}
/**
* Terminate the currently executed request
*/
public void terminate(){
synchronized(this){
if(acquisition==null){
return;
}
logger.info("Stop current acquisition");
acquisition.abort();
}
}
/**
* Terminate the request which is identified by its tracking id. If the request
* is still in the execution queue it gets removed there.
* @param trackingId
*/
public void terminate(String trackingId){
// If request is currently executed terminate it
if(currentRequest.getTrackingId().equals(trackingId)){
terminate();
return;
}
// Remove request from request queue
ExecutionRequest rremove = null;
for(ExecutionRequest r:requests){
if(r.getTrackingId().equals(trackingId)){
rremove = r; // We have to split the filtering and termination as we otherwise get a concurrent access exception.
break;
}
}
if(rremove!=null){
boolean b = requests.remove(rremove);
// There is a chance that between the upper loop and here the request
// already got dequeued. This check ensures that the requests got removed
// if not it got dequeued and therefore we have to terminate the current
// execution.
if(!b){
terminate();
}
}
}
}

View File

@@ -16,23 +16,28 @@
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.aq.ng.rdescriptors;
package ch.psi.fda.rest;
import java.util.ArrayList;
import java.util.List;
import ch.psi.jcae.ChannelDescriptor;
import ch.psi.fda.model.v1.Configuration;
/**
* @author ebner
*
*/
public class ProbeDescriptor {
public class ExecutionRequest {
private List<ChannelDescriptor<?>> sensors = new ArrayList<>();
private final String trackingId;
private final Configuration configuration;
public List<ChannelDescriptor<?>> getSensors(){
return sensors;
public ExecutionRequest(String trackingId, Configuration configuration){
this.trackingId = trackingId;
this.configuration = configuration;
}
public String getTrackingId() {
return trackingId;
}
public Configuration getConfiguration() {
return configuration;
}
}

View File

@@ -0,0 +1,22 @@
package ch.psi.fda.rest;
import javax.inject.Singleton;
import org.glassfish.hk2.utilities.binding.AbstractBinder;
import ch.psi.fda.aq.AcquisitionConfiguration;
import ch.psi.jcae.ChannelService;
import ch.psi.jcae.impl.DefaultChannelService;
public class ResourceBinder extends AbstractBinder {
@Override
protected void configure() {
bind(DefaultChannelService.class).to(ChannelService.class).in(Singleton.class);
bind(AcquisitionConfiguration.class).to(AcquisitionConfiguration.class).in(Singleton.class);
bind(AcquisitionEngine.class).to(AcquisitionEngine.class).in(Singleton.class);
bind(ZMQDataService.class).to(ZMQDataService.class).in(Singleton.class);
}
}

View File

@@ -0,0 +1,98 @@
package ch.psi.fda.rest;
import java.io.IOException;
import java.net.InetAddress;
import java.net.URI;
import java.util.concurrent.CountDownLatch;
import java.util.logging.Logger;
import javax.ws.rs.core.UriBuilder;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.GnuParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
import org.glassfish.jersey.jackson.JacksonFeature;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.grizzly.http.server.HttpServer;
import sun.misc.Signal;
import sun.misc.SignalHandler;
@SuppressWarnings("restriction")
public class RestServer {
private static final Logger logger = Logger.getLogger(RestServer.class.getName());
public static void main(String[] args) throws IOException, ParseException {
// Option handling
int port = 8080;
Options options = new Options();
options.addOption("h", false, "Help");
options.addOption("p", true, "Server port (default: "+port+")");
GnuParser parser = new GnuParser();
CommandLine line = parser.parse(options, args);
if (line.hasOption("p")) {
port = Integer.parseInt(line.getOptionValue("p"));
}
if (line.hasOption("h")) {
HelpFormatter f = new HelpFormatter();
f.printHelp("broker", options);
return;
}
URI baseUri = UriBuilder.fromUri("http://" + InetAddress.getLocalHost().getHostName() + "/").port(port).build();
// Broker broker = createBroker(config);
ResourceBinder binder = new ResourceBinder();
ResourceConfig resourceConfig = new ResourceConfig(JacksonFeature.class);
resourceConfig.packages(RestServer.class.getPackage().getName()+".services"); // Services are located in services package
resourceConfig.register(binder);
HttpServer server = GrizzlyHttpServerFactory.createHttpServer(baseUri, resourceConfig);
// Static content
// String home = System.getenv("BROKER_BASE");
// if (home == null) {
// home = "src/main/assembly";
// }
// home = home + "/www";
// server.getServerConfiguration().addHttpHandler(new StaticHttpHandler(home), "/static");
logger.info("Broker started");
// logger.info(String.format("Management interface available at %sstatic/", baseUri));
logger.info("Use ctrl+c to stop ...");
// Signal handling
final CountDownLatch latch = new CountDownLatch(1);
Signal.handle(new Signal("INT"), new SignalHandler() {
public void handle(Signal sig) {
if(latch.getCount()==0){
logger.info("Terminate broker by System.exit()");
System.exit(1); // Terminate program after 2 ctrl+c
}
latch.countDown();
}
});
// Wait for termination, i.e. wait for ctrl+c
try {
latch.await();
} catch (InterruptedException e) {
}
server.stop();
// broker.terminate();
}
}

View File

@@ -0,0 +1,85 @@
/**
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.rest;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jeromq.ZMQ;
import ch.psi.fda.core.messages.Message;
import com.google.common.eventbus.Subscribe;
/**
* @author ebner
*
*/
public class ZMQDataService {
private static final Logger logger = Logger.getLogger(ZMQDataService.class.getName());
private final int bufferSize = 5;
private ZMQ.Context context;
private ZMQ.Socket socket;
private String trackingId;
public ZMQDataService(){
initialize();
}
public void initialize(){
context = ZMQ.context();
zmq.ZError.clear(); // Clear error code
socket = context.socket(ZMQ.PUB);
socket.setHWM(bufferSize);
socket.bind("tcp://*:10000");
}
public void terminate(){
socket.close();
context.term();
zmq.ZError.clear(); // Clear error code
}
@Subscribe
public void onMessage(Message m) {
logger.info(m.toString());
socket.sendMore("{\"trackingId\":\"" + trackingId + "\"}");
try (
ByteArrayOutputStream b = new ByteArrayOutputStream();
ObjectOutputStream o = new ObjectOutputStream(b);
) {
o.writeObject(m);
socket.send(b.toByteArray());
} catch (IOException e) {
logger.log(Level.WARNING, "Unable to serialize message", e);
}
}
public void setTrackingId(String id){
trackingId = id;
}
}

View File

@@ -16,13 +16,34 @@
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.aq.ng.rdescriptors;
/**
* Resource descriptor of an operating system shell.
* @author ebner
*
*/
public class ShellDescriptor {
package ch.psi.fda.rest.services;
import javax.inject.Inject;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.MediaType;
import ch.psi.fda.model.v1.Configuration;
import ch.psi.fda.rest.AcquisitionEngine;
@Path("fda")
public class ScanService {
@Inject
private AcquisitionEngine aengine;
@POST
@Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
// @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public String execute(Configuration configuration) throws InterruptedException{
return aengine.submit(configuration);
}
@DELETE
public void stop(){
aengine.terminate();
}
}

Some files were not shown because too many files have changed in this diff Show More