removed xmlscan based classes and imported ch.psi.fda.xscan library
instead
This commit is contained in:
@@ -6,7 +6,6 @@
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="src" path="target/generated-sources/xjc"/>
|
||||
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
|
||||
@@ -13,11 +13,18 @@
|
||||
<version>0.0.2</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>ch.psi.fda</groupId>
|
||||
<artifactId>ch.psi.fda.xscan</artifactId>
|
||||
<version>2.2.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>ch.psi</groupId>
|
||||
<artifactId>ch.psi.fda.cdump</artifactId>
|
||||
<version>1.0.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>ch.psi</groupId>
|
||||
<artifactId>ch.psi.fda.fdaq</artifactId>
|
||||
@@ -48,42 +55,19 @@
|
||||
<version>2.5.1</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>org.jeromq</groupId>
|
||||
<artifactId>jeromq</artifactId>
|
||||
<version>0.2.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>ch.psi</groupId>
|
||||
<artifactId>jcae</artifactId>
|
||||
<version>2.1.11</version>
|
||||
</dependency>
|
||||
<!-- Plotting library -->
|
||||
<dependency>
|
||||
<groupId>ch.psi</groupId>
|
||||
<artifactId>plot</artifactId>
|
||||
<version>1.1.31</version>
|
||||
</dependency>
|
||||
<!-- Java SMB/CIFS library -->
|
||||
<dependency>
|
||||
<groupId>jcifs</groupId>
|
||||
<artifactId>jcifs</artifactId>
|
||||
<version>1.3.17</version>
|
||||
</dependency>
|
||||
|
||||
<!-- JAXB implementation -->
|
||||
<!-- <dependency> <groupId>com.sun.xml.bind</groupId> <artifactId>jaxb-impl</artifactId>
|
||||
<version>2.2.1</version> </dependency> <dependency> <groupId>com.sun.xml.bind</groupId>
|
||||
<artifactId>jaxb-xjc</artifactId> <version>2.2.1</version> </dependency> -->
|
||||
<!-- Jython Library -->
|
||||
<dependency>
|
||||
<groupId>org.python</groupId>
|
||||
<artifactId>jython</artifactId>
|
||||
<version>2.5.3</version>
|
||||
</dependency>
|
||||
<!-- CLI Libraries -->
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>cli</artifactId>
|
||||
@@ -95,12 +79,6 @@
|
||||
<artifactId>jmatio</artifactId>
|
||||
<version>0.2u2psi1</version>
|
||||
</dependency>
|
||||
<!-- Mail Libraries -->
|
||||
<dependency>
|
||||
<groupId>com.sun.mail</groupId>
|
||||
<artifactId>javax.mail</artifactId>
|
||||
<version>1.5.0</version>
|
||||
</dependency>
|
||||
<!-- Library for reading/writing XDR Format (MDA) -->
|
||||
<dependency>
|
||||
<groupId>org.freehep</groupId>
|
||||
@@ -127,19 +105,9 @@
|
||||
<target>1.7</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<!-- <plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.8</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-javadocs</id>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin> -->
|
||||
<!-- <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.8</version> <executions> <execution> <id>attach-javadocs</id>
|
||||
<goals> <goal>jar</goal> </goals> </execution> </executions> </plugin> -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
@@ -153,99 +121,7 @@
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<!-- Schema generation -->
|
||||
<plugin>
|
||||
<groupId>org.jvnet.jaxb2.maven2</groupId>
|
||||
<artifactId>maven-jaxb2-plugin</artifactId>
|
||||
<version>0.8.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>generate</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<generatePackage>ch.psi.fda.model.v1</generatePackage>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<!-- Schema Documentation Generation -->
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>xml-maven-plugin</artifactId>
|
||||
<version>1.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>transform</phase>
|
||||
<goals>
|
||||
<goal>transform</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<transformationSets>
|
||||
<transformationSet>
|
||||
<!-- <outputDir>target</outputDir> -->
|
||||
<dir>src/main/resources</dir>
|
||||
<stylesheet>src/main/documentation/xs3p.xsl</stylesheet>
|
||||
<fileMappers>
|
||||
<fileMapper
|
||||
implementation="org.codehaus.plexus.components.io.filemappers.RegExpFileMapper">
|
||||
<pattern>\.xsd$</pattern>
|
||||
<replacement>.html</replacement>
|
||||
</fileMapper>
|
||||
</fileMappers>
|
||||
</transformationSet>
|
||||
</transformationSets>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<!--This plugin's configuration is used to store Eclipse m2e settings
|
||||
only. It has no influence on the Maven build itself. -->
|
||||
<plugin>
|
||||
<groupId>org.eclipse.m2e</groupId>
|
||||
<artifactId>lifecycle-mapping</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<configuration>
|
||||
<lifecycleMappingMetadata>
|
||||
<pluginExecutions>
|
||||
<pluginExecution>
|
||||
<pluginExecutionFilter>
|
||||
<groupId>
|
||||
org.jvnet.jaxb2.maven2
|
||||
</groupId>
|
||||
<artifactId>
|
||||
maven-jaxb2-plugin
|
||||
</artifactId>
|
||||
<versionRange>
|
||||
[0.8.0,)
|
||||
</versionRange>
|
||||
<goals>
|
||||
<goal>generate</goal>
|
||||
</goals>
|
||||
</pluginExecutionFilter>
|
||||
<action>
|
||||
<ignore></ignore>
|
||||
</action>
|
||||
</pluginExecution>
|
||||
</pluginExecutions>
|
||||
</lifecycleMappingMetadata>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<configuration>
|
||||
<descriptors>
|
||||
<descriptor>src/main/assembly/assembly.xml</descriptor>
|
||||
</descriptors>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</build>
|
||||
|
||||
<distributionManagement>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,102 +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.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.messages.DataMessage;
|
||||
import ch.psi.fda.messages.EndOfStreamMessage;
|
||||
import ch.psi.fda.messages.Message;
|
||||
import ch.psi.fda.messages.Metadata;
|
||||
import ch.psi.fda.messages.StreamDelimiterMessage;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,77 +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.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.messages.DataMessage;
|
||||
import ch.psi.fda.messages.Message;
|
||||
import ch.psi.fda.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);
|
||||
}
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Paul Scherrer Institute
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package ch.psi.fda.aq;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.mail.Message;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.Session;
|
||||
import javax.mail.Transport;
|
||||
import javax.mail.internet.InternetAddress;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
|
||||
import ch.psi.fda.model.v1.Recipient;
|
||||
|
||||
/**
|
||||
* Agent to send out notifications to specified recipients.
|
||||
*/
|
||||
public class NotificationAgent {
|
||||
|
||||
private final static String smsPostfix = "@sms.switch.ch";
|
||||
|
||||
private Properties properties;
|
||||
private String fromAddress;
|
||||
private final List<Recipient> recipients = new ArrayList<Recipient>();
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param host SMTP server to send notifications to
|
||||
* @param recipients List of recipients
|
||||
* @param from Address string that will show up in the from field. For example: fda@psi.ch. This argument must not contain white spaces
|
||||
*/
|
||||
public NotificationAgent(String host, String from){
|
||||
|
||||
fromAddress = from;
|
||||
|
||||
properties = new Properties();
|
||||
properties.put("mail.smtp.host", host);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void sendNotification(String aSubject, String aBody, boolean error, boolean success) {
|
||||
|
||||
for(Recipient recipient: recipients){
|
||||
|
||||
if((error && recipient.isError()) || (success && recipient.isSuccess())){
|
||||
String receiver;
|
||||
|
||||
// Verify mail recipients
|
||||
if(recipient.getValue().matches("[0-9,\\\\.,-,a-z,A-Z]*@[0-9,\\\\.,a-z,A-Z]*")){
|
||||
receiver = recipient.getValue();
|
||||
}
|
||||
else if(recipient.getValue().matches("[0-9]+")){
|
||||
// Assume that it is a SMS number
|
||||
receiver = recipient.getValue() + smsPostfix;
|
||||
}
|
||||
else{
|
||||
Logger.getLogger(NotificationAgent.class.getName()).log(Level.WARNING, "Invalid email address");
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
Logger.getLogger(NotificationAgent.class.getName()).log(Level.INFO, "Send notification to " + receiver);
|
||||
|
||||
//Here, no Authenticator argument is used (it is null).
|
||||
//Authenticators are used to prompt the user for user
|
||||
//name and password.
|
||||
Session session = Session.getDefaultInstance(properties, null);
|
||||
MimeMessage message = new MimeMessage(session);
|
||||
try {
|
||||
//The "from" address may be set in code, or set in the
|
||||
//config file under "mail.from" ; here, the latter style is used
|
||||
message.setFrom( new InternetAddress(fromAddress) );
|
||||
|
||||
message.addRecipient(Message.RecipientType.TO, new InternetAddress(receiver));
|
||||
message.setSubject(aSubject);
|
||||
message.setText(aBody);
|
||||
Transport.send(message);
|
||||
} catch (MessagingException ex) {
|
||||
Logger.getLogger(NotificationAgent.class.getName()).log(Level.WARNING, "Failed to send notification to " + receiver, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<Recipient> getRecipients() {
|
||||
return recipients;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
package ch.psi.fda.aq;
|
||||
|
||||
import com.google.common.eventbus.EventBus;
|
||||
|
||||
import ch.psi.fda.EContainer;
|
||||
import ch.psi.fda.model.v1.Configuration;
|
||||
import ch.psi.jcae.ChannelService;
|
||||
|
||||
public class XScanContainer implements EContainer {
|
||||
|
||||
private final Acquisition acquisition;
|
||||
|
||||
private EventBus bus;
|
||||
private Configuration xscanConfiguration;
|
||||
|
||||
public XScanContainer(ChannelService cservice, AcquisitionConfiguration config, EventBus bus, Configuration xscanConfiguration){
|
||||
acquisition = new Acquisition(cservice, config);
|
||||
this.bus = bus;
|
||||
this.xscanConfiguration = xscanConfiguration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
acquisition.initalize(bus, xscanConfiguration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
try {
|
||||
acquisition.execute();
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void abort() {
|
||||
acquisition.abort();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
acquisition.abort();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
acquisition.destroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActive() {
|
||||
return acquisition.isActive();
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package ch.psi.fda.aq;
|
||||
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
|
||||
import ch.psi.fda.edescriptor.EDescriptor;
|
||||
import ch.psi.fda.model.v1.Configuration;
|
||||
|
||||
@XmlRootElement(name="edescriptor")
|
||||
@XmlType(name="edescriptor")
|
||||
public class XScanDescriptor implements EDescriptor {
|
||||
|
||||
private Configuration configuration;
|
||||
|
||||
public XScanDescriptor(){
|
||||
}
|
||||
|
||||
public XScanDescriptor(Configuration configuration){
|
||||
this.configuration = configuration;
|
||||
}
|
||||
|
||||
|
||||
public Configuration getConfiguration() {
|
||||
return configuration;
|
||||
}
|
||||
public void setConfiguration(Configuration configuration) {
|
||||
this.configuration = configuration;
|
||||
}
|
||||
}
|
||||
@@ -1,330 +0,0 @@
|
||||
package ch.psi.fda.aq;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import ch.psi.fda.DescriptorProvider;
|
||||
import ch.psi.fda.edescriptor.EDescriptor;
|
||||
import ch.psi.fda.model.ModelManager;
|
||||
import ch.psi.fda.model.v1.ArrayDetector;
|
||||
import ch.psi.fda.model.v1.Configuration;
|
||||
import ch.psi.fda.model.v1.ContinuousPositioner;
|
||||
import ch.psi.fda.model.v1.Data;
|
||||
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.vdescriptor.LinePlot;
|
||||
import ch.psi.fda.vdescriptor.VDescriptor;
|
||||
import ch.psi.fda.vdescriptor.XYSeries;
|
||||
import ch.psi.fda.vdescriptor.XYZSeries;
|
||||
import ch.psi.fda.vdescriptor.YSeries;
|
||||
import ch.psi.fda.vdescriptor.YZSeries;
|
||||
|
||||
public class XScanDescriptorProvider implements DescriptorProvider {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(XScanDescriptorProvider.class.getName());
|
||||
|
||||
private EDescriptor edescriptor;
|
||||
private VDescriptor vdescriptor;
|
||||
|
||||
@Override
|
||||
public void load(File... files) {
|
||||
|
||||
if(files.length<1 || files[0]==null){
|
||||
throw new IllegalArgumentException("There need to be at lease one file specified");
|
||||
}
|
||||
File file = files[0];
|
||||
|
||||
if(!file.exists()){
|
||||
throw new IllegalArgumentException("File "+file.getAbsolutePath()+" does not exist");
|
||||
}
|
||||
|
||||
Configuration c;
|
||||
try {
|
||||
c = ModelManager.unmarshall(file);
|
||||
} catch (Exception e) {
|
||||
throw new UnsupportedOperationException("Unable to deserialize configuration: "+e.getMessage(), e);
|
||||
}
|
||||
|
||||
// Set data file name
|
||||
// Determine name used for the data file
|
||||
String name = file.getName();
|
||||
name = name.replaceAll("\\.xml$", "");
|
||||
|
||||
if(c.getData()!=null){
|
||||
Data data = c.getData();
|
||||
// Only update filename if no name is specified in xml file
|
||||
if(data.getFileName()==null){
|
||||
data.setFileName(name);
|
||||
}
|
||||
}
|
||||
else{
|
||||
Data data = new Data();
|
||||
data.setFileName(name);
|
||||
c.setData(data);
|
||||
}
|
||||
|
||||
|
||||
// // Override number of executions
|
||||
// if(iterations != null){
|
||||
// c.setNumberOfExecution(iterations);
|
||||
// }
|
||||
// Fix configuration if iterations is specified with 0 and no iterations option is specified
|
||||
if(c.getNumberOfExecution()==0){
|
||||
c.setNumberOfExecution(1);
|
||||
}
|
||||
|
||||
this.edescriptor = new XScanDescriptor(c);
|
||||
this.vdescriptor = mapVisualizations(c.getVisualization());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a vdescriptor out of the scan description
|
||||
* @param vl
|
||||
* @return
|
||||
*/
|
||||
private VDescriptor mapVisualizations(List<Visualization> vl){
|
||||
VDescriptor vd = new VDescriptor();
|
||||
|
||||
|
||||
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;
|
||||
|
||||
String x = getId(lp.getX());
|
||||
|
||||
LinePlot lineplot = new LinePlot(lp.getTitle());
|
||||
List<Object> l = lp.getY();
|
||||
for(Object o: l){
|
||||
String y = getId(o);
|
||||
lineplot.getData().add(new XYSeries(x, y));
|
||||
}
|
||||
|
||||
vd.getPlots().add(lineplot);
|
||||
}
|
||||
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;
|
||||
|
||||
LinePlot lineplot = new LinePlot(lp.getTitle());
|
||||
// Create data filter for visualization
|
||||
List<Object> l = lp.getY();
|
||||
for(Object o: l){
|
||||
String idY = getId(o);
|
||||
|
||||
// TODO Need to actually check if minX of
|
||||
lineplot.setMinX(new Double(lp.getOffset()));
|
||||
lineplot.setMaxX(new Double(lp.getOffset()+lp.getSize()));
|
||||
lineplot.getData().add(new YSeries(idY));
|
||||
}
|
||||
}
|
||||
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());
|
||||
|
||||
|
||||
ch.psi.fda.vdescriptor.MatrixPlot matrixplot = new ch.psi.fda.vdescriptor.MatrixPlot(mp.getTitle());
|
||||
matrixplot.setMinX(minX);
|
||||
matrixplot.setMaxX(maxX);
|
||||
matrixplot.setnX(nX);
|
||||
matrixplot.setMinY(minY);
|
||||
matrixplot.setMaxY(maxY);
|
||||
matrixplot.setnY(nY);
|
||||
|
||||
matrixplot.getData().add(new XYZSeries(idX, idY, idZ));
|
||||
vd.getPlots().add(matrixplot);
|
||||
}
|
||||
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());
|
||||
|
||||
ch.psi.fda.vdescriptor.MatrixPlot matrixplot = new ch.psi.fda.vdescriptor.MatrixPlot(mp.getTitle());
|
||||
matrixplot.setMinX(minX);
|
||||
matrixplot.setMaxX(maxX);
|
||||
matrixplot.setnX(nX);
|
||||
matrixplot.setMinY(minY);
|
||||
matrixplot.setMaxY(maxY);
|
||||
matrixplot.setnY(nY);
|
||||
|
||||
matrixplot.getData().add(new YZSeries(idY, idZ));
|
||||
vd.getPlots().add(matrixplot);
|
||||
|
||||
}
|
||||
else{
|
||||
logger.warning(v.getClass().getName()+" is not supported as visualization type");
|
||||
}
|
||||
}
|
||||
return vd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve id string of the passed object
|
||||
* @param object
|
||||
* @return Id string of object
|
||||
*/
|
||||
private 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;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public EDescriptor getEDescriptor() {
|
||||
return edescriptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VDescriptor getVDescriptor() {
|
||||
return vdescriptor;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package ch.psi.fda.aq;
|
||||
|
||||
import com.google.common.eventbus.EventBus;
|
||||
|
||||
import ch.psi.fda.EContainer;
|
||||
import ch.psi.fda.EContainerFactory;
|
||||
import ch.psi.fda.edescriptor.EDescriptor;
|
||||
import ch.psi.jcae.ChannelService;
|
||||
import ch.psi.jcae.impl.DefaultChannelService;
|
||||
|
||||
public class XScanFactory implements EContainerFactory {
|
||||
|
||||
// TODO need to be injected
|
||||
private ChannelService cservice = new DefaultChannelService();
|
||||
|
||||
private AcquisitionConfiguration config = new AcquisitionConfiguration();
|
||||
|
||||
@Override
|
||||
public boolean supportsEDescriptor(EDescriptor descriptor) {
|
||||
return (descriptor instanceof XScanDescriptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EContainer createContainer(EDescriptor descriptor, EventBus bus) {
|
||||
|
||||
if(! (descriptor instanceof XScanDescriptor)){
|
||||
throw new IllegalArgumentException("Descriptor of type "+descriptor.getClass().getName()+" is not supported - descriptor need to be of type "+XScanDescriptor.class);
|
||||
}
|
||||
|
||||
XScanDescriptor xdescriptor = (XScanDescriptor) descriptor;
|
||||
|
||||
return new XScanContainer(cservice, config, bus, xdescriptor.getConfiguration());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,33 +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;
|
||||
|
||||
public interface Action {
|
||||
|
||||
/**
|
||||
* Execute logic of the action
|
||||
*/
|
||||
public void execute() throws InterruptedException;
|
||||
|
||||
/**
|
||||
* Abort the execution logic of the action
|
||||
*/
|
||||
public void abort();
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
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.
|
||||
*/
|
||||
public interface ActionLoop extends Action {
|
||||
|
||||
/**
|
||||
* Prepare ActionLoop for execution.
|
||||
*/
|
||||
public void prepare();
|
||||
|
||||
/**
|
||||
* Cleanup resources used by this ActionLoop while it was executed.
|
||||
*/
|
||||
public void cleanup();
|
||||
|
||||
/**
|
||||
* Get the pre actions of the Loop
|
||||
* @return pre actions
|
||||
*/
|
||||
public List<Action> getPreActions();
|
||||
|
||||
/**
|
||||
* Get the post actions of the loop
|
||||
* @return post actions
|
||||
*/
|
||||
public List<Action> getPostActions();
|
||||
|
||||
/**
|
||||
* @return is a datagroup
|
||||
*/
|
||||
public boolean isDataGroup();
|
||||
|
||||
/**
|
||||
* Set whether data of the loop belongs to a own data group
|
||||
* @param dataGroup
|
||||
*/
|
||||
public void setDataGroup(boolean dataGroup);
|
||||
|
||||
public EventBus getEventBus();
|
||||
}
|
||||
@@ -1,49 +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;
|
||||
|
||||
public interface Actor {
|
||||
/**
|
||||
* Set actor value
|
||||
*/
|
||||
public void set() throws InterruptedException;
|
||||
|
||||
/**
|
||||
* Function to check whether the actor has a next set value
|
||||
* @return Returns true if there is an actor value for the next iteration.
|
||||
* False if there is no actor value (i.e. this will be the last iteration in the ActionLoop)
|
||||
*/
|
||||
public boolean hasNext();
|
||||
|
||||
/**
|
||||
* Initialize the actor to the start
|
||||
*/
|
||||
public void init();
|
||||
|
||||
/**
|
||||
* Reverse the set values of the actor
|
||||
*/
|
||||
public void reverse();
|
||||
|
||||
/**
|
||||
* Reset the actuator to its initial configuration
|
||||
*/
|
||||
public void reset();
|
||||
}
|
||||
@@ -1,40 +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;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
/**
|
||||
* Callable used for parallel execution of the set method of an actor
|
||||
*/
|
||||
public class ActorSetCallable implements Callable<Object> {
|
||||
|
||||
private Actor actor;
|
||||
|
||||
public ActorSetCallable(Actor actor){
|
||||
this.actor = actor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object call() throws Exception {
|
||||
actor.set();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,41 +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;
|
||||
|
||||
/**
|
||||
* Guard to protect specific activities. A guard can be used to check for environment changes while a
|
||||
* certain activity was executed.
|
||||
*
|
||||
* Example:
|
||||
* An Guard can be used to check whether an injection happened while the the detector were read.
|
||||
*/
|
||||
public interface Guard {
|
||||
|
||||
/**
|
||||
* Initialize guard object and its internal state.
|
||||
*/
|
||||
public void init();
|
||||
|
||||
/**
|
||||
* Check the status of the guard.
|
||||
* @return Returns true if the guard condition was not constrainted since the last init call. False otherwise.
|
||||
*/
|
||||
public boolean check();
|
||||
}
|
||||
@@ -1,47 +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;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import ch.psi.fda.messages.DataMessage;
|
||||
import ch.psi.fda.messages.Metadata;
|
||||
|
||||
public interface Manipulation {
|
||||
|
||||
/**
|
||||
* Get the id of the manipulation
|
||||
* @return id of manipulation
|
||||
*/
|
||||
public String getId();
|
||||
|
||||
/**
|
||||
* Initialize the manipulation
|
||||
* @param metadata Metadata of the incomming data message
|
||||
*/
|
||||
public void initialize(List<Metadata> metadata);
|
||||
|
||||
/**
|
||||
* Execute the manipulation on the passed data message
|
||||
* @param message Message to manipulate
|
||||
* @return Result of the manipulation
|
||||
*/
|
||||
public Object execute(DataMessage message);
|
||||
}
|
||||
@@ -1,39 +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;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public interface Sensor {
|
||||
/**
|
||||
* Readout sensor.
|
||||
* @return Sensor value. The type of the returned value depends on the sensor type.
|
||||
*/
|
||||
public Object read() throws InterruptedException;
|
||||
|
||||
/**
|
||||
* Get the global id of the sensor
|
||||
* @return id of sensor
|
||||
*/
|
||||
public String getId();
|
||||
}
|
||||
@@ -1,124 +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.ChannelException;
|
||||
|
||||
/**
|
||||
* Perform a put on the specified Channel Access channel. The put can be done synchronous or
|
||||
* asynchronously.
|
||||
*/
|
||||
public class ChannelAccessCondition<E> implements Action {
|
||||
|
||||
private static Logger logger = Logger.getLogger(ChannelAccessCondition.class.getName());
|
||||
|
||||
private final Channel<E> channel;
|
||||
private final E expectedValue;
|
||||
private final Comparator<E> comparator;
|
||||
private final Long timeout;
|
||||
|
||||
private volatile boolean abort = false;
|
||||
private volatile Thread waitT = null;
|
||||
|
||||
/**
|
||||
* @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)
|
||||
*
|
||||
* @throws IllegalArgumentException Timeout specified is not >=0
|
||||
*/
|
||||
public ChannelAccessCondition(Channel<E> channel, E expectedValue, Long timeout){
|
||||
|
||||
if(timeout != null && timeout<=0){
|
||||
throw new IllegalArgumentException("Timeout must be > 0");
|
||||
}
|
||||
|
||||
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 && timeout<=0){
|
||||
throw new IllegalArgumentException("Timeout must be > 0");
|
||||
}
|
||||
|
||||
this.channel = channel;
|
||||
this.expectedValue = expectedValue;
|
||||
this.comparator = comparator;
|
||||
this.timeout = timeout;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @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();
|
||||
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);
|
||||
}
|
||||
}
|
||||
finally{
|
||||
waitT=null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void abort() {
|
||||
abort=true;
|
||||
if(waitT!=null){
|
||||
waitT.interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,94 +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.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.ChannelException;
|
||||
|
||||
/**
|
||||
* Perform a put on the specified Channel Access channel. The put can be done synchronous or
|
||||
* asynchronously.
|
||||
*/
|
||||
public class ChannelAccessPut<E> implements Action {
|
||||
|
||||
private static Logger logger = Logger.getLogger(ChannelAccessPut.class.getName());
|
||||
|
||||
private final Channel<E> channel;
|
||||
private final E value;
|
||||
private final boolean asynchronous;
|
||||
|
||||
private final Long timeout;
|
||||
|
||||
/**
|
||||
* @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)
|
||||
*/
|
||||
public ChannelAccessPut(Channel<E> channel, E value, boolean asynchronous, Long timeout){
|
||||
|
||||
this.channel = channel;
|
||||
this.value = value;
|
||||
this.asynchronous = asynchronous;
|
||||
this.timeout = timeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Additional constructor for convenience. This constructor defaults the operation type to synchronous put.
|
||||
* @param channel
|
||||
* @param value Value to set
|
||||
*/
|
||||
public ChannelAccessPut(Channel<E> channel, E value){
|
||||
this(channel, value, false, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws RuntimeException Cannot set value on channel
|
||||
*/
|
||||
@Override
|
||||
public void execute() throws InterruptedException {
|
||||
logger.finest("Put to channel: "+channel.getName()+ " asynchronous: "+asynchronous);
|
||||
try{
|
||||
if(asynchronous){
|
||||
channel.setValueNoWait(value);
|
||||
}
|
||||
else{
|
||||
if(timeout==null){
|
||||
channel.setValue(value);
|
||||
}
|
||||
else{
|
||||
channel.setValueAsync(value).get(timeout, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
}
|
||||
} catch (ExecutionException | TimeoutException | ChannelException e) {
|
||||
throw new RuntimeException("Unable to set channel [name:"+channel.getName()+"] to value "+value, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void abort() {
|
||||
}
|
||||
}
|
||||
@@ -1,52 +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 ch.psi.fda.core.Action;
|
||||
|
||||
/**
|
||||
* Wait a specific time until executing the next action ...
|
||||
*/
|
||||
public class Delay implements Action {
|
||||
|
||||
private final long time;
|
||||
|
||||
/**
|
||||
* @param time Time to wait in milliseconds
|
||||
*/
|
||||
public Delay(long time){
|
||||
|
||||
// Check if delay time is positive and >0
|
||||
if(time<=0){
|
||||
throw new IllegalArgumentException("Wait time must be >0");
|
||||
}
|
||||
|
||||
this.time = time;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() throws InterruptedException {
|
||||
Thread.sleep(time);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void abort() {
|
||||
}
|
||||
}
|
||||
@@ -1,142 +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.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptEngineManager;
|
||||
import javax.script.ScriptException;
|
||||
|
||||
import ch.psi.fda.core.Action;
|
||||
|
||||
/**
|
||||
* Executes a python script inside a Jython interpreter
|
||||
*/
|
||||
public class JythonAction implements Action {
|
||||
|
||||
private static Logger logger = Logger.getLogger(JythonAction.class.getName());
|
||||
|
||||
/**
|
||||
* Pattern of the entry function of the jython script
|
||||
*/
|
||||
private static final String entryFunction = "process";
|
||||
private static final String entryFunctionPattern = "def "+entryFunction+"\\((.*)\\):";
|
||||
|
||||
private ScriptEngine engine;
|
||||
|
||||
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){
|
||||
|
||||
this.globalObjects = globalObjects;
|
||||
|
||||
// Workaround for Jython memory leak
|
||||
// http://blog.hillbrecht.de/2009/07/11/jython-memory-leakout-of-memory-problem/
|
||||
System.setProperty("python.options.internalTablesImpl","weak");
|
||||
|
||||
// Create new script engine
|
||||
this.engine = new ScriptEngineManager().getEngineByName("python");
|
||||
|
||||
// Determine script entry function and the function parameters
|
||||
Pattern pattern = Pattern.compile(entryFunctionPattern);
|
||||
Matcher matcher = pattern.matcher(script);
|
||||
String[] functionParameters = null;
|
||||
if(matcher.find() && matcher.groupCount()==1){
|
||||
logger.finest("Entry function '"+entryFunctionPattern+"' found - Identified parameters: "+matcher.group(1));
|
||||
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);
|
||||
}
|
||||
|
||||
// Check whether all function parameters have a mapping
|
||||
for(int i=0;i<functionParameters.length; i++){
|
||||
String p = functionParameters[i];
|
||||
p = p.trim();
|
||||
boolean found = false;
|
||||
for(String pm: mapping.keySet()){
|
||||
if(pm.equals(p)){
|
||||
found=true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!found){
|
||||
throw new IllegalArgumentException("No mapping compontent found for parameter "+p);
|
||||
}
|
||||
}
|
||||
|
||||
// Check whether more mappings are specified than function parameters
|
||||
if(functionParameters.length<mapping.size()){
|
||||
throw new IllegalArgumentException("More mappings than function parameters are specified");
|
||||
}
|
||||
|
||||
// Load manipulation script
|
||||
try {
|
||||
engine.eval(script);
|
||||
} catch (ScriptException e) {
|
||||
throw new RuntimeException("Unable to load manipulation script", e);
|
||||
}
|
||||
|
||||
for(String b: mapping.keySet()){
|
||||
// Assign channel bean to variable
|
||||
engine.put(b, mapping.get(b));
|
||||
}
|
||||
}
|
||||
|
||||
@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+"\n");
|
||||
} catch (ScriptException e) {
|
||||
throw new RuntimeException("Action failed while executing the Jython script",e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void abort() {
|
||||
}
|
||||
}
|
||||
@@ -1,133 +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.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import ch.psi.fda.core.Action;
|
||||
|
||||
/**
|
||||
* Action that executes a specified command when it is executed.
|
||||
*/
|
||||
public class ShellAction implements Action{
|
||||
|
||||
private static Logger logger = Logger.getLogger(ShellAction.class.getName());
|
||||
|
||||
private volatile Process process;
|
||||
private volatile boolean abort = false;
|
||||
private boolean checkExitValue = true;
|
||||
private int exitValue = 0;
|
||||
|
||||
/**
|
||||
* Name (full path if it is not in the system path) of the script to execute when
|
||||
* the execute() function of this action is invoked.
|
||||
*/
|
||||
private final String script;
|
||||
|
||||
/**
|
||||
* @param script Name of the command to execute when this action is invoked
|
||||
*
|
||||
* @throws IllegalArgumentException Specified script does not exist
|
||||
*/
|
||||
public ShellAction(String script){
|
||||
String[] scri = script.split("[ ,\t]");
|
||||
File s = new File(scri[0]);
|
||||
if(!s.exists()){
|
||||
throw new IllegalArgumentException("Script "+script+" does not exist.");
|
||||
}
|
||||
this.script = script;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() throws InterruptedException {
|
||||
try{
|
||||
abort = false;
|
||||
logger.fine("Execute script "+script);
|
||||
process = Runtime.getRuntime().exec(new String[]{"/bin/bash","-c",script});
|
||||
int exitVal = process.waitFor();
|
||||
|
||||
// Log output of the shell script if loglevel is finest
|
||||
if(logger.isLoggable(Level.FINEST)){
|
||||
logger.finest("STDOUT [BEGIN]");
|
||||
// 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){
|
||||
logger.finest(line);
|
||||
}
|
||||
logger.finest("STDOUT [END]");
|
||||
|
||||
logger.finest("STDERR [BEGIN]");
|
||||
// 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){
|
||||
logger.finest(line);
|
||||
}
|
||||
logger.finest("STDERR [END]");
|
||||
}
|
||||
|
||||
logger.fine("Script ["+script+"] return value: "+exitVal);
|
||||
|
||||
if(abort){
|
||||
throw new RuntimeException("Script ["+script+"] was aborted");
|
||||
}
|
||||
else{
|
||||
// Check script exit value to 0 if != 0 then throw an runtime exception
|
||||
if(checkExitValue && exitVal != exitValue){
|
||||
throw new RuntimeException("Script ["+script+"] returned with an exit value not equal to 0");
|
||||
}
|
||||
}
|
||||
process = null;
|
||||
}
|
||||
catch(IOException e){
|
||||
throw new RuntimeException("Unable to execute script: "+script,e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void abort() {
|
||||
abort=true;
|
||||
if(process!=null){
|
||||
process.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isCheckExitValue() {
|
||||
return checkExitValue;
|
||||
}
|
||||
|
||||
public void setCheckExitValue(boolean checkExitValue) {
|
||||
this.checkExitValue = checkExitValue;
|
||||
}
|
||||
|
||||
public int getExitValue() {
|
||||
return exitValue;
|
||||
}
|
||||
|
||||
public void setExitValue(int exitValue) {
|
||||
this.exitValue = exitValue;
|
||||
}
|
||||
}
|
||||
@@ -1,253 +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 java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import ch.psi.fda.core.Actor;
|
||||
import ch.psi.jcae.Channel;
|
||||
import ch.psi.jcae.ChannelException;
|
||||
|
||||
public class ChannelAccessFunctionActuator<T> implements Actor {
|
||||
|
||||
private static Logger logger = Logger.getLogger(ChannelAccessFunctionActuator.class.getName());
|
||||
|
||||
private boolean asynchronous = false;
|
||||
private double start;
|
||||
private double end;
|
||||
private double stepSize;
|
||||
private int direction; // Move direction (start<end = 1, start>end = -1)
|
||||
|
||||
/**
|
||||
* Execution count of actuator. This variable is used to minimize the floating point
|
||||
* rounding errors for calculating the next step.
|
||||
*/
|
||||
private int count;
|
||||
|
||||
/**
|
||||
* Flag that indicates whether there is a next set value for the Actor
|
||||
*/
|
||||
private boolean next;
|
||||
|
||||
/**
|
||||
* Value to set at next @see ch.psi.fda.engine.Actor#set() call
|
||||
*/
|
||||
private double value;
|
||||
|
||||
/**
|
||||
* Level of accuracy the positioner need to have (e.g. if a positioner is set to 1 the readback set value
|
||||
* of the positioner need to have at lease 1+/-accuracy)
|
||||
* Default is stepSize/2
|
||||
*/
|
||||
private double accuracy;
|
||||
|
||||
/**
|
||||
* Move timeout
|
||||
*/
|
||||
private Long timeout;
|
||||
|
||||
private final T doneValue;
|
||||
private final long doneDelay;
|
||||
|
||||
private final double originalStart;
|
||||
private final double originalEnd;
|
||||
private final int originalDirection;
|
||||
|
||||
private Channel<Double> channel;
|
||||
private Channel<T> doneChannel = null;
|
||||
|
||||
private final Function function;
|
||||
private boolean checkActorSet = true;
|
||||
|
||||
/**
|
||||
* Constructor - Initialize actor
|
||||
* @param channelName
|
||||
* @param start
|
||||
* @param end
|
||||
* @param stepSize
|
||||
* @param timeout Maximum move time (in milliseconds)
|
||||
*/
|
||||
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 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
|
||||
* @param end
|
||||
* @param stepSize
|
||||
* @param timeout Maximum move time (in milliseconds)
|
||||
*/
|
||||
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));
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
|
||||
if(stepSize <= 0){
|
||||
throw new IllegalArgumentException("Step size ["+stepSize+"] must be > 0");
|
||||
}
|
||||
this.stepSize = stepSize;
|
||||
|
||||
this.accuracy = stepSize/2;
|
||||
|
||||
// Validate and save timeout parameter
|
||||
if(timeout!=null && timeout<=0){
|
||||
throw new IllegalArgumentException("Timeout must be >0 or null");
|
||||
}
|
||||
else{
|
||||
this.timeout = timeout;
|
||||
}
|
||||
|
||||
if(function==null){
|
||||
throw new IllegalArgumentException("Function must not be null");
|
||||
}
|
||||
this.function = function;
|
||||
|
||||
|
||||
init();
|
||||
|
||||
// Save original settings
|
||||
this.originalStart = start;
|
||||
this.originalEnd = end;
|
||||
this.originalDirection = direction;
|
||||
|
||||
this.channel = channel;
|
||||
this.doneChannel = doneChannel;
|
||||
}
|
||||
|
||||
@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.");
|
||||
}
|
||||
|
||||
// Set actuator channel
|
||||
logger.finest("Set actuator channel "+channel.getName()+" to value: "+value);
|
||||
try {
|
||||
double fvalue = function.calculate(value);
|
||||
|
||||
if(!asynchronous){
|
||||
if(timeout==null){
|
||||
channel.setValue(fvalue);
|
||||
}
|
||||
else{
|
||||
channel.setValueAsync(fvalue).get(timeout, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
}
|
||||
else{
|
||||
channel.setValueNoWait(fvalue);
|
||||
}
|
||||
|
||||
if(doneChannel != null){
|
||||
Thread.sleep(doneDelay);
|
||||
doneChannel.waitForValue(doneValue);
|
||||
}
|
||||
|
||||
// Check whether the set value is really on the value that was set before.
|
||||
if(checkActorSet){
|
||||
double c = channel.getValue(true);
|
||||
double a = Math.abs( c - fvalue );
|
||||
if ( a > accuracy ){
|
||||
throw new RuntimeException("Actor could not be set to the value "+fvalue+" The readback of the set value does not match the value that was set [value: "+c+" delta: "+a+" accuracy: "+accuracy+"]");
|
||||
}
|
||||
}
|
||||
|
||||
} catch (ExecutionException | TimeoutException | ChannelException e) {
|
||||
throw new RuntimeException("Unable to move actuator [channel: "+channel.getName()+"] to value "+value,e);
|
||||
}
|
||||
|
||||
|
||||
count++;
|
||||
double nextValue = start+(count*stepSize*direction); // Done like this to keep floating point rounding errors minimal
|
||||
|
||||
if((direction==1&&nextValue<=end)||(direction==-1&nextValue>=end)){
|
||||
|
||||
// Apply function
|
||||
// nextValue = function.calculate(nextValue);
|
||||
|
||||
logger.fine("Next actor value: "+nextValue);
|
||||
value=nextValue;
|
||||
this.next = true;
|
||||
}
|
||||
else{
|
||||
// There is no next set value
|
||||
this.next = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return next;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
this.count = 0;
|
||||
|
||||
// Determine move direction
|
||||
this.direction = 1;
|
||||
if(start>end){
|
||||
direction=-1; // Move in negative direction
|
||||
}
|
||||
|
||||
// Set first set value to the start value
|
||||
this.value = start;
|
||||
this.next = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void reverse() {
|
||||
double oldStart = start;
|
||||
this.start = this.end;
|
||||
this.end = oldStart;
|
||||
|
||||
// Determine move direction
|
||||
this.direction = 1;
|
||||
if(this.start>this.end){
|
||||
direction=-1; // Move in negative direction
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
this.start = this.originalStart;
|
||||
this.end = this.originalEnd;
|
||||
this.direction = this.originalDirection;
|
||||
}
|
||||
|
||||
public boolean isAsynchronous() {
|
||||
return asynchronous;
|
||||
}
|
||||
public void setAsynchronous(boolean asynchronous) {
|
||||
this.asynchronous = asynchronous;
|
||||
}
|
||||
}
|
||||
@@ -1,234 +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 java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import ch.psi.fda.core.Actor;
|
||||
import ch.psi.jcae.Channel;
|
||||
import ch.psi.jcae.ChannelException;
|
||||
|
||||
/**
|
||||
* This actuator sets an Channel Access channel from a start to an end value by doing discrete steps.
|
||||
*/
|
||||
public class ChannelAccessLinearActuator<T> implements Actor {
|
||||
|
||||
private static Logger logger = Logger.getLogger(ChannelAccessLinearActuator.class.getName());
|
||||
|
||||
private boolean asynchronous = false;
|
||||
|
||||
private double start;
|
||||
private double end;
|
||||
private double stepSize;
|
||||
private int direction;
|
||||
|
||||
/**
|
||||
* Execution count of actuator. This variable is used to minimize the floating point
|
||||
* rounding errors for calculating the next step.
|
||||
*/
|
||||
private int count;
|
||||
|
||||
/**
|
||||
* Flag that indicates whether there is a next set value for the Actor
|
||||
*/
|
||||
private boolean next;
|
||||
|
||||
/**
|
||||
* Value to set at next @see ch.psi.fda.engine.Actor#set() call
|
||||
*/
|
||||
private double value;
|
||||
|
||||
/**
|
||||
* Level of accuracy the positioner need to have (e.g. if a positioner is set to 1 the readback set value
|
||||
* of the positioner need to have at lease 1+/-accuracy)
|
||||
* Default is stepSize/2
|
||||
*/
|
||||
private double accuracy;
|
||||
|
||||
|
||||
|
||||
private final T doneValue;
|
||||
private final long doneDelay;
|
||||
|
||||
private final double originalStart;
|
||||
private final double originalEnd;
|
||||
private final int originalDirection;
|
||||
|
||||
private Long timeout; // Set timeout
|
||||
|
||||
private final Channel<Double> channel;
|
||||
private final Channel<T> doneChannel;
|
||||
|
||||
private boolean checkActorSet = true;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @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
|
||||
* @param end
|
||||
* @param stepSize
|
||||
* @param timeout Maximum move time (in milliseconds)
|
||||
*/
|
||||
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));
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
|
||||
if(stepSize <= 0){
|
||||
throw new IllegalArgumentException("Step size ["+stepSize+"] must be > 0");
|
||||
}
|
||||
this.stepSize = stepSize;
|
||||
|
||||
this.accuracy = stepSize/2;
|
||||
|
||||
// Validate and save timeout parameter
|
||||
if(timeout!=null && timeout<=0){
|
||||
throw new IllegalArgumentException("Timeout must be >0 or null");
|
||||
}
|
||||
else{
|
||||
this.timeout = timeout;
|
||||
}
|
||||
|
||||
|
||||
init();
|
||||
|
||||
// Save original settings
|
||||
this.originalStart = start;
|
||||
this.originalEnd = end;
|
||||
this.originalDirection = direction;
|
||||
|
||||
this.channel = channel;
|
||||
this.doneChannel = doneChannel;
|
||||
}
|
||||
|
||||
@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.");
|
||||
}
|
||||
|
||||
// Set actuator channel
|
||||
logger.finest("Set actuator channel "+channel.getName()+" to value: "+value);
|
||||
try {
|
||||
|
||||
if(!asynchronous){
|
||||
if(timeout==null){
|
||||
channel.setValue(value);
|
||||
}
|
||||
else{
|
||||
channel.setValueAsync(value).get(timeout, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
}
|
||||
else{
|
||||
channel.setValueNoWait(value);
|
||||
}
|
||||
|
||||
if(doneChannel != null){
|
||||
Thread.sleep(doneDelay);
|
||||
doneChannel.waitForValue(doneValue);
|
||||
}
|
||||
|
||||
// Check whether the set value is really on the value that was set before.
|
||||
if(checkActorSet){
|
||||
double c = channel.getValue(true);
|
||||
double a = Math.abs( c - value );
|
||||
if ( a > accuracy ){
|
||||
throw new RuntimeException("Actor could not be set to the value "+value+" The readback of the set value does not match the value that was set [value: "+c+" delta: "+a+" accuracy: "+accuracy+"]");
|
||||
}
|
||||
}
|
||||
|
||||
} catch (ExecutionException | TimeoutException | ChannelException e) {
|
||||
throw new RuntimeException("Unable to move actuator [channel: "+channel.getName()+"] to value "+value,e);
|
||||
}
|
||||
|
||||
|
||||
count++;
|
||||
double nextValue = start+(count*stepSize*direction); // Done like this to keep floating point rounding errors minimal
|
||||
|
||||
if((direction==1&&nextValue<=end)||(direction==-1&nextValue>=end)){
|
||||
logger.fine("Next actor value: "+nextValue);
|
||||
value=nextValue;
|
||||
this.next = true;
|
||||
}
|
||||
else{
|
||||
// There is no next set value
|
||||
this.next = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return next;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
this.count = 0;
|
||||
|
||||
// Determine move direction
|
||||
this.direction = 1;
|
||||
if(start>end){
|
||||
direction=-1; // Move in negative direction
|
||||
}
|
||||
|
||||
|
||||
// Set first set value to the start value
|
||||
this.value = start;
|
||||
this.next = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void reverse() {
|
||||
double oldStart = start;
|
||||
this.start = this.end;
|
||||
this.end = oldStart;
|
||||
|
||||
// Determine move direction
|
||||
this.direction = 1;
|
||||
if(this.start>this.end){
|
||||
direction=-1; // Move in negative direction
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
this.start = this.originalStart;
|
||||
this.end = this.originalEnd;
|
||||
this.direction = this.originalDirection;
|
||||
}
|
||||
|
||||
public boolean isAsynchronous() {
|
||||
return asynchronous;
|
||||
}
|
||||
public void setAsynchronous(boolean asynchronous) {
|
||||
this.asynchronous = asynchronous;
|
||||
}
|
||||
}
|
||||
@@ -1,238 +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 java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import ch.psi.fda.core.Actor;
|
||||
import ch.psi.jcae.Channel;
|
||||
import ch.psi.jcae.ChannelException;
|
||||
|
||||
/**
|
||||
* This actuator sets an Channel Access channel by using the positions from the given table.
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
public class ChannelAccessTableActuator<T> implements Actor {
|
||||
|
||||
private static Logger logger = Logger.getLogger(ChannelAccessTableActuator.class.getName());
|
||||
|
||||
private boolean asynchronous = false;
|
||||
|
||||
/**
|
||||
* Position table
|
||||
*/
|
||||
private final double[] table;
|
||||
|
||||
/**
|
||||
* Level of accuracy the positioner need to have (e.g. if a positioner is set to 1 the readback set value
|
||||
* of the positioner need to have at lease 1+/-accuracy)
|
||||
*/
|
||||
private double accuracy = 0.1;
|
||||
|
||||
/**
|
||||
* Execution count of actuator. This variable is used to minimize the floating point
|
||||
* rounding errors for calculating the next step.
|
||||
*/
|
||||
private int count;
|
||||
|
||||
/**
|
||||
* Flag that indicates whether there is a next set value for the Actor
|
||||
*/
|
||||
private boolean next;
|
||||
|
||||
|
||||
private Channel<Double> channel;
|
||||
private Channel<T> doneChannel = null;
|
||||
|
||||
private final T doneValue;
|
||||
private final long doneDelay;
|
||||
|
||||
/**
|
||||
* Flag that indicates whether the actor moves in the positive direction
|
||||
*/
|
||||
private boolean positiveDirection = true;
|
||||
private final boolean originalPositiveDirection;
|
||||
|
||||
/**
|
||||
* Maximum move time (in milliseconds)
|
||||
*/
|
||||
private Long timeout = null;
|
||||
|
||||
private boolean checkActorSet = true;
|
||||
|
||||
/**
|
||||
* Constructor - Initialize actor
|
||||
* @param channelName Name of the channel to set
|
||||
* @param table Position table with the explicit positions for each step
|
||||
* @param timeout Maximum move time (in milliseconds)
|
||||
*/
|
||||
public ChannelAccessTableActuator(Channel<Double> channel, double[] table, Long timeout){
|
||||
this(channel, null, null, 0, table, timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param channel
|
||||
* @param doneChannel
|
||||
* @param doneValue
|
||||
* @param doneDelay
|
||||
* @param table
|
||||
* @param timeout Maximum move time (in milliseconds)
|
||||
*/
|
||||
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));
|
||||
|
||||
if(table==null){
|
||||
throw new IllegalArgumentException("Null table is not accepted");
|
||||
}
|
||||
if(table.length==0){
|
||||
throw new IllegalArgumentException("Position table need to have at least one position");
|
||||
}
|
||||
|
||||
this.table = table;
|
||||
|
||||
// Validate and save timeout parameter
|
||||
if(timeout!=null && timeout<=0){
|
||||
throw new IllegalArgumentException("Timeout must be >0 or null");
|
||||
}
|
||||
else{
|
||||
this.timeout = timeout;
|
||||
}
|
||||
|
||||
init();
|
||||
|
||||
// Save the initial direction
|
||||
this.originalPositiveDirection = positiveDirection;
|
||||
|
||||
this.channel = channel;
|
||||
this.doneChannel = doneChannel;
|
||||
}
|
||||
|
||||
@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.");
|
||||
}
|
||||
|
||||
// Set actuator channel
|
||||
logger.finest("Set actuator channel "+channel.getName()+" to value: "+table[count]);
|
||||
try {
|
||||
if(!asynchronous){
|
||||
if(timeout==null){
|
||||
channel.setValue(table[count]);
|
||||
}
|
||||
else{
|
||||
channel.setValueAsync(table[count]).get(timeout, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
}
|
||||
else{
|
||||
channel.setValueNoWait(table[count]);
|
||||
}
|
||||
|
||||
|
||||
if(doneChannel != null){
|
||||
Thread.sleep(doneDelay);
|
||||
doneChannel.waitForValue(doneValue);
|
||||
}
|
||||
|
||||
// Check whether the set value is really on the value that was set before.
|
||||
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 (ExecutionException | ChannelException | TimeoutException e) {
|
||||
throw new RuntimeException("Move actuator [channel: "+channel.getName()+"] to value "+table[count],e);
|
||||
}
|
||||
|
||||
if(positiveDirection){
|
||||
count++;
|
||||
if(count<table.length){
|
||||
this.next = true;
|
||||
}
|
||||
else{
|
||||
// There is no next set value
|
||||
this.next = false;
|
||||
}
|
||||
}
|
||||
else{
|
||||
count--;
|
||||
if(count>=0){
|
||||
this.next = true;
|
||||
}
|
||||
else{
|
||||
// There is no next set value
|
||||
this.next = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return next;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
|
||||
// Set first set value to the start value
|
||||
if(positiveDirection){
|
||||
this.count = 0; // Set count to the first element
|
||||
}
|
||||
else{
|
||||
this.count = table.length-1; // Set count to the last element
|
||||
}
|
||||
|
||||
if(table.length>0){
|
||||
this.next = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reverse() {
|
||||
if(positiveDirection){
|
||||
positiveDirection=false;
|
||||
}
|
||||
else{
|
||||
positiveDirection=true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
this.positiveDirection = this.originalPositiveDirection;
|
||||
}
|
||||
|
||||
public boolean isAsynchronous() {
|
||||
return asynchronous;
|
||||
}
|
||||
public void setAsynchronous(boolean asynchronous) {
|
||||
this.asynchronous = asynchronous;
|
||||
}
|
||||
}
|
||||
@@ -1,201 +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 java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import ch.psi.fda.core.Action;
|
||||
import ch.psi.fda.core.Actor;
|
||||
|
||||
/**
|
||||
* Complex actuator that consists of a list of other actuators. The steps of this actor are composed out of the
|
||||
* 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.
|
||||
*/
|
||||
public class ComplexActuator implements Actor {
|
||||
|
||||
private static Logger logger = Logger.getLogger(ComplexActuator.class.getName());
|
||||
|
||||
/**
|
||||
* List of actors this actor is made of
|
||||
*/
|
||||
private final List<Actor> actors;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Flag that indicates whether there is a next set value for the Actor
|
||||
*/
|
||||
private boolean next;
|
||||
|
||||
/**
|
||||
* Index of the actor currently used
|
||||
*/
|
||||
private int actualActorCount;
|
||||
|
||||
/**
|
||||
* Actor currently used to perform steps
|
||||
*/
|
||||
private Actor actualActor;
|
||||
|
||||
/**
|
||||
* Flag to indicate the first set() execution of this actor.
|
||||
* This flag is used to decide whether to execute the pre actions.
|
||||
*/
|
||||
private boolean firstrun;
|
||||
|
||||
public ComplexActuator(){
|
||||
this.actors = new ArrayList<Actor>();
|
||||
this.preActions = new ArrayList<Action>();
|
||||
this.postActions = new ArrayList<Action>();
|
||||
|
||||
this.next = false;
|
||||
this.actualActorCount = 0;
|
||||
|
||||
this.firstrun = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set() throws InterruptedException {
|
||||
if(!next){
|
||||
throw new IllegalStateException("The actuator does not have any next step.");
|
||||
}
|
||||
|
||||
// PRE actions
|
||||
if(firstrun){
|
||||
this.firstrun = false;
|
||||
|
||||
// Execute pre actions
|
||||
logger.finest("Execute pre actions");
|
||||
for(Action action: preActions){
|
||||
action.execute();
|
||||
}
|
||||
}
|
||||
|
||||
actualActor.set(); // If the actor has no next step then something is wrong in the init/next step logic
|
||||
|
||||
// If the last point of the actual actuator is set take the next actuator in the list if there is one available
|
||||
while(!actualActor.hasNext()&&actualActorCount<actors.size()){
|
||||
actualActorCount++;
|
||||
if(actualActorCount<actors.size()){
|
||||
actualActor = actors.get(actualActorCount);
|
||||
}
|
||||
else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(actualActor.hasNext()){
|
||||
this.next = true;
|
||||
}
|
||||
else{
|
||||
this.next = false;
|
||||
|
||||
// Execute post actions
|
||||
logger.finest("Execute post actions");
|
||||
for(Action action: postActions){
|
||||
action.execute();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return next;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
// Initialize all actors this actor consist of
|
||||
for(Actor a: actors){
|
||||
a.init();
|
||||
}
|
||||
|
||||
// Set the actual actor to the first actor in the list
|
||||
actualActorCount=0;
|
||||
if(actualActorCount<actors.size()){
|
||||
actualActor = actors.get(actualActorCount);
|
||||
|
||||
// Check whether the actor has a next step, if not increase to the next one
|
||||
// This is needed because the first actor might not have any step ... (very unlikely but bad things happens some time)
|
||||
while(!actualActor.hasNext()&&actualActorCount<actors.size()){
|
||||
actualActorCount++;
|
||||
if(actualActorCount<actors.size()){
|
||||
actualActor = actors.get(actualActorCount);
|
||||
}
|
||||
else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(actualActor.hasNext()){
|
||||
this.next = true;
|
||||
}
|
||||
else{
|
||||
this.next = false;
|
||||
}
|
||||
|
||||
}
|
||||
else{
|
||||
actualActor=null;
|
||||
this.next=false;
|
||||
}
|
||||
|
||||
this.firstrun = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reverse() {
|
||||
// Reverse all actors this actor consist of
|
||||
for(Actor a: actors){
|
||||
a.reverse();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
// Reset all actors this actor consist of
|
||||
for(Actor a: actors){
|
||||
a.reset();
|
||||
}
|
||||
}
|
||||
|
||||
public List<Action> getPreActions() {
|
||||
return preActions;
|
||||
}
|
||||
public List<Actor> getActors() {
|
||||
return actors;
|
||||
}
|
||||
public List<Action> getPostActions() {
|
||||
return postActions;
|
||||
}
|
||||
}
|
||||
@@ -1,24 +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;
|
||||
|
||||
public interface Function {
|
||||
public double calculate(double parameter);
|
||||
}
|
||||
@@ -1,106 +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 java.util.Map;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptEngineManager;
|
||||
import javax.script.ScriptException;
|
||||
|
||||
import ch.psi.fda.core.scripting.JythonGlobalVariable;
|
||||
|
||||
public class JythonFunction implements Function {
|
||||
|
||||
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+"\\((.*)\\):";
|
||||
|
||||
private ScriptEngine engine;
|
||||
private String additionalParameter = "";
|
||||
|
||||
|
||||
public JythonFunction(String script, Map<String, JythonGlobalVariable> map){
|
||||
|
||||
// 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
|
||||
String[] parameter;
|
||||
Pattern pattern = Pattern.compile(ENTRY_FUNCTION_PATTERN);
|
||||
Matcher matcher = pattern.matcher(script);
|
||||
if(matcher.find() && matcher.groupCount()==1){
|
||||
if(!matcher.group(1).trim().equals("")){
|
||||
logger.finest("Entry function '"+ENTRY_FUNCTION_PATTERN+"' found - Identified parameters: "+matcher.group(1));
|
||||
parameter = matcher.group(1).split(" *, *");
|
||||
}
|
||||
else{
|
||||
parameter = new String[0];
|
||||
}
|
||||
}
|
||||
else{
|
||||
throw new IllegalArgumentException("Cannot determine entry function: "+ENTRY_FUNCTION_PATTERN);
|
||||
}
|
||||
|
||||
// Check whether all parameters are mapped
|
||||
StringBuilder b = new StringBuilder();
|
||||
for(int i=1;i<parameter.length; i++){ // Starting at 1 because first argument is implicit.
|
||||
if(!map.containsKey(parameter[i])){
|
||||
throw new IllegalArgumentException("Function parameter "+parameter[i]+" is not mapped");
|
||||
}
|
||||
b.append(",");
|
||||
b.append(parameter[i]);
|
||||
}
|
||||
additionalParameter = b.toString();
|
||||
|
||||
// Set variables in Jython engine
|
||||
for(String k: map.keySet()){
|
||||
engine.put(k, map.get(k));
|
||||
}
|
||||
|
||||
// Load manipulation script
|
||||
try {
|
||||
engine.eval(script);
|
||||
} catch (ScriptException e) {
|
||||
throw new RuntimeException("Unable to load manipulation script", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public double calculate(double parameter) {
|
||||
logger.fine("Function called");
|
||||
|
||||
try {
|
||||
logger.info("calculate( "+parameter+""+additionalParameter+" )");
|
||||
return ((Double) engine.eval("calculate( "+parameter+""+additionalParameter+" )"));
|
||||
} catch (ScriptException e) {
|
||||
throw new RuntimeException("Calculating actuator step failed while executing the Jython script",e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,93 +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;
|
||||
import ch.psi.fda.core.Sensor;
|
||||
|
||||
/**
|
||||
* Pseudo actor that is literally doing nothing for n times
|
||||
*/
|
||||
public class PseudoActuatorSensor implements Actor, Sensor {
|
||||
|
||||
/**
|
||||
* Execution count of actuator.
|
||||
*/
|
||||
private int count;
|
||||
|
||||
/**
|
||||
* Number of counts for this actuator
|
||||
*/
|
||||
private final int counts;
|
||||
|
||||
private final String id;
|
||||
|
||||
/**
|
||||
* @param counts
|
||||
* @param id Id of the Actor/Sensor
|
||||
*/
|
||||
public PseudoActuatorSensor(String id, int counts){
|
||||
if(counts < 1){
|
||||
throw new IllegalArgumentException("Count ["+counts+"] must be > 0");
|
||||
}
|
||||
this.id = id;
|
||||
this.counts = counts;
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void set() {
|
||||
if(!hasNext()){
|
||||
throw new IllegalStateException("The actuator does not have any next step.");
|
||||
}
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return (count<counts);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
count=0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reverse() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object read() {
|
||||
return new Double(count); // Return actual count
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return this.id;
|
||||
}
|
||||
}
|
||||
@@ -1,89 +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.guard;
|
||||
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import ch.psi.fda.core.Guard;
|
||||
import ch.psi.jcae.ChannelException;
|
||||
|
||||
/**
|
||||
* Guard checking channels to meet a certain condition
|
||||
*/
|
||||
public class ChannelAccessGuard implements Guard {
|
||||
|
||||
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 volatile boolean check = true;
|
||||
|
||||
private final List<ChannelAccessGuardCondition<?>> conditions;
|
||||
|
||||
public ChannelAccessGuard(List<ChannelAccessGuardCondition<?>> conditions){
|
||||
|
||||
this.conditions = conditions;
|
||||
|
||||
for(final ChannelAccessGuardCondition<?> condition: conditions){
|
||||
condition.getChannel().addPropertyChangeListener(new PropertyChangeListener() {
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
if(! evt.getNewValue().equals(condition.getValue())){
|
||||
check=false;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
check = true;
|
||||
|
||||
// Check one time if all conditions are met
|
||||
for(ChannelAccessGuardCondition<?> condition: conditions){
|
||||
try{
|
||||
if(! (condition.getChannel().getValue(true)).equals(condition.getValue()) ){
|
||||
check=false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
throw new RuntimeException("Guard interrupted ",e);
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
logger.log(Level.WARNING, "Unable ", e);
|
||||
check=false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean check() {
|
||||
return check;
|
||||
}
|
||||
}
|
||||
@@ -1,41 +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.guard;
|
||||
|
||||
import ch.psi.jcae.Channel;
|
||||
|
||||
public class ChannelAccessGuardCondition<T> {
|
||||
|
||||
private final Channel<T> channel;
|
||||
private final T value; // Value of the channel to meet condition
|
||||
|
||||
public ChannelAccessGuardCondition(Channel<T> channel, T value){
|
||||
this.channel = channel;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public Channel<T> getChannel() {
|
||||
return channel;
|
||||
}
|
||||
|
||||
public T getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -1,436 +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.loops;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
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.messages.DataMessage;
|
||||
import ch.psi.fda.messages.EndOfStreamMessage;
|
||||
import ch.psi.fda.messages.Metadata;
|
||||
|
||||
/**
|
||||
* Loop of actions to accomplish a task or test.
|
||||
*/
|
||||
public class ActorSensorLoop implements ActionLoop {
|
||||
|
||||
private static Logger logger = Logger.getLogger(ActorSensorLoop.class.getName());
|
||||
|
||||
/**
|
||||
* Flag to indicate whether the data of this loop will be grouped
|
||||
* According to this flag the dataGroup flag in EndOfStream will be set.
|
||||
*/
|
||||
private boolean dataGroup = false;
|
||||
|
||||
/**
|
||||
* List of additional action loops that are executed at the end of each
|
||||
* iteration of the loop
|
||||
*/
|
||||
private List<ActionLoop> actionLoops;
|
||||
/**
|
||||
* List of actions that are executed at the beginning of the loop.
|
||||
*/
|
||||
private List<Action> preActions;
|
||||
/**
|
||||
* List of actions that are executed at the end of the loop.
|
||||
*/
|
||||
private List<Action> postActions;
|
||||
|
||||
/**
|
||||
* List of actions that are executed before the actors are set
|
||||
*/
|
||||
private List<Action> preActorActions;
|
||||
|
||||
/**
|
||||
* List of actions that are executed after all actors have been set
|
||||
*/
|
||||
private List<Action> postActorActions;
|
||||
|
||||
/**
|
||||
* List of actions that are executed before the sensors are read out
|
||||
*/
|
||||
private List<Action> preSensorActions;
|
||||
/**
|
||||
* List of actions that are executed after all sensors have been read out
|
||||
*/
|
||||
private List<Action> postSensorActions;
|
||||
|
||||
/**
|
||||
* List of actors of this loop
|
||||
*/
|
||||
private List<Actor> actors;
|
||||
|
||||
/**
|
||||
* List of sensors of this loop
|
||||
*/
|
||||
private List<Sensor> sensors;
|
||||
|
||||
/**
|
||||
* Guard used to check whether the environment was ok while reading out the sensors
|
||||
*/
|
||||
private Guard guard = null;
|
||||
|
||||
private volatile boolean loop = false;
|
||||
private volatile boolean abort = false;
|
||||
|
||||
private final boolean zigZag;
|
||||
|
||||
private List<ActorSetCallable> pactors;
|
||||
|
||||
private EventBus eventBus = new EventBus();
|
||||
|
||||
|
||||
public ActorSensorLoop(){
|
||||
this(false);
|
||||
}
|
||||
|
||||
public ActorSensorLoop(boolean zigZag){
|
||||
this.zigZag = zigZag;
|
||||
this.actionLoops = new ArrayList<ActionLoop>();
|
||||
this.preActions = new ArrayList<Action>();
|
||||
this.postActions = new ArrayList<Action>();
|
||||
this.preActorActions = new ArrayList<Action>();
|
||||
this.postActorActions = new ArrayList<Action>();
|
||||
this.preSensorActions = new ArrayList<Action>();
|
||||
this.postSensorActions = new ArrayList<Action>();
|
||||
|
||||
this.actors = new ArrayList<Actor>();
|
||||
this.pactors = new ArrayList<ActorSetCallable>();
|
||||
this.sensors = new ArrayList<Sensor>();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Executes the actor sensor loop. The actor sensor loop is build up as follows:
|
||||
* preActions
|
||||
* loop{
|
||||
* check actors - abort if there are no new steps
|
||||
* pre actor actions
|
||||
* set actors
|
||||
* post actor actions
|
||||
* pre sensor actions
|
||||
* read sensors
|
||||
* post sensor actions
|
||||
* execute additional registered action loops
|
||||
* }
|
||||
* postActions
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
@Override
|
||||
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
|
||||
*/
|
||||
ExecutorService executorService = Executors.newCachedThreadPool();
|
||||
|
||||
loop = true;
|
||||
|
||||
// Execute pre actions
|
||||
for(Action action: preActions){
|
||||
action.execute();
|
||||
}
|
||||
|
||||
// Initialize actors of Loop
|
||||
for(Actor actor: actors){
|
||||
actor.init();
|
||||
}
|
||||
|
||||
// Variable to store the last guard status
|
||||
boolean guardOK=true;
|
||||
|
||||
try{
|
||||
|
||||
// Execute loop logic
|
||||
while(loop){
|
||||
|
||||
if(guardOK){
|
||||
|
||||
|
||||
// If actors are defined for the loop check whether all of them
|
||||
// have a next step defined if there is no actor defined only run this loop once
|
||||
if(actors.size()>0){
|
||||
// Check whether the actors of this loop have a next step. If not
|
||||
// abort the loop
|
||||
boolean hasNext = true;
|
||||
for(Actor actor: actors){
|
||||
if(!actor.hasNext()){
|
||||
hasNext=false;
|
||||
break; // Stop actor check loop
|
||||
}
|
||||
}
|
||||
|
||||
// If not all actors have a next step abort the loop
|
||||
if(!hasNext){
|
||||
break; // Stop action loop
|
||||
}
|
||||
}
|
||||
else{
|
||||
// No actors defined, only run loop once
|
||||
loop = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Execute pre actor actions
|
||||
for(Action action: preActorActions){
|
||||
action.execute();
|
||||
}
|
||||
|
||||
if(abort){ // End loop if abort was issued
|
||||
break;
|
||||
}
|
||||
|
||||
// Set actors
|
||||
// for(Actor actor: actors){
|
||||
// actor.set();
|
||||
// }
|
||||
// Parallel set of the actors
|
||||
try {
|
||||
for (Future<Object> f : executorService.invokeAll(pactors)) {
|
||||
f.get(); //Blocks until the async set() is finished
|
||||
}
|
||||
} catch (ExecutionException e) {
|
||||
throw new RuntimeException("Setting the actors failed",e);
|
||||
}
|
||||
|
||||
// Execute post actor actions
|
||||
for(Action action: postActorActions){
|
||||
action.execute();
|
||||
}
|
||||
|
||||
if(abort){ // End loop if abort was issued
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(guard!=null){
|
||||
// Initialize guard
|
||||
guard.init();
|
||||
guardOK=guard.check();
|
||||
|
||||
// Wait until guard is ok
|
||||
while(!guardOK){
|
||||
logger.info("Waiting for guard condition(s) to be met");
|
||||
// Sleep 100 milliseconds before next check
|
||||
Thread.sleep(1000);
|
||||
|
||||
// Check whether the loop is not aborted, if it is aborted
|
||||
// break the wait loop (afterwards also the loop loop is aborted)
|
||||
if(!loop){
|
||||
break;
|
||||
}
|
||||
|
||||
guard.init();
|
||||
guardOK=guard.check();
|
||||
}
|
||||
|
||||
// If loop is aborted proceed to next iteration an abort loop
|
||||
if(!loop){
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Execute pre sensor actions
|
||||
for(Action action: preSensorActions){
|
||||
action.execute();
|
||||
}
|
||||
|
||||
if(abort){ // End loop if abort was issued
|
||||
break;
|
||||
}
|
||||
|
||||
// Read sensors
|
||||
DataMessage message = new DataMessage(metadata);
|
||||
for(Sensor sensor: sensors){
|
||||
// Readout sensor
|
||||
Object o = sensor.read();
|
||||
// Add sensor data item to message
|
||||
message.getData().add(o);
|
||||
}
|
||||
|
||||
// Execute post sensor actions
|
||||
for(Action action: postSensorActions){
|
||||
action.execute();
|
||||
}
|
||||
|
||||
if(abort){ // End loop if abort was issued
|
||||
break;
|
||||
}
|
||||
|
||||
// Check guard if one is registered
|
||||
if(guard!=null){
|
||||
guardOK=guard.check();
|
||||
}
|
||||
|
||||
if(guardOK){
|
||||
|
||||
// Post a message with the sensor data
|
||||
eventBus.post(message);
|
||||
|
||||
// Loop all configured ActionLoop objects
|
||||
for(ActionLoop actionLoop: actionLoops){
|
||||
actionLoop.execute();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Execute post actions
|
||||
for(Action action: postActions){
|
||||
action.execute();
|
||||
}
|
||||
|
||||
}
|
||||
finally{
|
||||
// Ensure that data stream is terminated ...
|
||||
|
||||
// Issue end of loop control message
|
||||
// Set iflag of the EndOfStreamMessage according to dataGroup flag of this loop
|
||||
eventBus.post(new EndOfStreamMessage(dataGroup));
|
||||
}
|
||||
|
||||
if(zigZag){
|
||||
// Reverse actors for the next run
|
||||
for(Actor actor: actors){
|
||||
actor.reverse();
|
||||
}
|
||||
}
|
||||
|
||||
executorService.shutdownNow();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void abort(){
|
||||
abort = true;
|
||||
loop = false;
|
||||
|
||||
// To abort all wait actions interrupt this thread
|
||||
for(Action a: preSensorActions){
|
||||
a.abort();
|
||||
}
|
||||
|
||||
// Recursively abort all registered action loops
|
||||
for(ActionLoop actionLoop: actionLoops){
|
||||
actionLoop.abort();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepare() {
|
||||
// Create callable for all actors
|
||||
pactors.clear();
|
||||
for(final Actor a: actors){
|
||||
pactors.add(new ActorSetCallable(a));
|
||||
}
|
||||
|
||||
// Reset all actuators
|
||||
for(Actor a: actors){
|
||||
a.reset();
|
||||
}
|
||||
|
||||
// Recursively call prepare() method of all registered action loops
|
||||
for(ActionLoop actionLoop: actionLoops){
|
||||
actionLoop.prepare();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanup() {
|
||||
// Recursively call cleanup() method of all registered action loops
|
||||
for(ActionLoop actionLoop: actionLoops){
|
||||
actionLoop.cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Action> getPreActions() {
|
||||
return preActions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Action> getPostActions() {
|
||||
return postActions;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public EventBus getEventBus(){
|
||||
return eventBus;
|
||||
}
|
||||
|
||||
|
||||
public List<ActionLoop> getActionLoops() {
|
||||
return actionLoops;
|
||||
}
|
||||
public List<Action> getPreActorActions() {
|
||||
return preActorActions;
|
||||
}
|
||||
public List<Action> getPostActorActions() {
|
||||
return postActorActions;
|
||||
}
|
||||
public List<Action> getPreSensorActions() {
|
||||
return preSensorActions;
|
||||
}
|
||||
public List<Action> getPostSensorActions() {
|
||||
return postSensorActions;
|
||||
}
|
||||
public List<Actor> getActors() {
|
||||
return actors;
|
||||
}
|
||||
public List<Sensor> getSensors() {
|
||||
return sensors;
|
||||
}
|
||||
public Guard getGuard() {
|
||||
return guard;
|
||||
}
|
||||
public void setGuard(Guard guard) {
|
||||
this.guard = guard;
|
||||
}
|
||||
public boolean isDataGroup() {
|
||||
return dataGroup;
|
||||
}
|
||||
public void setDataGroup(boolean dataGroup) {
|
||||
this.dataGroup = dataGroup;
|
||||
}
|
||||
}
|
||||
@@ -1,46 +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.loops.cr;
|
||||
|
||||
/**
|
||||
* Filter calculating the delta of two subsequent values
|
||||
*/
|
||||
public class CrlogicDeltaDataFilter {
|
||||
|
||||
private Double lastValue = null;
|
||||
|
||||
public void reset(){
|
||||
lastValue = null;
|
||||
}
|
||||
|
||||
public Double delta(Double value){
|
||||
|
||||
Double lvalue = lastValue;
|
||||
lastValue = value;
|
||||
|
||||
if(lvalue==null){
|
||||
return Double.NaN;
|
||||
}
|
||||
else{
|
||||
// Return delta
|
||||
return(value-lvalue);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,809 +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.loops.cr;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
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.Semaphore;
|
||||
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.messages.DataMessage;
|
||||
import ch.psi.fda.messages.EndOfStreamMessage;
|
||||
import ch.psi.fda.messages.Metadata;
|
||||
import ch.psi.jcae.ChannelException;
|
||||
import ch.psi.jcae.ChannelService;
|
||||
|
||||
/**
|
||||
* While using Crlogic the IOC system clock rate should/must be set to 1000 (default 60)
|
||||
*
|
||||
* sysClkRateSet 1000
|
||||
*
|
||||
*/
|
||||
public class CrlogicLoop implements ActionLoop {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(CrlogicLoop.class.getName());
|
||||
|
||||
/**
|
||||
* Flag to indicate whether the data of this loop will be grouped
|
||||
* According to this flag the dataGroup flag in EndOfStream will be set.
|
||||
*/
|
||||
private boolean dataGroup = false;
|
||||
|
||||
private boolean keepTmpFiles = false;
|
||||
|
||||
private BlockingQueue<String> readQueue = new LinkedBlockingQueue<String>();
|
||||
private volatile boolean stopReadoutThread = false;
|
||||
private Thread readoutThread;
|
||||
|
||||
/**
|
||||
* Default timeout (in milliseconds) for wait operations
|
||||
*/
|
||||
private long startStopTimeout = 8000;
|
||||
|
||||
/**
|
||||
* Name of the NFS server to place the data of the OTF logic
|
||||
*/
|
||||
private final String server;
|
||||
/**
|
||||
* Share on the NFS server to put the OTF data on to
|
||||
*/
|
||||
private final String share;
|
||||
/**
|
||||
* SMB share to access the data written by the OTF C logic
|
||||
*/
|
||||
private final String smbShare;
|
||||
|
||||
/**
|
||||
* Flag whether the actor of this loop should move in zig zag mode
|
||||
*/
|
||||
private final boolean zigZag;
|
||||
|
||||
boolean useReadback;
|
||||
boolean useEncoder;
|
||||
|
||||
/**
|
||||
* List of actions that are executed at the beginning of the loop.
|
||||
*/
|
||||
private List<Action> preActions;
|
||||
/**
|
||||
* List of actions that are executed at the end of the loop.
|
||||
*/
|
||||
private List<Action> postActions;
|
||||
|
||||
/**
|
||||
* Prefix for the CRLOGIC channels
|
||||
*/
|
||||
private String prefix;
|
||||
|
||||
private TemplateCrlogic template;
|
||||
private TemplateMotor motortemplate;
|
||||
|
||||
/**
|
||||
* Semaphore to ensure that data is read in correct sequence
|
||||
*/
|
||||
private Semaphore semaphore = new Semaphore(1);
|
||||
|
||||
/**
|
||||
* List of sensors of this loop
|
||||
*/
|
||||
private List<CrlogicResource> sensors;
|
||||
|
||||
private List<String> readoutResources;
|
||||
private Map<Integer, CrlogicDeltaDataFilter> scalerIndices;
|
||||
private CrlogicRangeDataFilter crlogicDataFilter;
|
||||
|
||||
|
||||
/**
|
||||
* Abort status
|
||||
*/
|
||||
private boolean abort = false;
|
||||
private boolean abortForce = false;
|
||||
private Thread executionThread = null;
|
||||
|
||||
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;
|
||||
this.smbShare = smbShare;
|
||||
this.zigZag = zigZag;
|
||||
|
||||
// Initialize lists used by the loop
|
||||
this.preActions = new ArrayList<Action>();
|
||||
this.postActions = new ArrayList<Action>();
|
||||
this.sensors = new ArrayList<>();
|
||||
this.readoutResources = new ArrayList<String>();
|
||||
this.scalerIndices = new HashMap<Integer, CrlogicDeltaDataFilter>();
|
||||
|
||||
this.crlogicDataFilter = new CrlogicRangeDataFilter();
|
||||
}
|
||||
|
||||
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
|
||||
* @throws InterruptedException
|
||||
* @throws IOException
|
||||
*/
|
||||
private void collectData(String tmpDir, String tmpFileName) throws InterruptedException, IOException {
|
||||
semaphore.acquire();
|
||||
if (tmpDir.startsWith("smb:")) {
|
||||
|
||||
SmbFile tmpFile = new SmbFile(tmpDir, tmpFileName);
|
||||
logger.info("Collect data from " + tmpFile.getCanonicalPath());
|
||||
|
||||
SmbFile lockfile = new SmbFile(tmpFile.getCanonicalPath() + ".lock");
|
||||
|
||||
logger.info("Wait until file is written [lock file: " + lockfile.getCanonicalPath() + "]");
|
||||
// Wait until file is created
|
||||
while ((!tmpFile.exists()) || lockfile.exists()) {
|
||||
try{
|
||||
Thread.sleep(100);
|
||||
}
|
||||
catch(InterruptedException e){
|
||||
abort=true;
|
||||
}
|
||||
if(abort){
|
||||
// If abort is issued while waiting for data immediately return without
|
||||
// trying to read the data
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
InputStreamReader inreader = new InputStreamReader(tmpFile.getInputStream());
|
||||
BufferedReader in = new BufferedReader(inreader);
|
||||
String line;
|
||||
boolean firstline = true;
|
||||
int linecount=0;
|
||||
int mcounter=0;
|
||||
|
||||
// boolean wasInRangeBefore = false;
|
||||
boolean discardAnyway = false;
|
||||
|
||||
while (true) {
|
||||
line = in.readLine();
|
||||
linecount++;
|
||||
if (line == null) {
|
||||
break;
|
||||
} else {
|
||||
// if(line.matches("^\\[.*")){
|
||||
if (line.matches("^ *#.*")) {
|
||||
// Skip header/comment lines
|
||||
// logger.info("HEADER: " + line);
|
||||
} else {
|
||||
if (firstline) {
|
||||
firstline = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
// logger.info(line);
|
||||
|
||||
// Write into queue
|
||||
DataMessage message = new DataMessage(metadata);
|
||||
String[] tokens = line.split("\t");
|
||||
boolean use = true;
|
||||
|
||||
for(int i=0;i<tokens.length;i++){
|
||||
String t = tokens[i];
|
||||
Double val;
|
||||
|
||||
if(i==0){
|
||||
Double raw = new Double(t);
|
||||
|
||||
if(useEncoder){
|
||||
val = crlogicDataFilter.calculatePositionMotorUseEncoder(raw);
|
||||
}
|
||||
else if(useReadback){
|
||||
val = crlogicDataFilter.calculatePositionMotorUseReadback(raw);
|
||||
}
|
||||
else{
|
||||
val = crlogicDataFilter.calculatePositionMotor(raw);
|
||||
}
|
||||
|
||||
// Check whether data is within the configured range - otherwise drop data
|
||||
use = crlogicDataFilter.filter(val);
|
||||
// if(!use){
|
||||
// break;
|
||||
// }
|
||||
}
|
||||
else if(scalerIndices.containsKey(i)){
|
||||
CrlogicDeltaDataFilter f = scalerIndices.get(i);
|
||||
val = f.delta(new Double(t));
|
||||
}
|
||||
else{
|
||||
val = new Double(t);
|
||||
}
|
||||
|
||||
|
||||
message.getData().add(val);
|
||||
}
|
||||
|
||||
// Does not work if zigzag, ...
|
||||
// // Use this to filter out motor retry movements at the end of the scan
|
||||
// wasInRangeBefore = wasInRangeBefore | use;
|
||||
// if(!use && wasInRangeBefore){
|
||||
// discardAnyway=true;
|
||||
// // Optimization - terminate read loop once range is left
|
||||
// logger.info("Terminate read loop because point is outside range");
|
||||
// break;
|
||||
// }
|
||||
|
||||
// Filter data
|
||||
if(use && !discardAnyway){
|
||||
eventbus.post(message);
|
||||
mcounter++;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
in.close();
|
||||
inreader.close();
|
||||
|
||||
logger.info("Lines read: "+linecount+" Messages generated (after filtering): "+mcounter);
|
||||
|
||||
// Remove temporary file
|
||||
if(!keepTmpFiles){
|
||||
tmpFile.delete();
|
||||
}
|
||||
}
|
||||
else{
|
||||
// TODO - File in local file system
|
||||
}
|
||||
|
||||
// Issue end of loop control message
|
||||
eventbus.post(new EndOfStreamMessage(dataGroup));
|
||||
semaphore.release();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ch.psi.fda.core.Action#execute()
|
||||
*/
|
||||
@Override
|
||||
public void execute() throws InterruptedException {
|
||||
try{
|
||||
|
||||
// Set values for the datafilter
|
||||
crlogicDataFilter.setStart(start);
|
||||
crlogicDataFilter.setEnd(end);
|
||||
|
||||
// Reset data filter
|
||||
for(Integer k: scalerIndices.keySet()){
|
||||
scalerIndices.get(k).reset();
|
||||
}
|
||||
|
||||
synchronized(this){
|
||||
// Set abort state to false
|
||||
abort = false;
|
||||
abortForce = false;
|
||||
|
||||
// Set execution thread to current thread
|
||||
executionThread = Thread.currentThread();
|
||||
}
|
||||
|
||||
|
||||
// TODO each actuator will result in an additional sensor (at the beginning)
|
||||
// Dependent on actuator settings (readback use encoder, ...)
|
||||
|
||||
|
||||
// TODO filename generation?
|
||||
final String tmpFileName = "tmp-"+System.currentTimeMillis()+".txt";
|
||||
|
||||
Long timeout = 600000l; // 10 minutes move timeout
|
||||
|
||||
// Check if logic is inactive, otherwise return early
|
||||
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(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(TemplateCrlogic.Status.INACTIVE.toString());
|
||||
}
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
logger.info("Set parameters");
|
||||
template.getNfsServer().setValue(server);
|
||||
template.getNfsShare().setValue(share);
|
||||
template.getDataFile().setValue(tmpFileName);
|
||||
|
||||
int tps = template.getTicksPerSecond().getValue();
|
||||
logger.info("Ticks per second: "+tps);
|
||||
|
||||
logger.info("Set readout resources");
|
||||
|
||||
template.getReadoutResources().setValue(readoutResources.toArray(new String[readoutResources.size()]));
|
||||
|
||||
|
||||
|
||||
// Set ticks between interrupt to integration time
|
||||
int ticks = (int)(tps*integrationTime);
|
||||
template.getTicksBetweenInterrupts().setValue(ticks);
|
||||
|
||||
// Prepare motor
|
||||
double totalTimeSeconds = Math.abs((end-start)/stepSize*integrationTime);
|
||||
int hours = (int) Math.floor(totalTimeSeconds/60/60);
|
||||
int minutes = (int) Math.floor(totalTimeSeconds/60-hours*60);
|
||||
int seconds = (int) Math.floor(totalTimeSeconds-hours*60*60-minutes*60);
|
||||
|
||||
logger.info("Estimated time: "+hours+":"+minutes+":"+seconds);
|
||||
|
||||
int direction = 1;
|
||||
if(end-start<0){
|
||||
direction = -1;
|
||||
}
|
||||
|
||||
double motorBaseSpeed = motortemplate.getBaseSpeed().getValue();
|
||||
double motorHighLimit = motortemplate.getHighLimit().getValue();
|
||||
double motorLowLimit = motortemplate.getLowLimit().getValue();
|
||||
double motorBacklash = motortemplate.getBacklashDistance().getValue();
|
||||
|
||||
boolean respectMotorMinSpeed = false; // if false set min speed to 0
|
||||
double motorMinSpeed = 0;
|
||||
if(respectMotorMinSpeed){
|
||||
motorMinSpeed = motorBaseSpeed;
|
||||
}
|
||||
|
||||
// Check user parameters
|
||||
// TODO start and end values must be between the motor high and low value - otherwise fail
|
||||
if(start>motorHighLimit || start<motorLowLimit){
|
||||
// Start value is outside motor high and/or low value
|
||||
logger.info("Start value is outside motor high and/or low value");
|
||||
throw new IllegalArgumentException("Start value is outside motor high and/or low value");
|
||||
}
|
||||
if(end>motorHighLimit || end<motorLowLimit){
|
||||
// End value is outside motor high and/or low value
|
||||
logger.info("End value is outside motor high and/or low value");
|
||||
throw new IllegalArgumentException("End value is outside motor high and/or low value");
|
||||
}
|
||||
// TODO Check minimum step size
|
||||
int minimumTicks = 10;
|
||||
double minStepSize = motorMinSpeed*(minimumTicks/tps);
|
||||
if(stepSize<minStepSize){
|
||||
// Step size is too small
|
||||
logger.info("Step size is too small");
|
||||
throw new IllegalArgumentException("Step size is too small");
|
||||
}
|
||||
// TODO Check integration time
|
||||
if(motorMinSpeed>0){
|
||||
double maxIntegrationTime = stepSize/motorMinSpeed;
|
||||
if(integrationTime>maxIntegrationTime){
|
||||
logger.info("Integration time is too big");
|
||||
// Integration time is too big
|
||||
throw new IllegalArgumentException("Integration time is too big");
|
||||
}
|
||||
}
|
||||
double motorMaxSpeed = motortemplate.getVelocity().getValue();
|
||||
double minIntegrationTime = Math.min( (stepSize/motorMaxSpeed), ((double)minimumTicks/(double)tps) );
|
||||
if(integrationTime<minIntegrationTime){
|
||||
// Integration time is too small
|
||||
logger.info("Integration time is too small [min integration time: "+minIntegrationTime+"]");
|
||||
throw new IllegalArgumentException("Integration time is too small [min integration time: "+minIntegrationTime+"]");
|
||||
}
|
||||
|
||||
|
||||
// TODO Calculate and set motor speed, backlash, etc.
|
||||
double motorSpeed = stepSize/integrationTime;
|
||||
double backlash = (0.5*motorSpeed*motortemplate.getAccelerationTime().getValue())+motorBacklash+additionalBacklash;
|
||||
double realEnd = end+(backlash*direction);
|
||||
double realStart = start-(backlash*direction);
|
||||
|
||||
|
||||
// Move to start
|
||||
logger.info("Move motor to start ["+realStart+"]");
|
||||
motortemplate.getSetValue().setValueAsync(realStart).get(timeout, TimeUnit.MILLISECONDS); // Will block until move is done
|
||||
|
||||
|
||||
// Set motor paramters
|
||||
// Backup settings
|
||||
logger.info("Backup motor settings");
|
||||
double backupSpeed = motortemplate.getVelocity().getValue();
|
||||
double backupBacklash = motorBacklash;
|
||||
double backupMinSpeed = motorBaseSpeed;
|
||||
|
||||
try{
|
||||
// Set motor settings
|
||||
logger.info("Update motor settings");
|
||||
// if(!respectMotorMinSpeed){
|
||||
// motortemplate.getBaseSpeed().setValue(0d);
|
||||
// }
|
||||
// Set base speed as fast as possible but not faster than the original base speed.
|
||||
double base = motorBaseSpeed;
|
||||
if(motorSpeed<base){
|
||||
base = motorSpeed;
|
||||
}
|
||||
motortemplate.getBaseSpeed().setValue(base);
|
||||
motortemplate.getVelocity().setValue(motorSpeed);
|
||||
motortemplate.getBacklashDistance().setValue(0d);
|
||||
|
||||
|
||||
// Execute pre actions
|
||||
for(Action action: preActions){
|
||||
action.execute();
|
||||
}
|
||||
|
||||
|
||||
// Start crlogic logic
|
||||
logger.info("Start CRLOGIC");
|
||||
template.getStatus().setValue(TemplateCrlogic.Status.INITIALIZE.toString());
|
||||
try{
|
||||
template.getStatus().waitForValue(TemplateCrlogic.Status.ACTIVE.toString(), startStopTimeout);
|
||||
}
|
||||
catch(ChannelException | ExecutionException | TimeoutException e){
|
||||
logger.info( "Failed to start CRLOGIC. Logic in status: "+template.getStatus().getValue() );
|
||||
if(template.getStatus().getValue().equals(TemplateCrlogic.Status.FAULT.toString())){
|
||||
logger.info("Error message: "+template.getMessage().getValue());
|
||||
}
|
||||
// Recover to inactive
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
// Move motor(s) to end / wait until motor is stopped
|
||||
logger.info("Move motor to end ["+realEnd+"]");
|
||||
try{
|
||||
motortemplate.getSetValue().setValueAsync(realEnd).get(timeout, TimeUnit.MILLISECONDS); // Will block until move is done
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
if(abort & (!abortForce)){
|
||||
// Abort motor move
|
||||
motortemplate.getCommand().setValue(TemplateMotor.Commands.Stop.ordinal());
|
||||
motortemplate.getCommand().setValue(TemplateMotor.Commands.Go.ordinal());
|
||||
}
|
||||
else{
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
logger.info("Motor reached end position");
|
||||
|
||||
// Stop crlogic logic
|
||||
logger.info("Stop CRLOGIC");
|
||||
template.getStatus().setValue(TemplateCrlogic.Status.STOP.toString());
|
||||
// Wait until stopped
|
||||
logger.info("Wait until stopped");
|
||||
try{
|
||||
template.getStatus().waitForValue(TemplateCrlogic.Status.INACTIVE.toString(), startStopTimeout);
|
||||
}
|
||||
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);
|
||||
}
|
||||
logger.info("CRLOGIC is now stopped");
|
||||
|
||||
|
||||
// Execute post actions
|
||||
for(Action action: postActions){
|
||||
action.execute();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
finally{
|
||||
logger.info("Restore motor settings");
|
||||
motortemplate.getBaseSpeed().setValue(backupMinSpeed);
|
||||
motortemplate.getVelocity().setValue(backupSpeed);
|
||||
motortemplate.getBacklashDistance().setValue(backupBacklash);
|
||||
}
|
||||
|
||||
// Request read of data file
|
||||
readQueue.put(tmpFileName);
|
||||
|
||||
if(zigZag){
|
||||
// reverse start/end
|
||||
double aend = end;
|
||||
end=start;
|
||||
start=aend;
|
||||
}
|
||||
|
||||
synchronized(this){
|
||||
executionThread = null;
|
||||
}
|
||||
}
|
||||
catch(ChannelException | ExecutionException | TimeoutException e){
|
||||
throw new RuntimeException("Unable to execute crloop", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void abort() {
|
||||
abort(false);
|
||||
}
|
||||
|
||||
public synchronized void abort(boolean force){
|
||||
abort = true;
|
||||
abortForce = force;
|
||||
|
||||
// executionThread variable guarded by "this"
|
||||
if(executionThread != null){
|
||||
executionThread.interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
@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() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
while(!stopReadoutThread){
|
||||
String file;
|
||||
try {
|
||||
file = readQueue.take();
|
||||
} catch (InterruptedException e) {
|
||||
break;
|
||||
}
|
||||
// TODO Read file and
|
||||
try {
|
||||
collectData(smbShare, file);
|
||||
} 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
readoutThread.start();
|
||||
|
||||
try{
|
||||
// Connect crlogic channels
|
||||
template = new TemplateCrlogic();
|
||||
logger.info("Connect channels");
|
||||
Map<String,String> map = new HashMap<>();
|
||||
map.put("PREFIX", prefix);
|
||||
cservice.createAnnotatedChannels(template, map);
|
||||
|
||||
// Connect motor channels
|
||||
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: "+ TemplateMotor.Type.values()[motortemplate.getType().getValue()]);
|
||||
logger.info("Motor use readback: "+useReadback);
|
||||
logger.info("Motor use encoder: "+useEncoder);
|
||||
|
||||
// TODO build up list of readout resources (based on sensors)
|
||||
readoutResources.clear();
|
||||
// first sensor is the actuator
|
||||
|
||||
// Determine mode of motor
|
||||
if((!useReadback) && (!useEncoder)){
|
||||
// Open loop
|
||||
if(this.readback!=null){
|
||||
throw new IllegalArgumentException("Readback not supported if motor is configured in open loop");
|
||||
}
|
||||
else{
|
||||
readoutResources.add(this.name);
|
||||
}
|
||||
|
||||
}
|
||||
else if(useReadback && (!useEncoder)){
|
||||
String readback;
|
||||
// use readback link
|
||||
if(this.readback!=null){
|
||||
// Use specified readback
|
||||
readback = this.readback;
|
||||
}
|
||||
else{
|
||||
// Set resouce to readback link
|
||||
readback = (motortemplate.getReadbackLink().getValue());
|
||||
readback = readback.replaceAll(" +.*", ""); // remove NPP etc at the end
|
||||
}
|
||||
|
||||
readoutResources.add(readback);
|
||||
|
||||
// Fill readback encoder settings
|
||||
// Connect to encoder
|
||||
TemplateEncoder encodertemplate = new TemplateEncoder();
|
||||
map = new HashMap<>();
|
||||
map.put("PREFIX", readback);
|
||||
cservice.createAnnotatedChannels(encodertemplate, map);
|
||||
|
||||
// Read encoder settings
|
||||
if(encodertemplate.getDirection().getValue()==TemplateEncoder.Direction.Positive.ordinal()){
|
||||
crlogicDataFilter.setEncoderDirection(1);
|
||||
}
|
||||
else{
|
||||
crlogicDataFilter.setEncoderDirection(-1);
|
||||
}
|
||||
crlogicDataFilter.setEncoderOffset(encodertemplate.getOffset().getValue());
|
||||
crlogicDataFilter.setEncoderResolution(encodertemplate.getResolution().getValue());
|
||||
|
||||
// Disconnect from encoder
|
||||
cservice.destroyAnnotatedChannels(encodertemplate);
|
||||
|
||||
}
|
||||
else if (useEncoder && (!useReadback)){
|
||||
// use readback link
|
||||
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(this.name+"_ENC");
|
||||
}
|
||||
}
|
||||
else{
|
||||
throw new IllegalArgumentException("Motor configuration not supportet: use readback - "+useReadback+" use encoder - "+useEncoder);
|
||||
}
|
||||
|
||||
// Fill Motor specific settings
|
||||
if(motortemplate.getDirection().getValue()==TemplateMotor.Direction.Positive.ordinal()){
|
||||
crlogicDataFilter.setMotorDirection(1);
|
||||
}
|
||||
else{
|
||||
crlogicDataFilter.setMotorDirection(-1);
|
||||
}
|
||||
crlogicDataFilter.setMotorEncoderResolution(motortemplate.getEncoderResolution().getValue());
|
||||
crlogicDataFilter.setMotorOffset(motortemplate.getOffset().getValue());
|
||||
crlogicDataFilter.setMotorReadbackResolution(motortemplate.getReadbackResolution().getValue());
|
||||
crlogicDataFilter.setMotorResolution(motortemplate.getMotorResolution().getValue());
|
||||
|
||||
// Clear all indices
|
||||
scalerIndices.clear();
|
||||
|
||||
int c = 1; // We start at 1 because the actuator right now is an implicit sensor
|
||||
for(CrlogicResource s: sensors){
|
||||
readoutResources.add(s.getKey());
|
||||
if(s.isDelta()){
|
||||
scalerIndices.put(c, new CrlogicDeltaDataFilter());
|
||||
}
|
||||
c++;
|
||||
}
|
||||
|
||||
// Workaround - somehow one has to add an empty thing to the value otherwise the c logic
|
||||
// does not pick up the end
|
||||
readoutResources.add("");
|
||||
}
|
||||
catch(Exception e){
|
||||
throw new RuntimeException("Unable to prepare crloop: ",e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanup() {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Action> getPreActions() {
|
||||
return preActions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Action> getPostActions() {
|
||||
return postActions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDataGroup() {
|
||||
return dataGroup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDataGroup(boolean dataGroup) {
|
||||
this.dataGroup = dataGroup;
|
||||
}
|
||||
|
||||
public List<CrlogicResource> getSensors() {
|
||||
return sensors;
|
||||
}
|
||||
|
||||
public boolean isKeepTmpFiles() {
|
||||
return keepTmpFiles;
|
||||
}
|
||||
|
||||
public void setKeepTmpFiles(boolean keepTmpFiles) {
|
||||
this.keepTmpFiles = keepTmpFiles;
|
||||
}
|
||||
|
||||
public EventBus getEventBus(){
|
||||
return eventbus;
|
||||
}
|
||||
}
|
||||
@@ -1,274 +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.loops.cr;
|
||||
|
||||
/**
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
public class CrlogicRangeDataFilter {
|
||||
|
||||
private double motorResolution = 1;
|
||||
private int motorDirection = 1;
|
||||
private double motorOffset = 0;
|
||||
private double motorReadbackResolution = 1;
|
||||
private double motorEncoderResolution = 1;
|
||||
|
||||
private double encoderOffset = 0;
|
||||
private double encoderResolution = 1;
|
||||
private int encoderDirection = 1;
|
||||
|
||||
private double start = 0;
|
||||
private double end = 0;
|
||||
private boolean positive = true;
|
||||
|
||||
/**
|
||||
* Marker whether the value was equal
|
||||
*/
|
||||
private boolean wasEqualBefore = false;
|
||||
|
||||
/**
|
||||
* @return the motorResolution
|
||||
*/
|
||||
public double getMotorResolution() {
|
||||
return motorResolution;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param motorResolution the motorResolution to set
|
||||
*/
|
||||
public void setMotorResolution(double motorResolution) {
|
||||
this.motorResolution = motorResolution;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the motorDirection
|
||||
*/
|
||||
public int getMotorDirection() {
|
||||
return motorDirection;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param motorDirection the motorDirection to set
|
||||
*/
|
||||
public void setMotorDirection(int motorDirection) {
|
||||
this.motorDirection = motorDirection;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the motorOffset
|
||||
*/
|
||||
public double getMotorOffset() {
|
||||
return motorOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param motorOffset the motorOffset to set
|
||||
*/
|
||||
public void setMotorOffset(double motorOffset) {
|
||||
this.motorOffset = motorOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the motorReadbackResolution
|
||||
*/
|
||||
public double getMotorReadbackResolution() {
|
||||
return motorReadbackResolution;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param motorReadbackResolution the motorReadbackResolution to set
|
||||
*/
|
||||
public void setMotorReadbackResolution(double motorReadbackResolution) {
|
||||
this.motorReadbackResolution = motorReadbackResolution;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the motorEncoderResolution
|
||||
*/
|
||||
public double getMotorEncoderResolution() {
|
||||
return motorEncoderResolution;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param motorEncoderResolution the motorEncoderResolution to set
|
||||
*/
|
||||
public void setMotorEncoderResolution(double motorEncoderResolution) {
|
||||
this.motorEncoderResolution = motorEncoderResolution;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the encoderOffset
|
||||
*/
|
||||
public double getEncoderOffset() {
|
||||
return encoderOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param encoderOffset the encoderOffset to set
|
||||
*/
|
||||
public void setEncoderOffset(double encoderOffset) {
|
||||
this.encoderOffset = encoderOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the encoderResolution
|
||||
*/
|
||||
public double getEncoderResolution() {
|
||||
return encoderResolution;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param encoderResolution the encoderResolution to set
|
||||
*/
|
||||
public void setEncoderResolution(double encoderResolution) {
|
||||
this.encoderResolution = encoderResolution;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the encoderDirection
|
||||
*/
|
||||
public int getEncoderDirection() {
|
||||
return encoderDirection;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param encoderDirection the encoderDirection to set
|
||||
*/
|
||||
public void setEncoderDirection(int encoderDirection) {
|
||||
this.encoderDirection = encoderDirection;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the start
|
||||
*/
|
||||
public double getStart() {
|
||||
return start;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param start the start to set
|
||||
*/
|
||||
public void setStart(double start) {
|
||||
this.start = start;
|
||||
if(start<=end){
|
||||
positive=true;
|
||||
}
|
||||
else{
|
||||
positive=false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the end
|
||||
*/
|
||||
public double getEnd() {
|
||||
return end;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param end the end to set
|
||||
*/
|
||||
public void setEnd(double end) {
|
||||
this.end = end;
|
||||
if(end>=start){
|
||||
positive=true;
|
||||
}
|
||||
else{
|
||||
positive=false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate real position
|
||||
* @param raw
|
||||
* @return
|
||||
*/
|
||||
public double calculatePositionMotor(double raw){
|
||||
return(((raw * motorResolution * motorReadbackResolution)/motorDirection)+motorOffset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate real motor position using the readback link
|
||||
* @param raw
|
||||
* @return
|
||||
*/
|
||||
public double calculatePositionMotorUseReadback(double raw){
|
||||
return((((raw - encoderOffset) * encoderResolution * encoderDirection * motorReadbackResolution) / motorDirection) + motorOffset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate real motor position using encoder
|
||||
* @param raw
|
||||
* @return
|
||||
*/
|
||||
public double calculatePositionMotorUseEncoder(double raw){
|
||||
return(raw * motorEncoderResolution * motorReadbackResolution/motorDirection + motorOffset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter whether value is with the range
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public boolean filter(Double value){
|
||||
if(positive){
|
||||
if(start<=value && value<=end){
|
||||
|
||||
// If motor is very accurete and user backlash==null it might be that value is exactly
|
||||
// the end value. To prevent that unnecessary data is captured execute this check
|
||||
if(wasEqualBefore){
|
||||
wasEqualBefore=false; // Reset flag
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check whether was equal
|
||||
if(value==end){
|
||||
wasEqualBefore=true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else{
|
||||
if(end<=value && value <=start){
|
||||
|
||||
if(wasEqualBefore){
|
||||
wasEqualBefore=false; // Reset flag
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check whether was equal
|
||||
if(value==start){
|
||||
wasEqualBefore=true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,71 +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.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;
|
||||
}
|
||||
}
|
||||
@@ -1,237 +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.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.messages.Message;
|
||||
|
||||
public class ParallelCrlogic implements ActionLoop {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(ParallelCrlogic.class.getName());
|
||||
|
||||
/**
|
||||
* Flag to indicate whether the data of this loop will be grouped
|
||||
* According to this flag the dataGroup flag in EndOfStream will be set.
|
||||
*/
|
||||
private boolean dataGroup = false;
|
||||
|
||||
private CrlogicLoop crlogic;
|
||||
private ScrlogicLoop scrlogic;
|
||||
|
||||
/**
|
||||
* List of actions that are executed at the beginning of the loop.
|
||||
*/
|
||||
private List<Action> preActions;
|
||||
/**
|
||||
* List of actions that are executed at the end of the loop.
|
||||
*/
|
||||
private List<Action> postActions;
|
||||
|
||||
private ParallelCrlogicStreamMerge merger;
|
||||
|
||||
|
||||
private final EventBus eventbus;
|
||||
|
||||
public ParallelCrlogic(CrlogicLoop crlogic, ScrlogicLoop scrlogic){
|
||||
|
||||
if(crlogic==null){
|
||||
throw new IllegalArgumentException("No Crloop specified");
|
||||
}
|
||||
if(scrlogic==null){
|
||||
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 CrlogicResource("tmp_timestamp","TIMESTAMP"));
|
||||
this.scrlogic = scrlogic;
|
||||
|
||||
// Initialize lists used by the loop
|
||||
this.preActions = new ArrayList<Action>();
|
||||
this.postActions = new ArrayList<Action>();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepare() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() throws InterruptedException {
|
||||
|
||||
// Execute pre actions
|
||||
for(Action action: preActions){
|
||||
action.execute();
|
||||
}
|
||||
|
||||
|
||||
ExecutorService service = Executors.newFixedThreadPool(3); // 2 for the parallel data acquisition and 1 for the merger thread
|
||||
final CyclicBarrier b = new CyclicBarrier(2);
|
||||
|
||||
List<Future<Boolean>> list = new ArrayList<Future<Boolean>>();
|
||||
|
||||
// Start a thread for each logic
|
||||
logger.info("Submit logic");
|
||||
Future<Boolean> f = service.submit(new Callable<Boolean>(){
|
||||
@Override
|
||||
public Boolean call() throws Exception {
|
||||
|
||||
// Prepare logic
|
||||
crlogic.prepare();
|
||||
|
||||
// Ensure that really all parallel logics start in parallel
|
||||
b.await();
|
||||
|
||||
// Execute the logic of this path
|
||||
crlogic.execute();
|
||||
|
||||
// Need to stop the scrlogic logic (otherwise it would keep going to take data)
|
||||
scrlogic.abort();
|
||||
return true;
|
||||
}});
|
||||
list.add(f);
|
||||
|
||||
//Start a thread for the scrlogic
|
||||
logger.info("Submit logic");
|
||||
f = service.submit(new Callable<Boolean>(){
|
||||
@Override
|
||||
public Boolean call() throws Exception {
|
||||
|
||||
// Prepare logic
|
||||
scrlogic.prepare();
|
||||
|
||||
// Ensure that really all parallel logics start in parallel
|
||||
b.await();
|
||||
|
||||
// Execute the logic of this path
|
||||
scrlogic.execute(); // This actually just starts the collection ...
|
||||
return true;
|
||||
}});
|
||||
list.add(f);
|
||||
|
||||
|
||||
// // Start data merge thread
|
||||
// logger.info("Start data merge");
|
||||
// f = service.submit(new Callable<Boolean>(){
|
||||
// @Override
|
||||
// public Boolean call() throws Exception {
|
||||
//
|
||||
// merger.merge();
|
||||
// return true;
|
||||
// }});
|
||||
// list.add(f);
|
||||
|
||||
|
||||
for(Future<Boolean> bf: list){
|
||||
// Wait for completion of the thread
|
||||
try {
|
||||
bf.get();
|
||||
} catch (ExecutionException e) {
|
||||
logger.log(Level.WARNING, "Something went wrong while waiting for crthreads to finish");
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
merger.merge();
|
||||
|
||||
// Wait until all threads have finished
|
||||
service.shutdown();
|
||||
service.awaitTermination(1, TimeUnit.MINUTES);
|
||||
|
||||
|
||||
// Execute post actions
|
||||
for(Action action: postActions){
|
||||
action.execute();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void abort() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanup() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Action> getPreActions() {
|
||||
return preActions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Action> getPostActions() {
|
||||
return postActions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDataGroup() {
|
||||
return dataGroup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDataGroup(boolean dataGroup) {
|
||||
this.dataGroup = dataGroup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EventBus getEventBus(){
|
||||
return eventbus;
|
||||
}
|
||||
}
|
||||
@@ -1,163 +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.loops.cr;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
|
||||
import com.google.common.eventbus.EventBus;
|
||||
|
||||
import ch.psi.fda.messages.DataMessage;
|
||||
import ch.psi.fda.messages.EndOfStreamMessage;
|
||||
import ch.psi.fda.messages.Message;
|
||||
import ch.psi.fda.messages.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.
|
||||
*/
|
||||
public class ParallelCrlogicStreamMerge {
|
||||
|
||||
|
||||
private BlockingQueue<Message> primaryQueue;
|
||||
private BlockingQueue<Message> secondaryQueue;
|
||||
|
||||
private final EventBus eventbus;
|
||||
|
||||
private List<Metadata> metadata;
|
||||
|
||||
/**
|
||||
* @param pqueue Primary/master queue
|
||||
* @param squeue Secondary queue
|
||||
*/
|
||||
public ParallelCrlogicStreamMerge(BlockingQueue<Message> pqueue, BlockingQueue<Message> squeue, EventBus ebus){
|
||||
this.primaryQueue = pqueue;
|
||||
this.secondaryQueue = squeue;
|
||||
|
||||
this.eventbus = ebus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge the streams based on the timestamp
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
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.take();
|
||||
|
||||
while(! (m instanceof EndOfStreamMessage)){
|
||||
|
||||
if(m instanceof DataMessage){
|
||||
|
||||
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);
|
||||
|
||||
while(true){
|
||||
// Assumption: the secondary Queue holds at least the data up to the
|
||||
// timestamp of the primary queue
|
||||
Message mess = secondaryQueue.peek();
|
||||
|
||||
if(mess instanceof EndOfStreamMessage){
|
||||
break;
|
||||
}
|
||||
|
||||
if(mess == null){
|
||||
break;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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();
|
||||
|
||||
if(currMilliCheck>milliseconds || (currMilliCheck==milliseconds && currNanoCheck>nanoOffset)){
|
||||
break;
|
||||
}
|
||||
|
||||
DataMessage ms = (DataMessage) secondaryQueue.take();
|
||||
|
||||
currData = ms.getData();
|
||||
// Remove timestamps
|
||||
currData.remove(0);
|
||||
currData.remove(0);
|
||||
}
|
||||
else{
|
||||
// No DataMessage
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Add data to primary data queue message and put it into the out queue
|
||||
dm.getData().addAll(currData);
|
||||
dm.setMetadata(metadata);
|
||||
eventbus.post(dm);
|
||||
}
|
||||
|
||||
|
||||
m = primaryQueue.take();
|
||||
}
|
||||
|
||||
// Add the end of stream message of the primary queue
|
||||
eventbus.post(m);
|
||||
|
||||
// Clear all remaining messages in secondary queue
|
||||
secondaryQueue.clear();
|
||||
}
|
||||
}
|
||||
@@ -1,305 +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.loops.cr;
|
||||
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
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.messages.DataMessage;
|
||||
import ch.psi.fda.messages.EndOfStreamMessage;
|
||||
import ch.psi.fda.messages.Metadata;
|
||||
import ch.psi.jcae.Channel;
|
||||
import ch.psi.jcae.impl.type.DoubleTimestamp;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* other on different IOC's have not arrived yet. - The sequence of
|
||||
* monitors fired for one channel is according to the sequence of the
|
||||
* causes. No monitor package is overtaking an other package on the
|
||||
* network.
|
||||
*
|
||||
* - No monitor events are lost on the network (while using monitors you
|
||||
* cannot guarantee this)
|
||||
*
|
||||
* The data queue returned by this logic includes two items for the
|
||||
* timestamp and nanoseconds offset. These two items are the first two
|
||||
* items of a message The id's are: crTimestampMilliseconds
|
||||
* crTimestampOffsetNanoseconds
|
||||
*/
|
||||
public class ScrlogicLoop implements ActionLoop {
|
||||
|
||||
private static String ID_TIMESTAMP_MILLISECONDS = "crTimestampMilliseconds";
|
||||
private static String ID_TIMESTAMP_OFFSET_NANOSECONDS = "crTimestampOffsetNanoseconds";
|
||||
|
||||
// Get Logger
|
||||
private static final Logger logger = Logger.getLogger(ScrlogicLoop.class.getName());
|
||||
|
||||
|
||||
/**
|
||||
* 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 boolean dataGroup = false;
|
||||
private final List<Action> preActions = new ArrayList<Action>();
|
||||
private final List<Action> postActions = new ArrayList<Action>();
|
||||
|
||||
private List<String> sensorIds;
|
||||
private List<Channel<DoubleTimestamp>> sensors;
|
||||
|
||||
/**
|
||||
* List of monitors that were attached to the sensor channels (i.e
|
||||
* workaround)
|
||||
*/
|
||||
private final List<PropertyChangeListener> monitors = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* List of blocking queues that hold the data for one sensor (channel)
|
||||
*/
|
||||
private final List<BlockingQueue<TimestampedValue>> queues = new ArrayList<BlockingQueue<TimestampedValue>>();
|
||||
|
||||
private CountDownLatch latch;
|
||||
|
||||
private final EventBus eventbus;
|
||||
private List<Metadata> metadata;
|
||||
|
||||
public ScrlogicLoop(List<String> sensorIds, List<Channel<DoubleTimestamp>> sensors) {
|
||||
this.eventbus = new EventBus();
|
||||
this.sensorIds = sensorIds;
|
||||
this.sensors = sensors;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() throws InterruptedException {
|
||||
|
||||
// Clear all queues
|
||||
queues.clear();
|
||||
latch = new CountDownLatch(1);
|
||||
|
||||
// Attach monitors to the channels (this is actually a workaround)
|
||||
for (Channel<DoubleTimestamp> sensor : sensors) {
|
||||
final BlockingQueue<TimestampedValue> q = new LinkedBlockingQueue<TimestampedValue>();
|
||||
queues.add(q);
|
||||
PropertyChangeListener listener = new PropertyChangeListener() {
|
||||
|
||||
@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(listener);
|
||||
monitors.add(listener);
|
||||
|
||||
}
|
||||
|
||||
logger.info("Start data acquisition");
|
||||
|
||||
latch.await();
|
||||
|
||||
// Remove monitors
|
||||
|
||||
for (int i = 0; i < sensors.size(); i++) {
|
||||
Channel<DoubleTimestamp> sensor = sensors.get(i);
|
||||
sensor.removePropertyChangeListener(monitors.get(i));
|
||||
}
|
||||
|
||||
// Merge data
|
||||
merge();
|
||||
|
||||
// Clear data queues
|
||||
for (BlockingQueue<TimestampedValue> q : queues) {
|
||||
q.clear();
|
||||
}
|
||||
queues.clear();
|
||||
|
||||
|
||||
// Put end of stream to the queue
|
||||
eventbus.post(new EndOfStreamMessage(dataGroup));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void abort() {
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepare() {
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanup() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Action> getPreActions() {
|
||||
return preActions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Action> getPostActions() {
|
||||
return postActions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDataGroup() {
|
||||
return dataGroup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDataGroup(boolean dataGroup) {
|
||||
this.dataGroup = dataGroup;
|
||||
}
|
||||
|
||||
private boolean hasNext(){
|
||||
for (BlockingQueue<TimestampedValue> q: queues) {
|
||||
if(!q.isEmpty()){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge data collected by different monitor
|
||||
*
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
private void merge() throws InterruptedException {
|
||||
// Array to hold temporary channel values
|
||||
TimestampedValue[] cvalues = new TimestampedValue[queues.size()];
|
||||
TimestampedValueComparator comparator = new TimestampedValueComparator();
|
||||
|
||||
// Oldest value written
|
||||
TimestampedValue globalOldest = null;
|
||||
List<Integer> indexes = new ArrayList<Integer>();
|
||||
|
||||
while (hasNext()) {
|
||||
Thread.sleep(10); // Ensure that close by monitors have time to
|
||||
// catch up / also ensure context switch
|
||||
|
||||
// Oldest value of this run
|
||||
TimestampedValue oldest = null;
|
||||
// Queue index of the oldest value of this run
|
||||
indexes.clear();
|
||||
|
||||
// Find oldest element in any of the queues
|
||||
for (int i = 0; i < queues.size(); i++) {
|
||||
|
||||
BlockingQueue<TimestampedValue> q = queues.get(i);
|
||||
TimestampedValue ttcheck = q.peek();
|
||||
|
||||
if (ttcheck != null) {
|
||||
if (oldest == null) {
|
||||
// Update the oldest variable with current element
|
||||
oldest = ttcheck;
|
||||
indexes.clear();
|
||||
indexes.add(i);
|
||||
} else if (comparator.compare(ttcheck, oldest) < 0) {
|
||||
// Check whether timestamp is less (older) than the current oldest timestamp.
|
||||
oldest = ttcheck;
|
||||
indexes.clear();
|
||||
indexes.add(i);
|
||||
} else if (comparator.compare(ttcheck, oldest) == 0) {
|
||||
// SAME TIMESTAMP
|
||||
indexes.add(i);
|
||||
} else {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// logger.info("Index: "+index+" Permits: "+semaphore.availablePermits());
|
||||
// System.out.println("indexes: "+indexes.size());
|
||||
|
||||
if (indexes.size() > 0) {
|
||||
long timestamp = 0l;
|
||||
long nanoOffset = 0l;
|
||||
|
||||
for (Integer index : indexes) {
|
||||
// Get next older value
|
||||
cvalues[index] = queues.get(index).poll();
|
||||
|
||||
if (globalOldest != null) {
|
||||
if (comparator.compare(cvalues[index], globalOldest) >= 0) {
|
||||
// Update the global oldest variable
|
||||
globalOldest = cvalues[index];
|
||||
timestamp = cvalues[index].getTimestamp();
|
||||
nanoOffset = cvalues[index].getNanosecondsOffset();
|
||||
} else {
|
||||
// Monitors did not fire in sequence (an newer
|
||||
// monitor overtook an older (from an other IOC))
|
||||
logger.warning("Timestamped value out of sequence - discard value !!!!");
|
||||
// Continue with next value ...
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
globalOldest = cvalues[index];
|
||||
}
|
||||
}
|
||||
|
||||
// Assemble data message ...
|
||||
DataMessage message = new DataMessage(metadata);
|
||||
|
||||
message.getData().add(new Double(timestamp));
|
||||
message.getData().add(new Double(nanoOffset));
|
||||
|
||||
for (int y = 0; y < cvalues.length; y++) {
|
||||
if (cvalues[y] != null) {
|
||||
message.getData().add(new Double(cvalues[y].getValue()));
|
||||
} else {
|
||||
message.getData().add(Double.NaN);
|
||||
}
|
||||
}
|
||||
// System.out.println(message);
|
||||
eventbus.post(message);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public EventBus getEventBus(){
|
||||
return eventbus;
|
||||
}
|
||||
}
|
||||
@@ -1,114 +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.loops.cr;
|
||||
|
||||
import ch.psi.jcae.Channel;
|
||||
import ch.psi.jcae.annotation.CaChannel;
|
||||
|
||||
public class TemplateCrlogic {
|
||||
|
||||
/**
|
||||
* Ticks per second - IOC setting
|
||||
* ATTENTION - This field must only be set bu the IOC - ATTENTION
|
||||
*/
|
||||
@CaChannel(type=Integer.class, name ="${PREFIX}:TPS")
|
||||
private Channel<Integer> ticksPerSecond;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Message from the OTFSCAN IOC logic
|
||||
*/
|
||||
@CaChannel(type=String.class, name ="${PREFIX}:MSG")
|
||||
private Channel<String> message;
|
||||
|
||||
/**
|
||||
* IOC ticks between data acquisition interrupts
|
||||
*/
|
||||
@CaChannel(type=Integer.class, name ="${PREFIX}:TBINT")
|
||||
private Channel<Integer> ticksBetweenInterrupts;
|
||||
|
||||
/**
|
||||
* Name or ip address of the NFS server to save the data to
|
||||
* (depending on the IOC setup)
|
||||
*/
|
||||
@CaChannel(type=String.class, name ="${PREFIX}:NFSSE")
|
||||
private Channel<String> nfsServer;
|
||||
|
||||
/**
|
||||
* Name of the NFS share on the NFS server
|
||||
*/
|
||||
@CaChannel(type=String.class, name ="${PREFIX}:NFSSH")
|
||||
private Channel<String> nfsShare;
|
||||
|
||||
/**
|
||||
* Name of the data file
|
||||
*/
|
||||
@CaChannel(type=String.class, name ="${PREFIX}:DFNAM")
|
||||
private Channel<String> dataFile;
|
||||
|
||||
/**
|
||||
* Flag to identify whether the data file should be appended
|
||||
*/
|
||||
@CaChannel(type=Boolean.class, name ="${PREFIX}:FAPPE")
|
||||
private Channel<Boolean> appendFile;
|
||||
|
||||
/**
|
||||
* Readout resources
|
||||
*/
|
||||
@CaChannel(type=String[].class, name ="${PREFIX}:RRES")
|
||||
private Channel<String[]> readoutResources;
|
||||
|
||||
|
||||
|
||||
public Channel<Integer> getTicksPerSecond() {
|
||||
return ticksPerSecond;
|
||||
}
|
||||
public Channel<String> getStatus() {
|
||||
return status;
|
||||
}
|
||||
public Channel<String> getMessage() {
|
||||
return message;
|
||||
}
|
||||
public Channel<Integer> getTicksBetweenInterrupts() {
|
||||
return ticksBetweenInterrupts;
|
||||
}
|
||||
public Channel<String> getNfsServer() {
|
||||
return nfsServer;
|
||||
}
|
||||
public Channel<String> getNfsShare() {
|
||||
return nfsShare;
|
||||
}
|
||||
public Channel<String> getDataFile() {
|
||||
return dataFile;
|
||||
}
|
||||
public Channel<Boolean> getAppendFile() {
|
||||
return appendFile;
|
||||
}
|
||||
public Channel<String[]> getReadoutResources() {
|
||||
return readoutResources;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,59 +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.loops.cr;
|
||||
|
||||
import ch.psi.jcae.Channel;
|
||||
import ch.psi.jcae.annotation.CaChannel;
|
||||
|
||||
public class TemplateEncoder {
|
||||
|
||||
/**
|
||||
* Resolution - $(P)$(E)_SCL
|
||||
*/
|
||||
@CaChannel(type=Double.class, name="${PREFIX}_SCL")
|
||||
private Channel<Double> resolution;
|
||||
|
||||
/**
|
||||
* Offset - $(P)$(E)_OFF
|
||||
*/
|
||||
@CaChannel(type=Double.class, name ="${PREFIX}_OFF")
|
||||
private Channel<Double> offset;
|
||||
|
||||
/**
|
||||
* Direction - $(P)$(E)_DIR
|
||||
*/
|
||||
public enum Direction {Negative, Positive};
|
||||
@CaChannel(type=Integer.class, name ="${PREFIX}_DIR")
|
||||
private Channel<Integer> direction;
|
||||
|
||||
|
||||
|
||||
public Channel<Double> getResolution() {
|
||||
return resolution;
|
||||
}
|
||||
public Channel<Double> getOffset() {
|
||||
return offset;
|
||||
}
|
||||
public Channel<Integer> getDirection() {
|
||||
return direction;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,471 +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.loops.cr;
|
||||
|
||||
import ch.psi.jcae.Channel;
|
||||
import ch.psi.jcae.annotation.CaChannel;
|
||||
|
||||
public class TemplateMotor {
|
||||
|
||||
public enum Type {SOFT_CHANNEL, MOTOR_SIMULATION, OMS_VME58, OMS_MAXv};
|
||||
|
||||
/**
|
||||
* ## Drive section ##
|
||||
* # User coordinates #
|
||||
*/
|
||||
|
||||
/**
|
||||
* .HLM High limit - double
|
||||
*/
|
||||
@CaChannel(type=Double.class, name ="${PREFIX}.HLM")
|
||||
private Channel<Double> highLimit;
|
||||
|
||||
/**
|
||||
* .LLM Low limit - double
|
||||
*/
|
||||
@CaChannel(type=Double.class, name ="${PREFIX}.LLM")
|
||||
private Channel<Double> lowLimit;
|
||||
|
||||
/**
|
||||
* .RBV Readback value - double
|
||||
*/
|
||||
@CaChannel(type=Double.class, name ="${PREFIX}.RBV", monitor=true)
|
||||
private Channel<Double> readbackValue;
|
||||
|
||||
/**
|
||||
* .VAL Set value - double
|
||||
*/
|
||||
@CaChannel(type=Double.class, name ="${PREFIX}.VAL", monitor=true)
|
||||
private Channel<Double> setValue;
|
||||
|
||||
/**
|
||||
* .RLV Relative move value - double
|
||||
*/
|
||||
@CaChannel(type=Double.class, name ="${PREFIX}.RLV")
|
||||
private Channel<Double> relativeMoveValue;
|
||||
|
||||
/**
|
||||
* .TWV Teak value - double
|
||||
*/
|
||||
@CaChannel(type=Double.class, name ="${PREFIX}.TWV")
|
||||
private Channel<Double> tweakValue;
|
||||
|
||||
/**
|
||||
* .TWR Tweak reverse - move left - int
|
||||
*/
|
||||
@CaChannel(type=Integer.class, name ="${PREFIX}.TWR")
|
||||
private Channel<Integer> tweakReverse;
|
||||
|
||||
/**
|
||||
* .TWF Tweak forward - move right - int
|
||||
*/
|
||||
@CaChannel(type=Integer.class, name ="${PREFIX}.TWF")
|
||||
private Channel<Integer> tweakForward;
|
||||
|
||||
/**
|
||||
* .JOGR Jog reverse - int
|
||||
*/
|
||||
@CaChannel(type=Integer.class, name ="${PREFIX}.JOGR")
|
||||
private Channel<Integer> jogReverse;
|
||||
|
||||
/**
|
||||
* .JOGF Jog forward - int
|
||||
*/
|
||||
@CaChannel(type=Integer.class, name ="${PREFIX}.JOGF")
|
||||
private Channel<Integer> jogForward;
|
||||
|
||||
/**
|
||||
* .HOMR Home reverse - int
|
||||
*/
|
||||
@CaChannel(type=Integer.class, name ="${PREFIX}.HOMR")
|
||||
private Channel<Integer> homeReverse;
|
||||
|
||||
/**
|
||||
* .HOMF Home forward - int
|
||||
*/
|
||||
@CaChannel(type=Integer.class, name ="${PREFIX}.HOMF")
|
||||
private Channel<Integer> homeForward;
|
||||
|
||||
/**
|
||||
* .EGU Engineering unit - String
|
||||
*/
|
||||
@CaChannel(type=String.class, name ="${PREFIX}.EGU")
|
||||
private Channel<String> engineeringUnit;
|
||||
|
||||
/**
|
||||
* .DTYP Type - String (e.g. "OMS MAXv") see enum Type
|
||||
*/
|
||||
@CaChannel(type=Integer.class, name ="${PREFIX}.DTYP")
|
||||
private Channel<Integer> type;
|
||||
|
||||
/**
|
||||
* .DESC Description - String
|
||||
*/
|
||||
@CaChannel(type=String.class, name ="${PREFIX}.DESC")
|
||||
private Channel<String> description;
|
||||
|
||||
|
||||
/**
|
||||
* # Dial coordinates #
|
||||
*/
|
||||
|
||||
/**
|
||||
* .DHLM Dial high limit - double
|
||||
*/
|
||||
@CaChannel(type=Double.class, name ="${PREFIX}.DHLM")
|
||||
private Channel<Double> dialHighLimit;
|
||||
|
||||
/**
|
||||
* .DLLM Dial low limit - double
|
||||
*/
|
||||
@CaChannel(type=Double.class, name ="${PREFIX}.DLLM")
|
||||
private Channel<Double> dialLowLimit;
|
||||
|
||||
/**
|
||||
* .DRBV Dial readback value - double
|
||||
*/
|
||||
@CaChannel(type=Double.class, name ="${PREFIX}.DRBV", monitor=true)
|
||||
private Channel<Double> dialReadbackValue;
|
||||
|
||||
/**
|
||||
* .DVAL Dial set value - double
|
||||
*/
|
||||
@CaChannel(type=Double.class, name ="${PREFIX}.DVAL", monitor=true)
|
||||
private Channel<Double> dialSetValue;
|
||||
|
||||
/**
|
||||
* .RVAL Raw value - int
|
||||
*/
|
||||
@CaChannel(type=Integer.class, name ="${PREFIX}.RVAL", monitor=true)
|
||||
private Channel<Integer> rawValue;
|
||||
|
||||
/**
|
||||
* .RRBV Raw readback value - int
|
||||
*/
|
||||
@CaChannel(type=Integer.class, name ="${PREFIX}.RRBV", monitor=true)
|
||||
private Channel<Integer> rawReadbackValue;
|
||||
|
||||
/**
|
||||
* .SPMG Stop/Pause/Move/Go - (0:"Stop", 1:"Pause", 2:"Move", 3:"Go") - 3
|
||||
*/
|
||||
public enum Commands { Stop, Pause, Move, Go };
|
||||
@CaChannel(type=Integer.class, name ="${PREFIX}.SPMG")
|
||||
private Channel<Integer> command;
|
||||
|
||||
|
||||
/**
|
||||
* ## Calibration section ##
|
||||
*/
|
||||
|
||||
/**
|
||||
* .SET Set/Use Switch - (0:"Use", 1:"Set") - 0
|
||||
*/
|
||||
public enum Calibration {Use, Set};
|
||||
@CaChannel(type=Integer.class, name ="${PREFIX}.SET")
|
||||
private Channel<Integer> calibration;
|
||||
|
||||
/**
|
||||
* .OFF User offset (EGU) - double
|
||||
*/
|
||||
@CaChannel(type=Double.class, name ="${PREFIX}.OFF")
|
||||
private Channel<Double> offset;
|
||||
|
||||
/**
|
||||
* .FOFF Offset-Freeze Switch - (0:"Variable", 1:"Frozen") - 1
|
||||
*/
|
||||
public enum OffsetMode {Variable, Frozen};
|
||||
@CaChannel(type=Integer.class, name ="${PREFIX}.FOFF")
|
||||
private Channel<Integer> offsetMode;
|
||||
|
||||
/**
|
||||
* .DIR User direction - (0:"Pos", 1:"Neg")
|
||||
*/
|
||||
public enum Direction {Positive, Negative};
|
||||
@CaChannel(type=Integer.class, name ="${PREFIX}.DIR")
|
||||
private Channel<Integer> direction;
|
||||
|
||||
|
||||
/**
|
||||
* ## Dynamics ##
|
||||
*/
|
||||
|
||||
/**
|
||||
* .VELO Velocity (EGU/s) - double
|
||||
*/
|
||||
@CaChannel(type=Double.class, name ="${PREFIX}.VELO")
|
||||
private Channel<Double> velocity;
|
||||
|
||||
/**
|
||||
* .BVEL Backlash velocity (EGU/s) - double
|
||||
*/
|
||||
@CaChannel(type=Double.class, name ="${PREFIX}.BVEL")
|
||||
private Channel<Double> backlashVelocity;
|
||||
|
||||
/**
|
||||
* .VBAS Base speed (EGU/s) - double
|
||||
*/
|
||||
@CaChannel(type=Double.class, name ="${PREFIX}.VBAS")
|
||||
private Channel<Double> baseSpeed;
|
||||
|
||||
/**
|
||||
* .ACCL Acceleration time / seconds to velocity - double
|
||||
*/
|
||||
@CaChannel(type=Double.class, name ="${PREFIX}.ACCL")
|
||||
private Channel<Double> accelerationTime;
|
||||
|
||||
/**
|
||||
* .BACC Backlash acceleration time / seconds to velocity - double
|
||||
*/
|
||||
@CaChannel(type=Double.class, name ="${PREFIX}.BACC")
|
||||
private Channel<Double> backlashAccelerationTime;
|
||||
|
||||
/**
|
||||
* .BDST Backlash distance (EGU) - double
|
||||
*/
|
||||
@CaChannel(type=Double.class, name ="${PREFIX}.BDST")
|
||||
private Channel<Double> backlashDistance;
|
||||
|
||||
/**
|
||||
* .FRAC Move fraction - double
|
||||
*/
|
||||
@CaChannel(type=Double.class, name ="${PREFIX}.FRAC")
|
||||
private Channel<Double> moveFracion;
|
||||
|
||||
|
||||
/**
|
||||
* ## Resolution ##
|
||||
*/
|
||||
|
||||
/**
|
||||
* .MRES Motor resolution - double
|
||||
*/
|
||||
@CaChannel(type=Double.class, name ="${PREFIX}.MRES")
|
||||
private Channel<Double> motorResolution;
|
||||
|
||||
/**
|
||||
* .ERES Encoder resolution - double
|
||||
*/
|
||||
@CaChannel(type=Double.class, name ="${PREFIX}.ERES")
|
||||
private Channel<Double> encoderResolution;
|
||||
|
||||
/**
|
||||
* .RRES Readback resolution - double
|
||||
*/
|
||||
@CaChannel(type=Double.class, name ="${PREFIX}.RRES")
|
||||
private Channel<Double> readbackResolution;
|
||||
|
||||
/**
|
||||
* .RDBD Retry deadband (EGU) - double
|
||||
*/
|
||||
@CaChannel(type=Double.class, name ="${PREFIX}.RDBD")
|
||||
private Channel<Double> retryDeadband;
|
||||
|
||||
/**
|
||||
* .RTRY Max retry count - int
|
||||
*/
|
||||
@CaChannel(type=Integer.class, name ="${PREFIX}.RTRY")
|
||||
private Channel<Integer> maxRetryCount;
|
||||
|
||||
/**
|
||||
* .RCNT Retry count - int
|
||||
*/
|
||||
@CaChannel(type=Integer.class, name ="${PREFIX}.RCNT", monitor=true)
|
||||
private Channel<Integer> retryCount;
|
||||
|
||||
/**
|
||||
* .UEIP Use encoder (if present) - (0:"No", 1:"Yes")
|
||||
*/
|
||||
@CaChannel(type=Boolean.class, name ="${PREFIX}.UEIP")
|
||||
private Channel<Boolean> useEncoder;
|
||||
|
||||
/**
|
||||
* .URIP Use readback link (if present) - (0:"No", 1:"Yes")
|
||||
*/
|
||||
@CaChannel(type=Boolean.class, name ="${PREFIX}.URIP")
|
||||
private Channel<Boolean> useReadback;
|
||||
|
||||
/**
|
||||
* .DLY Readback delay (s) - double
|
||||
*/
|
||||
@CaChannel(type=Double.class, name ="${PREFIX}.DLY")
|
||||
private Channel<Double> readbackDelay;
|
||||
|
||||
/**
|
||||
* .RDBL Readback link - String
|
||||
*/
|
||||
@CaChannel(type=String.class, name ="${PREFIX}.RDBL")
|
||||
private Channel<String> readbackLink;
|
||||
|
||||
/**
|
||||
* .OMSL Output mode select - (0:"supervisory", 1:"closed_loop")
|
||||
*/
|
||||
public enum OutputMode {Supervisory, Closed_Loop};
|
||||
@CaChannel(type=Integer.class, name ="${PREFIX}.OMSL")
|
||||
private Channel<Integer> outputMode;
|
||||
|
||||
/**
|
||||
* ## Status ##
|
||||
*/
|
||||
|
||||
/**
|
||||
* .DMOV Done move - int
|
||||
*/
|
||||
@CaChannel(type=Boolean.class, name ="${PREFIX}.DMOV", monitor=true)
|
||||
private Channel<Boolean> moveDone;
|
||||
|
||||
|
||||
|
||||
public Channel<Double> getHighLimit() {
|
||||
return highLimit;
|
||||
}
|
||||
public Channel<Double> getLowLimit() {
|
||||
return lowLimit;
|
||||
}
|
||||
public Channel<Double> getReadbackValue() {
|
||||
return readbackValue;
|
||||
}
|
||||
public Channel<Double> getSetValue() {
|
||||
return setValue;
|
||||
}
|
||||
public Channel<Double> getRelativeMoveValue() {
|
||||
return relativeMoveValue;
|
||||
}
|
||||
public Channel<Double> getTweakValue() {
|
||||
return tweakValue;
|
||||
}
|
||||
public Channel<Integer> getTweakReverse() {
|
||||
return tweakReverse;
|
||||
}
|
||||
public Channel<Integer> getTweakForward() {
|
||||
return tweakForward;
|
||||
}
|
||||
public Channel<Integer> getJogReverse() {
|
||||
return jogReverse;
|
||||
}
|
||||
public Channel<Integer> getJogForward() {
|
||||
return jogForward;
|
||||
}
|
||||
public Channel<Integer> getHomeReverse() {
|
||||
return homeReverse;
|
||||
}
|
||||
public Channel<Integer> getHomeForward() {
|
||||
return homeForward;
|
||||
}
|
||||
public Channel<String> getEngineeringUnit() {
|
||||
return engineeringUnit;
|
||||
}
|
||||
public Channel<Integer> getType() {
|
||||
return type;
|
||||
}
|
||||
public Channel<String> getDescription() {
|
||||
return description;
|
||||
}
|
||||
public Channel<Double> getDialHighLimit() {
|
||||
return dialHighLimit;
|
||||
}
|
||||
public Channel<Double> getDialLowLimit() {
|
||||
return dialLowLimit;
|
||||
}
|
||||
public Channel<Double> getDialReadbackValue() {
|
||||
return dialReadbackValue;
|
||||
}
|
||||
public Channel<Double> getDialSetValue() {
|
||||
return dialSetValue;
|
||||
}
|
||||
public Channel<Integer> getRawValue() {
|
||||
return rawValue;
|
||||
}
|
||||
public Channel<Integer> getRawReadbackValue() {
|
||||
return rawReadbackValue;
|
||||
}
|
||||
public Channel<Integer> getCommand() {
|
||||
return command;
|
||||
}
|
||||
public Channel<Integer> getCalibration() {
|
||||
return calibration;
|
||||
}
|
||||
public Channel<Double> getOffset() {
|
||||
return offset;
|
||||
}
|
||||
public Channel<Integer> getOffsetMode() {
|
||||
return offsetMode;
|
||||
}
|
||||
public Channel<Integer> getDirection() {
|
||||
return direction;
|
||||
}
|
||||
public Channel<Double> getVelocity() {
|
||||
return velocity;
|
||||
}
|
||||
public Channel<Double> getBacklashVelocity() {
|
||||
return backlashVelocity;
|
||||
}
|
||||
public Channel<Double> getBaseSpeed() {
|
||||
return baseSpeed;
|
||||
}
|
||||
public Channel<Double> getAccelerationTime() {
|
||||
return accelerationTime;
|
||||
}
|
||||
public Channel<Double> getBacklashAccelerationTime() {
|
||||
return backlashAccelerationTime;
|
||||
}
|
||||
public Channel<Double> getBacklashDistance() {
|
||||
return backlashDistance;
|
||||
}
|
||||
public Channel<Double> getMoveFracion() {
|
||||
return moveFracion;
|
||||
}
|
||||
public Channel<Double> getMotorResolution() {
|
||||
return motorResolution;
|
||||
}
|
||||
public Channel<Double> getEncoderResolution() {
|
||||
return encoderResolution;
|
||||
}
|
||||
public Channel<Double> getReadbackResolution() {
|
||||
return readbackResolution;
|
||||
}
|
||||
public Channel<Double> getRetryDeadband() {
|
||||
return retryDeadband;
|
||||
}
|
||||
public Channel<Integer> getMaxRetryCount() {
|
||||
return maxRetryCount;
|
||||
}
|
||||
public Channel<Integer> getRetryCount() {
|
||||
return retryCount;
|
||||
}
|
||||
public Channel<Boolean> getUseEncoder() {
|
||||
return useEncoder;
|
||||
}
|
||||
public Channel<Boolean> getUseReadback() {
|
||||
return useReadback;
|
||||
}
|
||||
public Channel<Double> getReadbackDelay() {
|
||||
return readbackDelay;
|
||||
}
|
||||
public Channel<String> getReadbackLink() {
|
||||
return readbackLink;
|
||||
}
|
||||
public Channel<Integer> getOutputMode() {
|
||||
return outputMode;
|
||||
}
|
||||
public Channel<Boolean> getMoveDone() {
|
||||
return moveDone;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,80 +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.loops.cr;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import ch.psi.jcae.Channel;
|
||||
import ch.psi.jcae.annotation.CaChannel;
|
||||
|
||||
public class TemplateVSC16Scaler {
|
||||
|
||||
/**
|
||||
* Command
|
||||
*/
|
||||
public enum Command {Done, Count};
|
||||
@CaChannel(type=Integer.class, name ="${PREFIX}.CNT")
|
||||
private Channel<Integer> command;
|
||||
|
||||
|
||||
public enum Mode {OneShot, AutoCount};
|
||||
/**
|
||||
* Count mode
|
||||
*/
|
||||
@CaChannel(type=Integer.class, name ="${PREFIX}.CONT")
|
||||
private Channel<Integer> mode;
|
||||
|
||||
/**
|
||||
* Channel description
|
||||
*/
|
||||
@CaChannel(type=Boolean.class, name={"${PREFIX}.NM1", "${PREFIX}.NM2", "${PREFIX}.NM3", "${PREFIX}.NM4", "${PREFIX}.NM5", "${PREFIX}.NM6", "${PREFIX}.NM7", "${PREFIX}.NM8", "${PREFIX}.NM9", "${PREFIX}.NM10", "${PREFIX}.NM11", "${PREFIX}.NM12", "${PREFIX}.NM13", "${PREFIX}.NM14", "${PREFIX}.NM15", "${PREFIX}.NM16"})
|
||||
private List<Channel<Boolean>> channelDescription;
|
||||
|
||||
/**
|
||||
* Channel gate
|
||||
*/
|
||||
@CaChannel(type=Boolean.class, name={"${PREFIX}.G1", "${PREFIX}.G2", "${PREFIX}.G3", "${PREFIX}.G4", "${PREFIX}.G5", "${PREFIX}.G6", "${PREFIX}.G7", "${PREFIX}.G8", "${PREFIX}.G9", "${PREFIX}.G10", "${PREFIX}.G11", "${PREFIX}.G12", "${PREFIX}.G13", "${PREFIX}.G14", "${PREFIX}.G15", "${PREFIX}.G16"})
|
||||
private List<Channel<Boolean>> channelGate;
|
||||
|
||||
/**
|
||||
* Channel preset count
|
||||
* If gate is on scaler will only count until this value
|
||||
*/
|
||||
@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;
|
||||
|
||||
|
||||
|
||||
public Channel<Integer> getCommand() {
|
||||
return command;
|
||||
}
|
||||
public Channel<Integer> getMode() {
|
||||
return mode;
|
||||
}
|
||||
public List<Channel<Boolean>> getChannelDescription() {
|
||||
return channelDescription;
|
||||
}
|
||||
public List<Channel<Boolean>> getChannelGate() {
|
||||
return channelGate;
|
||||
}
|
||||
public List<Channel<Integer>> getChannelPresetCount() {
|
||||
return channelPresetCount;
|
||||
}
|
||||
}
|
||||
@@ -1,43 +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.loops.cr;
|
||||
|
||||
public class TimestampedValue {
|
||||
|
||||
private final Double value;
|
||||
private final long timestamp;
|
||||
private final long nanosecondsOffset;
|
||||
|
||||
public TimestampedValue(Double value, long timestamp, long nanosecondsOffset){
|
||||
this.value = value;
|
||||
this.timestamp = timestamp;
|
||||
this.nanosecondsOffset = nanosecondsOffset;
|
||||
}
|
||||
|
||||
public Double getValue() {
|
||||
return value;
|
||||
}
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
public long getNanosecondsOffset() {
|
||||
return nanosecondsOffset;
|
||||
}
|
||||
}
|
||||
@@ -1,44 +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.loops.cr;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
/**
|
||||
* Comparator for comparint 2 timestamped values
|
||||
*/
|
||||
public class TimestampedValueComparator implements Comparator<TimestampedValue> {
|
||||
|
||||
@Override
|
||||
public int compare(TimestampedValue o1, TimestampedValue o2) {
|
||||
if (o1.getTimestamp() < o2.getTimestamp()) {
|
||||
return -1;
|
||||
} else if (o1.getTimestamp() > o2.getTimestamp()) {
|
||||
return 1;
|
||||
} else if (o1.getTimestamp() == o2.getTimestamp()) {
|
||||
if (o1.getNanosecondsOffset() < o2.getNanosecondsOffset()) {
|
||||
return -1;
|
||||
} else if (o1.getNanosecondsOffset() > o2.getNanosecondsOffset()) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -1,158 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* Copyright 2012 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.otf;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.MalformedURLException;
|
||||
|
||||
import jcifs.smb.SmbFile;
|
||||
|
||||
public class DistributedFile {
|
||||
|
||||
private SmbFile smbfile = null;
|
||||
private File file = null;
|
||||
|
||||
public DistributedFile(SmbFile file){
|
||||
this.smbfile = file;
|
||||
}
|
||||
|
||||
public DistributedFile(File file){
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
public DistributedFile(String url) throws MalformedURLException{
|
||||
if(url.startsWith("smb://")){
|
||||
smbfile = new SmbFile(url);
|
||||
}
|
||||
else {
|
||||
file = new File(url);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public String getCanonicalPath() throws IOException{
|
||||
if(smbfile!=null){
|
||||
return(smbfile.getCanonicalPath());
|
||||
}
|
||||
else{
|
||||
return file.getCanonicalPath();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
public boolean exists() throws IOException {
|
||||
if(smbfile!=null){
|
||||
return(smbfile.exists());
|
||||
}
|
||||
else{
|
||||
return file.exists();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public boolean isDirectory() throws IOException {
|
||||
if(smbfile!=null){
|
||||
return(smbfile.isDirectory());
|
||||
}
|
||||
else{
|
||||
return file.isDirectory();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public DistributedFile[] listFiles() throws IOException {
|
||||
if(smbfile!=null){
|
||||
SmbFile[] files = smbfile.listFiles();
|
||||
DistributedFile[] dfiles = new DistributedFile[files.length];
|
||||
for(int i=0;i<files.length;i++){
|
||||
dfiles[i] = new DistributedFile(files[i]);
|
||||
}
|
||||
return(dfiles);
|
||||
}
|
||||
else{
|
||||
File[] files = file.listFiles();
|
||||
DistributedFile[] dfiles = new DistributedFile[files.length];
|
||||
for(int i=0;i<files.length;i++){
|
||||
dfiles[i] = new DistributedFile(files[i]);
|
||||
}
|
||||
return(dfiles);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public String getName() {
|
||||
if(smbfile!=null){
|
||||
return(smbfile.getName());
|
||||
}
|
||||
else{
|
||||
return file.getName();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public boolean isFile() throws IOException {
|
||||
if(smbfile!=null){
|
||||
return(smbfile.isFile());
|
||||
}
|
||||
else{
|
||||
return file.isFile();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public void delete() throws IOException {
|
||||
if(smbfile!=null){
|
||||
smbfile.delete();
|
||||
}
|
||||
else{
|
||||
file.delete();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public InputStreamReader getInputStream() throws IOException {
|
||||
if(smbfile!=null){
|
||||
return(new InputStreamReader(smbfile.getInputStream()));
|
||||
}
|
||||
else{
|
||||
return new FileReader(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,439 +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.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.List;
|
||||
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.sensors.TimestampSensor;
|
||||
import ch.psi.fda.messages.DataMessage;
|
||||
import ch.psi.fda.messages.EndOfStreamMessage;
|
||||
import ch.psi.fda.messages.Metadata;
|
||||
|
||||
/**
|
||||
* ActionLoop that is implementing the OTF Scan logic.
|
||||
* While executing the loop a full OTF scan procedure is executed.
|
||||
*/
|
||||
public class OTFLoop implements ActionLoop {
|
||||
|
||||
private static Logger logger = Logger.getLogger(OTFLoop.class.getName());
|
||||
|
||||
/**
|
||||
* Flag to indicate whether the data of this loop will be grouped
|
||||
* According to this flag the dataGroup flag in EndOfStream will be set.
|
||||
*/
|
||||
private boolean dataGroup = false;
|
||||
|
||||
/**
|
||||
* Maximum number of monitored channels
|
||||
*/
|
||||
private static final int numberOfMonitoredChannels = 8;
|
||||
/**
|
||||
* Maximum number of Scaler channels
|
||||
*/
|
||||
private static final int numberOfScalerChannels = 16;
|
||||
|
||||
/**
|
||||
* Default timeout (in milliseconds) for wait operations
|
||||
*/
|
||||
private long timeout = 8000;
|
||||
|
||||
/**
|
||||
* Name of the NFS server to place the data of the OTF logic
|
||||
*/
|
||||
private final String server;
|
||||
/**
|
||||
* Share on the NFS server to put the OTF data on to
|
||||
*/
|
||||
private final String share;
|
||||
/**
|
||||
* SMB share to access the data written by the OTF C logic
|
||||
*/
|
||||
private final String smbShare;
|
||||
|
||||
/**
|
||||
* Flag whether the actor of this loop should move in zig zag mode
|
||||
*/
|
||||
private final boolean zigZag;
|
||||
|
||||
/**
|
||||
* Bean holding all OTF channels and functionality.
|
||||
*/
|
||||
private TemplateOTF obean;
|
||||
|
||||
/**
|
||||
* List of actions that are executed at the beginning of the loop.
|
||||
*/
|
||||
private List<Action> preActions;
|
||||
/**
|
||||
* List of actions that are executed at the end of the loop.
|
||||
*/
|
||||
private List<Action> postActions;
|
||||
|
||||
/**
|
||||
* List of sensors of this loop
|
||||
*/
|
||||
private List<Sensor> sensors;
|
||||
|
||||
|
||||
private List<Integer> dataIndexes;
|
||||
|
||||
/**
|
||||
* Execution count of this loop. This count is used to determine the
|
||||
* file name of the OTF file.
|
||||
*/
|
||||
private int executionCount;
|
||||
|
||||
/**
|
||||
* Flag that indicates that the loop was requested to abort.
|
||||
*/
|
||||
private volatile boolean abort = false;
|
||||
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* @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(TemplateOTF obean, String server, String share, String smbShare, boolean zigZag){
|
||||
|
||||
this.eventbus = new EventBus();
|
||||
|
||||
this.obean = obean;
|
||||
|
||||
// Store loop configuration
|
||||
this.server = server;
|
||||
this.share = share;
|
||||
this.smbShare = smbShare;
|
||||
this.zigZag = zigZag;
|
||||
|
||||
// Initialize lists used by the loop
|
||||
this.preActions = new ArrayList<Action>();
|
||||
this.postActions = new ArrayList<Action>();
|
||||
this.sensors = new ArrayList<Sensor>();
|
||||
}
|
||||
|
||||
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 {
|
||||
|
||||
// Execute pre actions
|
||||
for(Action action: preActions){
|
||||
action.execute();
|
||||
}
|
||||
|
||||
// Start scan
|
||||
obean.start();
|
||||
|
||||
// Wait for end of scan
|
||||
obean.waitUntilStopped();
|
||||
|
||||
// Read data from file
|
||||
collectData();
|
||||
|
||||
// Execute post actions
|
||||
for(Action action: postActions){
|
||||
action.execute();
|
||||
}
|
||||
|
||||
|
||||
// Issue end of loop control message
|
||||
eventbus.post(new EndOfStreamMessage(dataGroup));
|
||||
|
||||
// Increase execution count
|
||||
executionCount++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void abort() {
|
||||
// Abort otf scan logic
|
||||
obean.abort();
|
||||
|
||||
abort=true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepare() {
|
||||
executionCount = 0;
|
||||
|
||||
// Set abort flag to false
|
||||
abort=false;
|
||||
|
||||
// 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){
|
||||
// Monitored channel
|
||||
OTFNamedChannelSensor so = (OTFNamedChannelSensor) s;
|
||||
if(channelCount>=numberOfMonitoredChannels){
|
||||
throw new IllegalArgumentException("Only up to "+numberOfMonitoredChannels+" channels can be monitored by OTF");
|
||||
}
|
||||
|
||||
monitoredChannels.add(so.getName());
|
||||
dataIndexes.add(2+numberOfScalerChannels+channelCount);
|
||||
|
||||
|
||||
channelCount++;
|
||||
}
|
||||
else if (s instanceof OTFScalerChannelSensor){
|
||||
OTFScalerChannelSensor so = (OTFScalerChannelSensor) s;
|
||||
if(so.getIndex()>=numberOfScalerChannels){
|
||||
throw new IllegalArgumentException("Scaler index must be between 0<=index<"+numberOfScalerChannels);
|
||||
}
|
||||
dataIndexes.add(2+so.getIndex()); // scalers follow directly after the readback
|
||||
}
|
||||
else if (s instanceof TimestampSensor){
|
||||
dataIndexes.add(2+numberOfScalerChannels+numberOfMonitoredChannels);
|
||||
}
|
||||
// else if (s instanceof OTFReadbackSensor){
|
||||
// dataIndexes.add(1);
|
||||
// }
|
||||
else{
|
||||
throw new IllegalArgumentException("Sensor type "+s.getClass()+" is not supported by this loop");
|
||||
}
|
||||
}
|
||||
|
||||
// Set OTF parameters
|
||||
try{
|
||||
obean.resetToDefaults();
|
||||
|
||||
// Set actor properties
|
||||
obean.setMotor(this.name);
|
||||
obean.waitUntilMotorOk(timeout);
|
||||
|
||||
obean.setBegin(this.start);
|
||||
obean.setEnd(this.end);
|
||||
obean.setStepSize(this.stepSize);
|
||||
obean.setIntegrationTime(this.integrationTime);
|
||||
|
||||
// Override encoder if specified
|
||||
if(this.readback!=null){
|
||||
obean.setUseEncoder(true);
|
||||
obean.setEncoder(this.readback);
|
||||
obean.waitUntilEncoderOk(timeout);
|
||||
}
|
||||
|
||||
// Set user backlash
|
||||
obean.setUserBacklash(this.additionalBacklash);
|
||||
|
||||
|
||||
// NFS settings
|
||||
obean.setNfsServer(server);
|
||||
obean.setNfsShare(share);
|
||||
|
||||
obean.setFileNameGeneration(true);
|
||||
obean.setAppendFile(false);
|
||||
obean.setZigZag(zigZag); // Set ZigZag because there might be iterations
|
||||
obean.setFileNameFormat("%06d"); // Force an update of the filename/counter by setting file format twice with different values
|
||||
obean.setFileNameFormat("%06d.txt");
|
||||
|
||||
|
||||
|
||||
// Set monitored channels
|
||||
obean.setMonitoredChannels(monitoredChannels.toArray(new String[monitoredChannels.size()]));
|
||||
}
|
||||
catch(Exception e){
|
||||
throw new RuntimeException("Unable to set OTF configuration parameters",e);
|
||||
}
|
||||
|
||||
|
||||
// Cleanup temporary directory
|
||||
try{
|
||||
DistributedFile tmpDir = new DistributedFile(smbShare);
|
||||
if( !tmpDir.exists() || !tmpDir.isDirectory() ){
|
||||
throw new RuntimeException("Cannot access OTF temporary directory "+tmpDir.getCanonicalPath());
|
||||
}
|
||||
DistributedFile[] files = tmpDir.listFiles();
|
||||
|
||||
for(int i=0;i<files.length;i++){
|
||||
// Only delete item if it is not a directory and if it matches the given pattern.
|
||||
if(files[i].isFile() && files[i].getName().matches("[0-9]+.txt")){
|
||||
files[i].delete();
|
||||
logger.fine("Delete file: "+files[i].getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(MalformedURLException e){
|
||||
throw new RuntimeException(e);
|
||||
} catch (IOException e) {
|
||||
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()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanup() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Action> getPreActions() {
|
||||
return preActions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Action> getPostActions() {
|
||||
return postActions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect data written by the OTFScan logic
|
||||
* @param dataSet
|
||||
* @param tmpFile
|
||||
*/
|
||||
private void collectData() {
|
||||
try{
|
||||
final int timestampIndex = 2+numberOfScalerChannels+numberOfMonitoredChannels;
|
||||
|
||||
DistributedFile tmpFile = new DistributedFile(smbShare +"/"+ String.format("%06d.txt", executionCount));
|
||||
logger.fine("Collect data from "+tmpFile.getCanonicalPath());
|
||||
|
||||
DistributedFile lockfile = new DistributedFile(tmpFile.getCanonicalPath() + ".lock");
|
||||
|
||||
logger.fine("Wait until file is written [lock file: "+lockfile.getCanonicalPath()+"]");
|
||||
// Wait until file is created
|
||||
while ((!tmpFile.exists()) || lockfile.exists()) {
|
||||
Thread.sleep(500);
|
||||
if(abort){
|
||||
// If abort is issued while waiting for data immediately return without
|
||||
// trying to read the data
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
logger.fine("Read file " + tmpFile.getCanonicalPath());
|
||||
InputStreamReader inreader = tmpFile.getInputStream();
|
||||
BufferedReader in = new BufferedReader(inreader);
|
||||
String line;
|
||||
boolean firstline = true;
|
||||
while (true) {
|
||||
line = in.readLine();
|
||||
if (line == null) {
|
||||
break;
|
||||
} else {
|
||||
if(line.matches("^\\[.*")){
|
||||
// Skip header lines
|
||||
}
|
||||
else{
|
||||
if(firstline){
|
||||
firstline=false;
|
||||
continue;
|
||||
}
|
||||
|
||||
DataMessage message = new DataMessage(metadata);
|
||||
// Add data to dataset
|
||||
String[] tokens = line.split("\t");
|
||||
|
||||
for(Integer i: dataIndexes){
|
||||
try{
|
||||
if(i == timestampIndex) {
|
||||
// Calculate time in milliseconds
|
||||
Double seconds = new Double(tokens[i]);
|
||||
Double nanoseconds = new Double(tokens[i+1]);
|
||||
|
||||
Double v = seconds*1000+Math.floor(nanoseconds*0.000001);
|
||||
message.getData().add(v);
|
||||
}
|
||||
else {
|
||||
|
||||
message.getData().add(new Double(tokens[i]));
|
||||
}
|
||||
}
|
||||
catch(NumberFormatException e){
|
||||
logger.warning("Cannot parse component ["+tokens[i]+"] from source file - will add 0 for this component");
|
||||
message.getData().add(new Double(0));
|
||||
}
|
||||
}
|
||||
eventbus.post(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
in.close();
|
||||
inreader.close();
|
||||
} catch(InterruptedException e){
|
||||
throw new RuntimeException("An interrupt occured while waiting for the file to show up",e);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("An IO Exception occured while reading the OTF data file",e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public List<Sensor> getSensors() {
|
||||
return sensors;
|
||||
}
|
||||
public boolean isDataGroup() {
|
||||
return dataGroup;
|
||||
}
|
||||
public void setDataGroup(boolean dataGroup) {
|
||||
this.dataGroup = dataGroup;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ch.psi.fda.core.ActionLoop#getEventBus()
|
||||
*/
|
||||
@Override
|
||||
public EventBus getEventBus() {
|
||||
return eventbus;
|
||||
}
|
||||
}
|
||||
@@ -1,69 +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.loops.otf;
|
||||
|
||||
import ch.psi.fda.core.Sensor;
|
||||
|
||||
/**
|
||||
* Sensor to read out a named (Epics) 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 OTFNamedChannelSensor implements Sensor {
|
||||
|
||||
/**
|
||||
* Name of the channel
|
||||
*/
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* Global id of the sensor
|
||||
*/
|
||||
private final String id;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param id Global id of the sensor
|
||||
* @param name Name of the (Epics) channel
|
||||
*/
|
||||
public OTFNamedChannelSensor(String id, String name){
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object read() {
|
||||
// Always return 0 if read() method is called.
|
||||
return 0d;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the name of the channel
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
@@ -1,67 +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.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.
|
||||
*
|
||||
*/
|
||||
public class OTFScalerChannelSensor implements Sensor {
|
||||
|
||||
/**
|
||||
* Index of the scaler channel. The index starts at 0;
|
||||
*/
|
||||
private final int index;
|
||||
|
||||
/**
|
||||
* Global id of the sensor
|
||||
*/
|
||||
private final String id;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param id Global id of the sensor
|
||||
* @param index Index of the scaler channel. Index starts at 0.
|
||||
*/
|
||||
public OTFScalerChannelSensor(String id, int index){
|
||||
this.id = id;
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object read() {
|
||||
return 0d;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the index of the scaler channel
|
||||
*/
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
@@ -1,964 +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.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;
|
||||
|
||||
/**
|
||||
* Bean holding all OTF channels and functionality
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
public class TemplateOTF {
|
||||
|
||||
public enum Status { SETUP, INACTIVE, INITIALIZE, ACTIVE, STOP, FAULT, ERROR };
|
||||
public enum Command { NONE, START, STOP };
|
||||
|
||||
private long timeoutMotorOk = 8000;
|
||||
private long commandTimeout = 20000; // Maximum time until a command should take effect
|
||||
|
||||
@CaChannel(type=String.class, name ="${PREFIX}:UMOT")
|
||||
private Channel<String> motor;
|
||||
|
||||
@CaChannel(type=String.class, name="${PREFIX}:MENC")
|
||||
private Channel<String> encoder;
|
||||
|
||||
@CaChannel(type=Double.class, name="${PREFIX}:UBEG")
|
||||
private Channel<Double> begin;
|
||||
|
||||
@CaChannel(type=Double.class, name="${PREFIX}:UBEG.DRVL")
|
||||
private Channel<Double> beginMin;
|
||||
|
||||
@CaChannel(type=Double.class, name="${PREFIX}:UBEG.DRVH")
|
||||
private Channel<Double> beginMax;
|
||||
|
||||
@CaChannel(type=Double.class, name="${PREFIX}:UEND")
|
||||
private Channel<Double> end;
|
||||
|
||||
@CaChannel(type=Double.class, name="${PREFIX}:UEND.DRVL")
|
||||
private Channel<Double> endMin;
|
||||
|
||||
@CaChannel(type=Double.class, name="${PREFIX}:UEND.DRVH")
|
||||
private Channel<Double> endMax;
|
||||
|
||||
@CaChannel(type=Double.class, name="${PREFIX}:USSIZ")
|
||||
private Channel<Double> stepSize;
|
||||
|
||||
@CaChannel(type=Double.class, name="${PREFIX}:USSIZ.DRVL")
|
||||
private Channel<Double> stepSizeMin;
|
||||
|
||||
@CaChannel(type=Double.class, name="${PREFIX}:UITIM")
|
||||
private Channel<Double> integrationTime;
|
||||
|
||||
@CaChannel(type=Double.class, name="${PREFIX}:UITIM.DRVL")
|
||||
private Channel<Double> integrationTimeMin;
|
||||
|
||||
@CaChannel(type=Double.class, name="${PREFIX}:UITIM.DRVH")
|
||||
private Channel<Double> integrationTimeMax;
|
||||
|
||||
@CaChannel(type=Double.class, name="${PREFIX}:UBCL")
|
||||
private Channel<Double> userBacklash;
|
||||
|
||||
@CaChannel(type=String.class, name="${PREFIX}:NFSSE")
|
||||
private Channel<String> nfsServer;
|
||||
|
||||
@CaChannel(type=String.class, name="${PREFIX}:NFSSH")
|
||||
private Channel<String> nfsShare;
|
||||
|
||||
@CaChannel(type=String.class, name="${PREFIX}:DFNAM")
|
||||
private Channel<String> fileName;
|
||||
|
||||
@CaChannel(type=String.class, name="${PREFIX}:FFORM")
|
||||
private Channel<String> fileNameFormat;
|
||||
|
||||
@CaChannel(type=Integer.class, name="${PREFIX}:FCNT")
|
||||
private Channel<Integer> fileCount;
|
||||
|
||||
@CaChannel(type=Integer.class, name="${PREFIX}:FCNT.B")
|
||||
private Channel<Integer> resetFileCounter;
|
||||
|
||||
@CaChannel(type=Boolean.class, name="${PREFIX}:FAPPE")
|
||||
private Channel<Boolean> appendFile;
|
||||
|
||||
@CaChannel(type=Boolean.class, name="${PREFIX}:FUSE")
|
||||
private Channel<Boolean> fileNameGeneration;
|
||||
|
||||
@CaChannel(type=Boolean.class, name="${PREFIX}:UZIGZ")
|
||||
private Channel<Boolean> zigZag;
|
||||
|
||||
@CaChannel(type=Integer.class, name="${PREFIX}:UCOM")
|
||||
private Channel<Integer> command;
|
||||
|
||||
@CaChannel(type=Boolean.class, name="${PREFIX}:SCRU", monitor=true)
|
||||
private Channel<Boolean> scanRunning;
|
||||
|
||||
@CaChannel(type=Boolean.class, name="${PREFIX}:MUENC")
|
||||
private Channel<Boolean> useEncoder;
|
||||
|
||||
@CaChannel(type=String.class, name={"${PREFIX}:CTM0","${PREFIX}:CTM1","${PREFIX}:CTM2","${PREFIX}:CTM3","${PREFIX}:CTM4","${PREFIX}:CTM5","${PREFIX}:CTM6","${PREFIX}:CTM7"})
|
||||
private List<Channel<String>> monitoredChannels;
|
||||
|
||||
@CaChannel(type=Boolean.class, name="${PREFIX}:OTF", monitor=true)
|
||||
private Channel<Boolean> running;
|
||||
|
||||
@CaChannel(type=Integer.class, name="${PREFIX}:USTAT", monitor=true)
|
||||
private Channel<Integer> status;
|
||||
|
||||
@CaChannel(type=Boolean.class, name="${PREFIX}:MOK", monitor=true)
|
||||
private Channel<Boolean> motorOk;
|
||||
|
||||
@CaChannel(type=Boolean.class, name="${PREFIX}:EOK", monitor=true)
|
||||
private Channel<Boolean> encoderOk;
|
||||
|
||||
@CaChannel(type=String.class, name="${PREFIX}:MSG")
|
||||
private Channel<String> message;
|
||||
|
||||
/**
|
||||
* Get the trigger name that can be used by the sscan record to trigger an OTFScan
|
||||
* @return Name of the trigger that can be used by sscan record
|
||||
*/
|
||||
public String getSScanTriggerName(){
|
||||
return(running.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Start OTF scan
|
||||
*/
|
||||
public void start() {
|
||||
try{
|
||||
if(getStatus().equals(Status.INACTIVE)){
|
||||
|
||||
// Send START command
|
||||
this.command.setValue(Command.START.ordinal());
|
||||
|
||||
// Wait until OtF logic is active
|
||||
this.scanRunning.waitForValue(true, commandTimeout);
|
||||
}
|
||||
else{
|
||||
throw new RuntimeException("Cannot start scan, status is not INACTIVE.\nThe current status is: "+getStatus()+" . The OTF logic need to be recovered manually [Message: "+getMessage()+"]");
|
||||
}
|
||||
}
|
||||
catch(Exception e){
|
||||
throw new RuntimeException("Unable to start OTF scan.",e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Abort scan
|
||||
*/
|
||||
public void abort() {
|
||||
try{
|
||||
// Send STOP command
|
||||
this.command.setValue(Command.STOP.ordinal());
|
||||
|
||||
// Do not wait for put to return
|
||||
this.running.setValueNoWait(false);
|
||||
}
|
||||
catch(Exception e){
|
||||
throw new RuntimeException("Unable to abort OTF logic" ,e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop OTF scan
|
||||
* @throws Exception
|
||||
*/
|
||||
public void stop() throws Exception{
|
||||
if(!getStatus().equals(Status.INACTIVE) || !getStatus().equals(Status.FAULT)){
|
||||
|
||||
// Send STOP command
|
||||
this.command.setValue(Command.STOP.ordinal());
|
||||
|
||||
// Wait until logic is stopped
|
||||
status.waitForValue(Status.INACTIVE.ordinal(), commandTimeout);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait until scan has stopped
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public void waitUntilStopped() throws InterruptedException {
|
||||
try {
|
||||
scanRunning.waitForValue(false); // Use of default wait timeout
|
||||
|
||||
// Check whether the status is INACTIVE otherwise get messge from OTF and throw an exception
|
||||
if(status.getValue() != Status.INACTIVE.ordinal()){
|
||||
throw new RuntimeException("OTFSCAN failed with message: "+message.getValue());
|
||||
}
|
||||
|
||||
} catch (ExecutionException | ChannelException | TimeoutException e) {
|
||||
throw new RuntimeException("An error occurred while waiting for the OTF logic to finish.", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait until scan has stopped
|
||||
* @param waitTimeout
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public void waitUntilStopped(Long waitTimeout) throws InterruptedException {
|
||||
try {
|
||||
scanRunning.waitForValue(false, waitTimeout);
|
||||
|
||||
// Check whether the status is INACTIVE otherwise get messge from OTF and throw an exception
|
||||
if(status.getValue() != Status.INACTIVE.ordinal()){
|
||||
throw new RuntimeException("OTFSCAN failed with message: "+message.getValue());
|
||||
}
|
||||
|
||||
} catch (ExecutionException | ChannelException | TimeoutException e) {
|
||||
throw new RuntimeException("An error occurred while waiting for the OTF logic to finish.", e);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset OTFScan records to defaults
|
||||
* @throws CAException
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public void resetToDefaults() throws InterruptedException{
|
||||
try{
|
||||
setMonitoredChannels(new String[]{});
|
||||
setMotor("");
|
||||
begin.setValue(0d);
|
||||
end.setValue(0d);
|
||||
stepSize.setValue(0d);
|
||||
integrationTime.setValue(0d);
|
||||
zigZag.setValue(false);
|
||||
setAppendFile(false);
|
||||
setFileNameGeneration(true);
|
||||
setFileName("");
|
||||
setFileNameFormat("%06d.txt");
|
||||
resetFileCounter();
|
||||
|
||||
setUserBacklash(0d);
|
||||
|
||||
// setNfsServer("");
|
||||
// setNfsShare("");
|
||||
|
||||
waitUntilMotorNotOk(timeoutMotorOk);
|
||||
}
|
||||
catch(ExecutionException | ChannelException e){
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get motor of the OTFScan axis
|
||||
* @return Name of the OTF motor
|
||||
* @throws CAException
|
||||
*/
|
||||
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 CAException
|
||||
*/
|
||||
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 CAException
|
||||
*/
|
||||
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 CAException
|
||||
*/
|
||||
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 CAException
|
||||
*/
|
||||
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 Exception
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get minimum value of the begin position
|
||||
* @return Min value for begin
|
||||
* @throws CAException
|
||||
*/
|
||||
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 CAException
|
||||
*/
|
||||
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 CAException
|
||||
*/
|
||||
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 CAException
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get minimum value of end position
|
||||
* @return Min value for end
|
||||
* @throws CAException
|
||||
*/
|
||||
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 CAException
|
||||
*/
|
||||
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 CAException
|
||||
*/
|
||||
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 CAException
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get minimum integration time
|
||||
* @return Min value for step size
|
||||
* @throws CAException
|
||||
*/
|
||||
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 CAException
|
||||
*/
|
||||
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 CAException
|
||||
*/
|
||||
public void setIntegrationTime(Double integrationTime) throws InterruptedException {
|
||||
try{
|
||||
if(integrationTime==null){
|
||||
throw new IllegalArgumentException("Integration time must not be null");
|
||||
}
|
||||
|
||||
// Check range (if limit is set to 0 then limit is not set)
|
||||
double min = integrationTimeMin.getValue();
|
||||
double max = integrationTimeMax.getValue();
|
||||
if(min!= 0 && max!= 0){
|
||||
if(integrationTime < min || integrationTime > max){
|
||||
throw new IllegalArgumentException("Integration time ["+integrationTime+"] is outside range [min: "+min+" max: "+max+"]");
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(min!= 0 && integrationTime<min){
|
||||
throw new IllegalArgumentException("Integration time ["+integrationTime+"] is outside range [min: "+min+" max: - ]");
|
||||
}
|
||||
else if(max!= 0 && integrationTime>max){
|
||||
throw new IllegalArgumentException("Integration time ["+integrationTime+"] is outside range [min: - max: "+max+"]");
|
||||
}
|
||||
}
|
||||
|
||||
this.integrationTime.setValue(integrationTime);
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get minimum integration time
|
||||
* @return Min value for integration time
|
||||
* @throws CAException
|
||||
*/
|
||||
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 CAException
|
||||
*/
|
||||
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 CAException
|
||||
*/
|
||||
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 CAException
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current NFS server the data is written to
|
||||
* @return Name of NFS server
|
||||
* @throws CAException
|
||||
*/
|
||||
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 CAException
|
||||
*/
|
||||
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 CAException
|
||||
*/
|
||||
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 CAException
|
||||
*/
|
||||
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 CAException
|
||||
*/
|
||||
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 CAException
|
||||
*/
|
||||
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 CAException
|
||||
*/
|
||||
public String getFileNameFormat() throws InterruptedException {
|
||||
try{
|
||||
return(this.fileNameFormat.getValue());
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set file name formate of the data file
|
||||
* @param fileNameFormat
|
||||
* @throws Exception
|
||||
*/
|
||||
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 CAException
|
||||
*/
|
||||
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 CAException
|
||||
*/
|
||||
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 CAException
|
||||
*/
|
||||
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 CAException
|
||||
*/
|
||||
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 CAException
|
||||
*/
|
||||
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 CAException
|
||||
*/
|
||||
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 CAException
|
||||
*/
|
||||
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 CAException
|
||||
*/
|
||||
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 InterruptedException {
|
||||
try{
|
||||
return(this.useEncoder.getValue());
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set flag to use encoder
|
||||
* @throws CAException
|
||||
*/
|
||||
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 CAException
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the channels that need to be monitored.
|
||||
* 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 CAException
|
||||
*/
|
||||
public void setMonitoredChannels(String[] values) throws InterruptedException {
|
||||
|
||||
try{
|
||||
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]);
|
||||
}
|
||||
else{
|
||||
this.monitoredChannels.get(i).setValue("");
|
||||
}
|
||||
}
|
||||
} catch (ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether an scan is running
|
||||
* @return Running flag
|
||||
* @throws CAException
|
||||
*/
|
||||
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 CAException
|
||||
*/
|
||||
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 CAException
|
||||
*/
|
||||
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 CAException
|
||||
*/
|
||||
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 CAException If motor ok flag does not switch to ok within the specified timeout
|
||||
*/
|
||||
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 CAException If motor ok flag does not switch to ok within the specified timeout
|
||||
*/
|
||||
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 InterruptedException {
|
||||
try{
|
||||
if(!useEncoder.getValue()){
|
||||
return;
|
||||
}
|
||||
encoderOk.waitForValue(true, timeout);
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,283 +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.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptEngineManager;
|
||||
import javax.script.ScriptException;
|
||||
|
||||
import ch.psi.fda.core.Manipulation;
|
||||
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.messages.DataMessage;
|
||||
import ch.psi.fda.messages.Metadata;
|
||||
|
||||
public class JythonManipulation implements Manipulation{
|
||||
|
||||
private static Logger logger = Logger.getLogger(JythonManipulation.class.getName());
|
||||
|
||||
/**
|
||||
* Pattern of the entry function of the jython script
|
||||
*/
|
||||
private static final String entryFunction = "process";
|
||||
private static final String entryFunctionPattern = "def "+entryFunction+"\\((.*)\\):";
|
||||
|
||||
/**
|
||||
* Code of the manipulation. The script need to implement a function of the type:
|
||||
* <code>
|
||||
* def process():
|
||||
* # ... your code
|
||||
* return value
|
||||
* </code>
|
||||
*
|
||||
* The number of parameters of the script are not limited. So <code>process(a)</code> is valid
|
||||
* as well as <code>process(a,b,c,d,e,f)</code>.
|
||||
* However for each parameter there need to be a mapping inside the mapping list! If there is no
|
||||
* mapping inside the Manipulator evaluating this Manipulation will throw an Exception.
|
||||
*/
|
||||
private final String script;
|
||||
|
||||
/**
|
||||
* Id of the resulting component
|
||||
*/
|
||||
private final String id;
|
||||
|
||||
/**
|
||||
* Mapping of components to manipulation code variables
|
||||
*/
|
||||
private final List<JythonParameterMapping> mapping;
|
||||
|
||||
private final boolean returnArray;
|
||||
|
||||
/**
|
||||
* Script engine of the manipulator
|
||||
*/
|
||||
private ScriptEngine engine;
|
||||
/**
|
||||
* 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 List<String> parameterIds = new ArrayList<>();
|
||||
/**
|
||||
* Parameter array of the entry function
|
||||
*/
|
||||
private String[] parameter;
|
||||
|
||||
/**
|
||||
* Jython entry call
|
||||
*/
|
||||
private String jythonCall;
|
||||
|
||||
|
||||
private Map<String,Object> gvariables = new HashMap<String,Object>();
|
||||
|
||||
|
||||
public JythonManipulation(String id, String script, List<JythonParameterMapping> mapping){
|
||||
this(id, script, mapping, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param id
|
||||
* @param script
|
||||
* @param mapping
|
||||
*/
|
||||
public JythonManipulation(String id, String script, List<JythonParameterMapping> mapping, boolean returnArray){
|
||||
this.id = id;
|
||||
this.script = script;
|
||||
this.mapping = mapping;
|
||||
this.returnArray = returnArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the script
|
||||
*/
|
||||
public String getScript() {
|
||||
return script;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the mapping
|
||||
*/
|
||||
public List<JythonParameterMapping> getMapping() {
|
||||
return mapping;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void initialize(List<Metadata> metadata){
|
||||
|
||||
// Workaround for Jython memory leak
|
||||
// http://blog.hillbrecht.de/2009/07/11/jython-memory-leakout-of-memory-problem/
|
||||
System.setProperty("python.options.internalTablesImpl","weak");
|
||||
|
||||
// Create new script engine
|
||||
this.engine = new ScriptEngineManager().getEngineByName("python");
|
||||
|
||||
// Determine script entry function and the function parameters
|
||||
Pattern pattern = Pattern.compile(entryFunctionPattern);
|
||||
Matcher matcher = pattern.matcher(this.script);
|
||||
if(matcher.find() && matcher.groupCount()==1){
|
||||
if(!matcher.group(1).trim().equals("")){
|
||||
logger.finest("Entry function '"+entryFunctionPattern+"' found - Identified parameters: "+matcher.group(1));
|
||||
parameter = matcher.group(1).split(" *, *");
|
||||
}
|
||||
else{
|
||||
parameter = new String[0];
|
||||
}
|
||||
}
|
||||
else{
|
||||
throw new IllegalArgumentException("Cannot determine entry function: "+entryFunctionPattern);
|
||||
}
|
||||
|
||||
// Load manipulation script
|
||||
try {
|
||||
engine.eval(this.script);
|
||||
} catch (ScriptException e) {
|
||||
throw new RuntimeException("Unable to load manipulation script", e);
|
||||
}
|
||||
|
||||
// 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];
|
||||
parameterIds = new ArrayList<>();
|
||||
for(int i=0;i<parameter.length; i++){
|
||||
String p = parameter[i];
|
||||
p = p.trim();
|
||||
boolean found = false;
|
||||
|
||||
for(JythonParameterMapping jpm: this.mapping){
|
||||
if(jpm.getVariable().equals(p)){
|
||||
if(jpm instanceof JythonParameterMappingID){
|
||||
JythonParameterMappingID pm = (JythonParameterMappingID)jpm;
|
||||
// Mapping for parameter found, determine index of the corresponding component
|
||||
// parameterIndex[i] = metadata.getIndex(pm.getRefid());
|
||||
parameterIds.add(pm.getRefid());
|
||||
}
|
||||
else if (jpm instanceof JythonParameterMappingChannel){
|
||||
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;
|
||||
parameterIds.add(null);
|
||||
// parameterIndex[i] = null;
|
||||
|
||||
engine.put(pm.getVariable(), pm.getGlobalVariable());
|
||||
}
|
||||
found=true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// If there is no mapping nothing can be found
|
||||
// If there are mappings everything need to be found
|
||||
if(!found){
|
||||
throw new IllegalArgumentException("No mapping compontent found for parameter "+p);
|
||||
}
|
||||
}
|
||||
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
buffer.append(entryFunction);
|
||||
buffer.append("(");
|
||||
|
||||
for(String p: parameter){
|
||||
buffer.append(p);
|
||||
buffer.append(",");
|
||||
}
|
||||
|
||||
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<parameterIds.size();i++){
|
||||
if(parameterIds.get(i) != null){
|
||||
engine.put(parameter[i], message.getData(parameterIds.get(i)));
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
if(returnArray){
|
||||
return((double[]) engine.eval(jythonCall));
|
||||
}
|
||||
else{
|
||||
// Due to the typeless nature of Python an Integer of Float/Double might be returned from the
|
||||
// Python code (e.g. depending on the factors in a calculation)
|
||||
// Always return the return value to a double. If this cannot be done return NaN
|
||||
Object r = engine.eval(jythonCall);
|
||||
if(r instanceof Double){
|
||||
return((Double) r);
|
||||
}
|
||||
else if( r instanceof Integer){
|
||||
return(((Integer)r).doubleValue());
|
||||
}
|
||||
else{
|
||||
// return Double.NaN;
|
||||
return r;
|
||||
}
|
||||
}
|
||||
} catch (ScriptException e) {
|
||||
// throw new RuntimeException("Data manipulaton [id: "+id+"] failed while executing the manipulation script",e);
|
||||
logger.log(Level.WARNING, "Data manipulaton [id: "+id+"] failed while executing the manipulation script");
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -1,55 +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;
|
||||
|
||||
/**
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
public class JythonGlobalVariable {
|
||||
private String name;
|
||||
private double value;
|
||||
|
||||
/**
|
||||
* @return the name
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
/**
|
||||
* @param name the name to set
|
||||
*/
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
/**
|
||||
* @return the value
|
||||
*/
|
||||
public double getValue() {
|
||||
return value;
|
||||
}
|
||||
/**
|
||||
* @param value the value to set
|
||||
*/
|
||||
public void setValue(double value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,55 +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;
|
||||
|
||||
/**
|
||||
* Mapping of a parameter to something
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
public abstract class JythonParameterMapping {
|
||||
|
||||
/**
|
||||
* Variable name inside the script
|
||||
*/
|
||||
private String variable;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param variable
|
||||
*/
|
||||
public JythonParameterMapping(String variable){
|
||||
this.variable = variable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the variable
|
||||
*/
|
||||
public String getVariable() {
|
||||
return variable;
|
||||
}
|
||||
/**
|
||||
* @param variable the variable to set
|
||||
*/
|
||||
public void setVariable(String variable) {
|
||||
this.variable = variable;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,42 +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 ch.psi.jcae.Channel;
|
||||
|
||||
|
||||
/**
|
||||
* Mapping of a script parameter to a channel bean.
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
public class JythonParameterMappingChannel<T> extends JythonParameterMapping {
|
||||
|
||||
private Channel<T> channel;
|
||||
|
||||
public JythonParameterMappingChannel(String variable, Channel<T> channel){
|
||||
super(variable);
|
||||
this.channel = channel;
|
||||
}
|
||||
|
||||
public Channel<T> getChannel() {
|
||||
return channel;
|
||||
}
|
||||
}
|
||||
@@ -1,56 +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;
|
||||
|
||||
|
||||
/**
|
||||
* Mapping of a script parameter to a component via the Id.
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
public class JythonParameterMappingGlobalVariable extends JythonParameterMapping {
|
||||
|
||||
private JythonGlobalVariable globalVariable;
|
||||
|
||||
/**
|
||||
* Constuctor
|
||||
* @param variable
|
||||
* @param globalVariable
|
||||
*/
|
||||
public JythonParameterMappingGlobalVariable(String variable, JythonGlobalVariable globalVariable){
|
||||
super(variable);
|
||||
this.globalVariable = globalVariable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the globalVariable
|
||||
*/
|
||||
public JythonGlobalVariable getGlobalVariable() {
|
||||
return globalVariable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param globalVariable the globalVariable to set
|
||||
*/
|
||||
public void setGlobalVariable(JythonGlobalVariable globalVariable) {
|
||||
this.globalVariable = globalVariable;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,58 +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;
|
||||
|
||||
|
||||
/**
|
||||
* Mapping of a script parameter to a component via the Id.
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
public class JythonParameterMappingID extends JythonParameterMapping {
|
||||
|
||||
/**
|
||||
* Id of the component to map to this variable
|
||||
*/
|
||||
private String refid;
|
||||
|
||||
/**
|
||||
* Constructor accepting varible/id pair
|
||||
* @param variable
|
||||
* @param refid
|
||||
*/
|
||||
public JythonParameterMappingID(String variable, String refid){
|
||||
super(variable);
|
||||
this.refid = refid;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the refid
|
||||
*/
|
||||
public String getRefid() {
|
||||
return refid;
|
||||
}
|
||||
/**
|
||||
* @param refid the refid to set
|
||||
*/
|
||||
public void setRefid(String refid) {
|
||||
this.refid = refid;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,72 +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.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;
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
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.
|
||||
*/
|
||||
public class ComplexSensor implements Sensor {
|
||||
|
||||
private static Logger logger = Logger.getLogger(ComplexSensor.class.getName());
|
||||
|
||||
private String id;
|
||||
private final Sensor sensor;
|
||||
private final List<Action> preActions;
|
||||
private final List<Action> postActions;
|
||||
|
||||
public ComplexSensor(String id, Sensor sensor){
|
||||
this.id = id;
|
||||
this.sensor = sensor;
|
||||
this.preActions = new ArrayList<Action>();
|
||||
this.postActions = new ArrayList<Action>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object read() throws InterruptedException {
|
||||
logger.finest("Execute pre actions");
|
||||
for(Action action: preActions){
|
||||
action.execute();
|
||||
}
|
||||
|
||||
Object value = sensor.read();
|
||||
|
||||
logger.finest("Execute post actions");
|
||||
for(Action action: postActions){
|
||||
action.execute();
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public List<Action> getPreActions() {
|
||||
return preActions;
|
||||
}
|
||||
public List<Action> getPostActions() {
|
||||
return postActions;
|
||||
}
|
||||
}
|
||||
@@ -1,46 +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 the current time in milliseconds
|
||||
*/
|
||||
public class TimestampSensor implements Sensor {
|
||||
|
||||
private final String id; // Global id of the sensor
|
||||
|
||||
public TimestampSensor(String id){
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object read() {
|
||||
// Return current time in milliseconds
|
||||
return new Double(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -35,10 +35,6 @@ import java.util.logging.Logger;
|
||||
|
||||
import ch.psi.fda.aq.AcquisitionConfiguration;
|
||||
|
||||
/**
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
public class ApplicationConfigurator {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(ApplicationConfigurator.class.getName());
|
||||
|
||||
@@ -1,100 +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.model;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import javax.xml.bind.JAXBContext;
|
||||
import javax.xml.bind.JAXBElement;
|
||||
import javax.xml.bind.JAXBException;
|
||||
import javax.xml.bind.Marshaller;
|
||||
import javax.xml.bind.UnmarshalException;
|
||||
import javax.xml.bind.Unmarshaller;
|
||||
import javax.xml.namespace.QName;
|
||||
import javax.xml.transform.Source;
|
||||
import javax.xml.transform.stream.StreamSource;
|
||||
import javax.xml.validation.Schema;
|
||||
import javax.xml.validation.SchemaFactory;
|
||||
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.SAXParseException;
|
||||
|
||||
import ch.psi.fda.model.v1.Configuration;
|
||||
|
||||
/**
|
||||
* Manage the serialization and deserialization of the FDA data model
|
||||
*/
|
||||
public class ModelManager {
|
||||
|
||||
/**
|
||||
* De-serialize an instance of the FDA data model
|
||||
*
|
||||
* @param file File to deserialize
|
||||
* @throws JAXBException Something went wrong while unmarshalling
|
||||
* @throws SAXException Cannot read model schema file
|
||||
*/
|
||||
public static Configuration unmarshall(File file) throws JAXBException, SAXException {
|
||||
|
||||
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(new StreamSource(file), 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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @throws SAXException Cannot read model schema files
|
||||
*/
|
||||
public static void marshall(Configuration model, File file) throws JAXBException, SAXException{
|
||||
QName qname = new QName("http://www.psi.ch/~ebner/models/scan/1.0", "configuration");
|
||||
|
||||
JAXBContext context = JAXBContext.newInstance(Configuration.class);
|
||||
Marshaller m = context.createMarshaller();
|
||||
m.setProperty("jaxb.formatted.output", true);
|
||||
|
||||
// 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
|
||||
m.setSchema(schema);
|
||||
|
||||
m.marshal( new JAXBElement<Configuration>(qname, Configuration.class, model ), file);
|
||||
}
|
||||
}
|
||||
@@ -1,43 +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.rest;
|
||||
|
||||
import ch.psi.fda.model.v1.Configuration;
|
||||
|
||||
/**
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
public class ExecutionRequest {
|
||||
|
||||
private final String trackingId;
|
||||
private final Configuration configuration;
|
||||
|
||||
public ExecutionRequest(String trackingId, Configuration configuration){
|
||||
this.trackingId = trackingId;
|
||||
this.configuration = configuration;
|
||||
}
|
||||
|
||||
public String getTrackingId() {
|
||||
return trackingId;
|
||||
}
|
||||
public Configuration getConfiguration() {
|
||||
return configuration;
|
||||
}
|
||||
}
|
||||
@@ -21,14 +21,12 @@ package ch.psi.fda.rest;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.jeromq.ZMQ;
|
||||
|
||||
import ch.psi.fda.messages.Message;
|
||||
import ch.psi.fda.model.v1.Visualization;
|
||||
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
|
||||
@@ -82,20 +80,21 @@ public class ZMQDataService {
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onMessage(List<Visualization> vis){
|
||||
logger.fine("Sending plotting filters");
|
||||
socket.sendMore("{\"htype\": [\"fda-plot-2.1\"], \"trackingId\":\"" + trackingId + "\"}");
|
||||
try (
|
||||
ByteArrayOutputStream b = new ByteArrayOutputStream();
|
||||
ObjectOutputStream o = new ObjectOutputStream(b);
|
||||
) {
|
||||
o.writeObject(vis);
|
||||
socket.send(b.toByteArray());
|
||||
} catch (IOException e) {
|
||||
logger.log(Level.WARNING, "Unable to serialize message", e);
|
||||
}
|
||||
}
|
||||
// TODO Need to revive this
|
||||
// @Subscribe
|
||||
// public void onMessage(List<Visualization> vis){
|
||||
// logger.fine("Sending plotting filters");
|
||||
// socket.sendMore("{\"htype\": [\"fda-plot-2.1\"], \"trackingId\":\"" + trackingId + "\"}");
|
||||
// try (
|
||||
// ByteArrayOutputStream b = new ByteArrayOutputStream();
|
||||
// ObjectOutputStream o = new ObjectOutputStream(b);
|
||||
// ) {
|
||||
// o.writeObject(vis);
|
||||
// socket.send(b.toByteArray());
|
||||
// } catch (IOException e) {
|
||||
// logger.log(Level.WARNING, "Unable to serialize message", e);
|
||||
// }
|
||||
// }
|
||||
|
||||
public void setTrackingId(String id){
|
||||
trackingId = id;
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package ch.psi.fda.rest.services;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@@ -8,7 +11,7 @@ import javax.ws.rs.ext.Provider;
|
||||
import javax.xml.bind.JAXBContext;
|
||||
import javax.xml.bind.JAXBException;
|
||||
|
||||
import ch.psi.fda.aq.XScanDescriptor;
|
||||
import ch.psi.fda.DescriptorProvider;
|
||||
import ch.psi.fda.edescriptor.EDescriptor;
|
||||
|
||||
/**
|
||||
@@ -19,15 +22,26 @@ import ch.psi.fda.edescriptor.EDescriptor;
|
||||
public class EDescriptorJAXBContextProvider implements ContextResolver<JAXBContext> {
|
||||
private static final Logger logger = Logger.getLogger(EDescriptorJAXBContextProvider.class.getName());
|
||||
|
||||
List<Class<?>> classes = new ArrayList<>();
|
||||
|
||||
public EDescriptorJAXBContextProvider(){
|
||||
classes.add(EDescriptor.class);
|
||||
ServiceLoader<DescriptorProvider> providers = ServiceLoader.load(DescriptorProvider.class);
|
||||
for (DescriptorProvider provider : providers) {
|
||||
classes.add(provider.getEDescriptorClass());
|
||||
}
|
||||
}
|
||||
|
||||
private JAXBContext context = null;
|
||||
|
||||
public JAXBContext getContext(Class<?> type) {
|
||||
if(type != EDescriptor.class)
|
||||
if(type != EDescriptor.class){
|
||||
return null; // No support for other classes than EDescriptor
|
||||
}
|
||||
|
||||
if(context == null) {
|
||||
try {
|
||||
context = JAXBContext.newInstance(EDescriptor.class, XScanDescriptor.class);
|
||||
context = JAXBContext.newInstance(classes.toArray(new Class[]{}));
|
||||
} catch (JAXBException e) {
|
||||
|
||||
logger.log(Level.WARNING, "Unable to create JAXB Context", e);
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
ch.psi.fda.aq.XScanDescriptorProvider
|
||||
@@ -1 +0,0 @@
|
||||
ch.psi.fda.aq.XScanFactory
|
||||
@@ -1,529 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsd:schema targetNamespace="http://www.psi.ch/~ebner/models/scan/1.0" version="1.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.psi.ch/~ebner/models/scan/1.0" elementFormDefault="qualified">
|
||||
|
||||
<xsd:complexType name="Visualization" abstract="true">
|
||||
<xsd:attribute name="title" type="xsd:string" use="optional" default=" "></xsd:attribute>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="LinePlot">
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="Visualization">
|
||||
<xsd:attribute name="x" type="xsd:IDREF" use="required"></xsd:attribute>
|
||||
<xsd:attribute name="y" type="xsd:IDREFS" use="required"></xsd:attribute>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="MatrixPlot">
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="Visualization">
|
||||
<xsd:attribute name="x" type="xsd:IDREF" use="required"></xsd:attribute>
|
||||
<xsd:attribute name="y" type="xsd:IDREF" use="required"></xsd:attribute>
|
||||
<xsd:attribute name="z" type="xsd:IDREF" use="required"></xsd:attribute>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="Action" abstract="true"></xsd:complexType>
|
||||
|
||||
<xsd:complexType name="ChannelAction">
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="Action">
|
||||
<xsd:attribute name="channel" type="xsd:string"
|
||||
use="required">
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="value" type="xsd:string"
|
||||
use="required">
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="operation" default="put"
|
||||
use="optional">
|
||||
<xsd:simpleType>
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="put"></xsd:enumeration>
|
||||
<xsd:enumeration value="putq"></xsd:enumeration>
|
||||
<xsd:enumeration value="wait"></xsd:enumeration>
|
||||
<xsd:enumeration value="waitOR"></xsd:enumeration>
|
||||
<xsd:enumeration value="waitAND"></xsd:enumeration>
|
||||
<xsd:enumeration value="waitREGEX"></xsd:enumeration>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="type" default="String"
|
||||
use="optional">
|
||||
<xsd:simpleType>
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="String"></xsd:enumeration>
|
||||
<xsd:enumeration value="Integer"></xsd:enumeration>
|
||||
<xsd:enumeration value="Double"></xsd:enumeration>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="timeout" type="xsd:double" use="optional"></xsd:attribute>
|
||||
<xsd:attribute name="delay" type="xsd:double"
|
||||
use="optional">
|
||||
</xsd:attribute>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
|
||||
|
||||
<xsd:complexType name="Positioner" abstract="true">
|
||||
<xsd:attribute name="id" type="xsd:ID" use="required"></xsd:attribute>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="ContinuousPositioner">
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="Positioner">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="start" type="xsd:double"
|
||||
maxOccurs="1" minOccurs="1">
|
||||
</xsd:element>
|
||||
<xsd:element name="end" type="xsd:double"
|
||||
maxOccurs="1" minOccurs="1">
|
||||
</xsd:element>
|
||||
<xsd:element name="stepSize" type="xsd:double"
|
||||
maxOccurs="1" minOccurs="1">
|
||||
</xsd:element>
|
||||
<xsd:element name="integrationTime"
|
||||
type="xsd:double" maxOccurs="1" minOccurs="1">
|
||||
</xsd:element>
|
||||
<xsd:element name="additionalBacklash"
|
||||
type="xsd:double" maxOccurs="1" minOccurs="0">
|
||||
</xsd:element>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string"
|
||||
use="required">
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="readback" type="xsd:string" use="optional"></xsd:attribute>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="DiscreteStepPositioner" abstract="true">
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="Positioner">
|
||||
<xsd:attribute name="name" type="xsd:string" use="optional"></xsd:attribute>
|
||||
<xsd:attribute name="readback" type="xsd:string" use="optional"></xsd:attribute>
|
||||
<xsd:attribute name="settlingTime" default="0" use="optional">
|
||||
<xsd:simpleType>
|
||||
<xsd:restriction base="xsd:double">
|
||||
<xsd:minInclusive value="0"></xsd:minInclusive>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="done" type="xsd:string" use="optional"></xsd:attribute>
|
||||
<xsd:attribute name="doneValue" type="xsd:string" use="optional" default="1"></xsd:attribute>
|
||||
<xsd:attribute name="type" default="Integer" use="optional">
|
||||
<xsd:simpleType>
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="String"></xsd:enumeration>
|
||||
<xsd:enumeration value="Integer"></xsd:enumeration>
|
||||
<xsd:enumeration value="Double"></xsd:enumeration>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="doneDelay" default="0">
|
||||
<xsd:simpleType>
|
||||
<xsd:restriction base="xsd:double">
|
||||
<xsd:minInclusive value="0"></xsd:minInclusive>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="asynchronous" type="xsd:boolean" default="false"></xsd:attribute>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="LinearPositioner">
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="DiscreteStepPositioner">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="start" type="xsd:double"></xsd:element>
|
||||
<xsd:element name="end" type="xsd:double"></xsd:element>
|
||||
<xsd:element name="stepSize" type="xsd:double"></xsd:element>
|
||||
</xsd:sequence>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="ArrayPositioner">
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="DiscreteStepPositioner">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="positions" type="xsd:string"></xsd:element>
|
||||
</xsd:sequence>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="RegionPositioner">
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="DiscreteStepPositioner">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="region" type="Region" maxOccurs="unbounded" minOccurs="1"></xsd:element>
|
||||
</xsd:sequence>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="Region">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="preAction" type="Action" maxOccurs="unbounded" minOccurs="0"></xsd:element>
|
||||
<xsd:element name="start" type="xsd:double" maxOccurs="1" minOccurs="1"></xsd:element>
|
||||
<xsd:element name="end" type="xsd:double" maxOccurs="1" minOccurs="1"></xsd:element>
|
||||
<xsd:element name="stepSize" type="xsd:double" maxOccurs="1" minOccurs="1"></xsd:element>
|
||||
<xsd:element name="function" type="Function" minOccurs="0" maxOccurs="1"></xsd:element>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
|
||||
|
||||
<xsd:complexType name="Data">
|
||||
<xsd:attribute name="format" use="optional" default="txt">
|
||||
<xsd:simpleType>
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="txt"></xsd:enumeration>
|
||||
<xsd:enumeration value="mat"></xsd:enumeration>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="fileName" type="xsd:string" use="optional"></xsd:attribute>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="Dimension" abstract="true">
|
||||
<xsd:attribute name="zigzag" type="xsd:boolean" use="optional" default="false"></xsd:attribute>
|
||||
<xsd:attribute name="dataGroup" type="xsd:boolean" use="optional" default="false"></xsd:attribute>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="ShellAction">
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="Action">
|
||||
<xsd:attribute name="command" type="xsd:string"
|
||||
use="required">
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="exitValue" type="xsd:int" default="0"></xsd:attribute>
|
||||
<xsd:attribute name="checkExitValue"
|
||||
type="xsd:boolean" default="true">
|
||||
</xsd:attribute>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="Detector" abstract="true">
|
||||
<xsd:attribute name="id" type="xsd:ID" use="required"></xsd:attribute>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="SimpleDetector" abstract="true">
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="Detector"></xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="ComplexDetector">
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="Detector">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="preAction" type="Action" maxOccurs="unbounded" minOccurs="0"></xsd:element>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required"></xsd:attribute>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="ArrayDetector">
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="ComplexDetector">
|
||||
<xsd:attribute name="arraySize" type="xsd:int" use="required"></xsd:attribute>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="ScalarDetector">
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="ComplexDetector">
|
||||
<xsd:attribute name="type" use="optional" default="Double">
|
||||
<xsd:simpleType>
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="Double"></xsd:enumeration>
|
||||
<xsd:enumeration value="String"></xsd:enumeration>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
</xsd:attribute>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="Timestamp">
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="SimpleDetector"></xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="SimpleScalarDetector">
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="SimpleDetector">
|
||||
<xsd:attribute name="name" type="xsd:string" use="required"></xsd:attribute>
|
||||
<xsd:attribute name="scr" type="xsd:boolean" default="false" use="optional"></xsd:attribute>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="ScalerChannel">
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="SimpleDetector">
|
||||
<xsd:attribute name="channel" use="required">
|
||||
<xsd:simpleType>
|
||||
<xsd:restriction base="xsd:int">
|
||||
<xsd:maxInclusive value="15"></xsd:maxInclusive>
|
||||
<xsd:minInclusive value="0"></xsd:minInclusive>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
</xsd:attribute>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="DiscreteStepDimension">
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="Dimension">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="preAction" type="Action" minOccurs="0" maxOccurs="unbounded"></xsd:element>
|
||||
<xsd:element name="positioner" type="DiscreteStepPositioner" maxOccurs="unbounded" minOccurs="0"></xsd:element>
|
||||
<xsd:element name="action" type="Action" minOccurs="0" maxOccurs="unbounded"></xsd:element>
|
||||
<xsd:element name="guard" type="Guard" maxOccurs="1" minOccurs="0"></xsd:element>
|
||||
<xsd:element name="detector" type="Detector" maxOccurs="unbounded" minOccurs="0"></xsd:element>
|
||||
<xsd:element name="postAction" type="Action" minOccurs="0" maxOccurs="unbounded"></xsd:element>
|
||||
</xsd:sequence>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="ContinuousDimension">
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="Dimension">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="preAction" type="Action" minOccurs="0" maxOccurs="unbounded"></xsd:element>
|
||||
<xsd:element name="positioner" type="ContinuousPositioner" maxOccurs="1" minOccurs="1"></xsd:element>
|
||||
<xsd:element name="detector" type="SimpleScalarDetector" maxOccurs="unbounded" minOccurs="0"></xsd:element>
|
||||
<xsd:element name="scaler" type="ScalerChannel" maxOccurs="unbounded" minOccurs="0"></xsd:element>
|
||||
<xsd:element name="timestamp" type="Timestamp" maxOccurs="1" minOccurs="0"></xsd:element>
|
||||
<xsd:element name="postAction" type="Action" minOccurs="0" maxOccurs="unbounded"></xsd:element>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="rasterize" type="xsd:boolean" use="optional" default="false"></xsd:attribute>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="Scan">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="preAction" type="Action"
|
||||
maxOccurs="unbounded" minOccurs="0">
|
||||
</xsd:element>
|
||||
<xsd:element name="cdimension" type="ContinuousDimension"
|
||||
maxOccurs="1" minOccurs="0">
|
||||
</xsd:element>
|
||||
<xsd:element name="dimension" type="DiscreteStepDimension"
|
||||
maxOccurs="unbounded" minOccurs="0">
|
||||
</xsd:element>
|
||||
<xsd:element name="postAction" type="Action"
|
||||
maxOccurs="unbounded" minOccurs="0">
|
||||
</xsd:element>
|
||||
<xsd:element name="manipulation" type="Manipulation" maxOccurs="unbounded" minOccurs="0"></xsd:element>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="id" type="xsd:string" use="optional"></xsd:attribute>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="Configuration">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="notification" type="Notification" minOccurs="0" maxOccurs="1"></xsd:element>
|
||||
<xsd:element name="data" type="Data" maxOccurs="1" minOccurs="0"></xsd:element>
|
||||
<xsd:element name="description" type="xsd:string" maxOccurs="1" minOccurs="0"></xsd:element>
|
||||
<xsd:element name="variable" type="Variable" maxOccurs="unbounded" minOccurs="0"></xsd:element>
|
||||
<xsd:element name="scan" type="Scan" maxOccurs="1" minOccurs="1"></xsd:element>
|
||||
<xsd:element name="visualization" type="Visualization" maxOccurs="unbounded" minOccurs="0"></xsd:element>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="numberOfExecution" type="xsd:int" use="optional" default="1"></xsd:attribute>
|
||||
<xsd:attribute name="failOnSensorError" type="xsd:boolean" default="true" use="optional"></xsd:attribute>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:element name="configuration" type="Configuration"></xsd:element>
|
||||
|
||||
<xsd:complexType name="DetectorOfDetectors">
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="ComplexDetector">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="detector" type="ScalarDetector" maxOccurs="unbounded" minOccurs="0"></xsd:element>
|
||||
</xsd:sequence>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="ParameterMapping">
|
||||
<xsd:attribute name="variable" type="xsd:string"
|
||||
use="required">
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="Manipulation" abstract="true">
|
||||
<xsd:attribute name="id" type="xsd:ID" use="required"></xsd:attribute>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="ScriptManipulation">
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="Manipulation">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="mapping" type="ParameterMapping" maxOccurs="unbounded" minOccurs="0"></xsd:element>
|
||||
<xsd:element name="script" type="xsd:string" maxOccurs="1" minOccurs="1"></xsd:element>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="returnArray" type="xsd:boolean" default="false"></xsd:attribute>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="PseudoPositioner">
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="DiscreteStepPositioner">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="counts" type="xsd:int" maxOccurs="1" minOccurs="1"></xsd:element>
|
||||
</xsd:sequence>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="IDParameterMapping">
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="ParameterMapping">
|
||||
<xsd:attribute name="refid" type="xsd:IDREF"></xsd:attribute>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="ChannelParameterMapping">
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="ParameterMapping">
|
||||
<xsd:attribute name="channel" type="xsd:string"></xsd:attribute>
|
||||
<xsd:attribute name="type" default="Double" use="optional">
|
||||
<xsd:simpleType>
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="Double"></xsd:enumeration>
|
||||
<xsd:enumeration value="Integer"></xsd:enumeration>
|
||||
<xsd:enumeration value="String"></xsd:enumeration>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
</xsd:attribute>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
|
||||
|
||||
|
||||
<xsd:complexType name="ScriptAction">
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="Action">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="mapping" type="ChannelParameterMapping" maxOccurs="unbounded" minOccurs="0"></xsd:element>
|
||||
<xsd:element name="script" type="xsd:string"
|
||||
maxOccurs="1" minOccurs="1">
|
||||
</xsd:element>
|
||||
</xsd:sequence>
|
||||
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="GuardCondition">
|
||||
<xsd:attribute name="channel" type="xsd:string"
|
||||
use="required">
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="value" type="xsd:string" use="required"></xsd:attribute>
|
||||
<xsd:attribute name="type" default="Integer">
|
||||
<xsd:simpleType>
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="Double"></xsd:enumeration>
|
||||
<xsd:enumeration value="Integer"></xsd:enumeration>
|
||||
<xsd:enumeration value="String"></xsd:enumeration>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="Guard">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="condition" type="GuardCondition" maxOccurs="unbounded" minOccurs="1"></xsd:element>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
|
||||
|
||||
|
||||
<xsd:complexType name="Notification">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="recipient" type="Recipient" minOccurs="0" maxOccurs="unbounded"></xsd:element>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="Recipient">
|
||||
<xsd:simpleContent>
|
||||
<xsd:extension base="xsd:string">
|
||||
<xsd:attribute name="error" type="xsd:boolean" default="true"></xsd:attribute>
|
||||
<xsd:attribute name="success" type="xsd:boolean" default="false" use="optional"></xsd:attribute>
|
||||
</xsd:extension>
|
||||
</xsd:simpleContent>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="FunctionPositioner">
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="DiscreteStepPositioner">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="start" type="xsd:double" maxOccurs="1" minOccurs="1"></xsd:element>
|
||||
<xsd:element name="end" type="xsd:double" maxOccurs="1" minOccurs="1"></xsd:element>
|
||||
<xsd:element name="stepSize" type="xsd:double" maxOccurs="1" minOccurs="1"></xsd:element>
|
||||
<xsd:element name="function" type="Function" maxOccurs="1" minOccurs="1"></xsd:element>
|
||||
</xsd:sequence>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
|
||||
|
||||
|
||||
<xsd:complexType name="LinePlotArray">
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="Visualization">
|
||||
<xsd:attribute name="y" type="xsd:IDREFS" use="required"></xsd:attribute>
|
||||
<xsd:attribute name="maxSeries" type="xsd:int" default="1" use="optional"></xsd:attribute>
|
||||
<xsd:attribute name="offset" type="xsd:int" use="optional" default="0"></xsd:attribute>
|
||||
<xsd:attribute name="size" type="xsd:int" use="optional" default="0"></xsd:attribute>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="MatrixPlotArray">
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="Visualization">
|
||||
<xsd:attribute name="y" type="xsd:IDREF" use="required"></xsd:attribute>
|
||||
<xsd:attribute name="z" type="xsd:IDREF" use="required"></xsd:attribute>
|
||||
<xsd:attribute name="offset" type="xsd:int" use="optional" default="0"></xsd:attribute>
|
||||
<xsd:attribute name="size" type="xsd:int" use="optional" default="0"></xsd:attribute>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="Function">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="mapping" type="ParameterMapping" minOccurs="0" maxOccurs="unbounded"></xsd:element>
|
||||
<xsd:element name="script" type="xsd:string" minOccurs="1" maxOccurs="1"></xsd:element>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="Variable">
|
||||
<xsd:attribute name="name" type="xsd:ID" use="required"></xsd:attribute>
|
||||
<xsd:attribute name="value" type="xsd:double" use="required"></xsd:attribute>
|
||||
<xsd:attribute name="description" type="xsd:string" use="optional"></xsd:attribute>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="VariableParameterMapping">
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="ParameterMapping">
|
||||
<xsd:attribute name="name" type="xsd:IDREF" use="required"></xsd:attribute>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
</xsd:schema>
|
||||
@@ -1,9 +0,0 @@
|
||||
<jxb:bindings version="1.0"
|
||||
xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
|
||||
xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
|
||||
<jxb:globalBindings>
|
||||
<jxb:serializable uid="1"/>
|
||||
</jxb:globalBindings>
|
||||
|
||||
</jxb:bindings>
|
||||
@@ -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.aq;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import ch.psi.fda.aq.AcquisitionConfiguration;
|
||||
|
||||
/**
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
public class AcquisitionConfigurationTest {
|
||||
|
||||
// Get Logger
|
||||
private static Logger logger = Logger.getLogger(AcquisitionConfigurationTest.class.getName());
|
||||
|
||||
/**
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
URL url = this.getClass().getClassLoader().getResource("home/config/fda.properties");
|
||||
System.setProperty("ch.psi.fda.config.file", new File(new URI(url.toString())).getAbsolutePath());
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.aq.AcquisitionConfiguration#getDataFilePrefix()}.
|
||||
* Test whether the supported date macros in the file prefix are resolved
|
||||
*/
|
||||
@Test
|
||||
public void testGetConfiguration() {
|
||||
AcquisitionConfiguration configuration = new AcquisitionConfiguration();
|
||||
String s = configuration.getDataFilePrefix();
|
||||
if(s==null){
|
||||
Assert.fail("No configuration returned for data file prefix");
|
||||
}
|
||||
logger.info("Data file prefix: "+s);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,232 +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.aq;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.google.common.eventbus.EventBus;
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
|
||||
import ch.psi.fda.aq.Collector;
|
||||
import ch.psi.fda.messages.ControlMessage;
|
||||
import ch.psi.fda.messages.DataMessage;
|
||||
import ch.psi.fda.messages.EndOfStreamMessage;
|
||||
import ch.psi.fda.messages.Message;
|
||||
import ch.psi.fda.messages.Metadata;
|
||||
|
||||
public class CollectorTest {
|
||||
|
||||
private static Logger logger = Logger.getLogger(CollectorTest.class.getName());
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.aq.Collector#run()}.
|
||||
*
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
@Test
|
||||
public void testRun() throws InterruptedException {
|
||||
|
||||
EventBus bus = new EventBus();
|
||||
|
||||
// Metadata
|
||||
List<Metadata> m0;
|
||||
List<Metadata> m1;
|
||||
List<Metadata> m2;
|
||||
m0 = new ArrayList<>();
|
||||
m0.add(new Metadata("id0-0", 0));
|
||||
m1 = new ArrayList<>();
|
||||
m1.add(new Metadata("id1-0", 1));
|
||||
m2 = new ArrayList<>();
|
||||
m2.add(new Metadata("id2-0", 2));
|
||||
|
||||
EventBus b0 = new EventBus();
|
||||
EventBus b1 = new EventBus();
|
||||
EventBus b2 = new EventBus();
|
||||
|
||||
Collector collector = new Collector(bus);
|
||||
collector.addEventBus(b0);
|
||||
collector.addEventBus(b1);
|
||||
collector.addEventBus(b2);
|
||||
|
||||
// Check component metadata of output queue
|
||||
|
||||
// check wether messages arrive
|
||||
bus.register(new Object() {
|
||||
|
||||
private boolean first = true;
|
||||
|
||||
@Subscribe
|
||||
public void onMessage(Message m) {
|
||||
if (m instanceof DataMessage) {
|
||||
DataMessage x = (DataMessage) m;
|
||||
|
||||
if (first) {
|
||||
first = false;
|
||||
// Check metadata
|
||||
int c = 2;
|
||||
for (Metadata cm : x.getMetadata()) {
|
||||
logger.info(String.format("id: %s dimension: %s", cm.getId(),cm.getDimension()));
|
||||
if (cm.getDimension() != c) {
|
||||
fail("Dimension number does not match required dimension number");
|
||||
}
|
||||
if (!cm.getId().equals("id" + c + "-0")) {
|
||||
fail("Id does not match required id");
|
||||
}
|
||||
c--;
|
||||
}
|
||||
}
|
||||
|
||||
logger.info(x.toString());
|
||||
} else if (m instanceof ControlMessage) {
|
||||
logger.info("---- " + m.toString() + " ----");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// dimension 2
|
||||
DataMessage m = new DataMessage(m2);
|
||||
m.getData().add(1.0);
|
||||
b2.post(m);
|
||||
|
||||
// dimension 1
|
||||
m = new DataMessage(m1);
|
||||
m.getData().add(0.1);
|
||||
b1.post(m);
|
||||
|
||||
// dimension 0
|
||||
m = new DataMessage(m0);
|
||||
m.getData().add(0.01);
|
||||
b0.post(m);
|
||||
m = new DataMessage(m0);
|
||||
m.getData().add(0.02);
|
||||
b0.post(m);
|
||||
b0.post(new EndOfStreamMessage());
|
||||
|
||||
// dimension 1
|
||||
m = new DataMessage(m1);
|
||||
m.getData().add(0.2);
|
||||
b1.post(m);
|
||||
|
||||
// dimension 0
|
||||
m = new DataMessage(m0);
|
||||
m.getData().add(0.01);
|
||||
b0.post(m);
|
||||
m = new DataMessage(m0);
|
||||
m.getData().add(0.02);
|
||||
b0.post(m);
|
||||
b0.post(new EndOfStreamMessage());
|
||||
|
||||
// dimension 1
|
||||
b1.post(new EndOfStreamMessage());
|
||||
|
||||
// dimension 2
|
||||
m = new DataMessage(m2);
|
||||
m.getData().add(2.0);
|
||||
b2.post(m);
|
||||
|
||||
// dimension 1
|
||||
m = new DataMessage(m1);
|
||||
m.getData().add(0.1);
|
||||
b1.post(m);
|
||||
|
||||
// dimension 0
|
||||
m = new DataMessage(m0);
|
||||
m.getData().add(0.01);
|
||||
b0.post(m);
|
||||
m = new DataMessage(m0);
|
||||
m.getData().add(0.02);
|
||||
b0.post(m);
|
||||
b0.post(new EndOfStreamMessage());
|
||||
|
||||
// dimension 1
|
||||
m = new DataMessage(m1);
|
||||
m.getData().add(0.2);
|
||||
b1.post(m);
|
||||
|
||||
// dimension 0
|
||||
m = new DataMessage(m0);
|
||||
m.getData().add(0.01);
|
||||
b0.post(m);
|
||||
m = new DataMessage(m0);
|
||||
m.getData().add(0.02);
|
||||
b0.post(m);
|
||||
b0.post(new EndOfStreamMessage());
|
||||
|
||||
// dimension 1
|
||||
b1.post(new EndOfStreamMessage());
|
||||
|
||||
// dimension 2
|
||||
m = new DataMessage(m2);
|
||||
m.getData().add(3.0);
|
||||
b2.post(m);
|
||||
|
||||
// dimension 1
|
||||
m = new DataMessage(m1);
|
||||
m.getData().add(0.1);
|
||||
b1.post(m);
|
||||
|
||||
// dimension 0
|
||||
m = new DataMessage(m0);
|
||||
m.getData().add(0.01);
|
||||
b0.post(m);
|
||||
m = new DataMessage(m0);
|
||||
m.getData().add(0.02);
|
||||
b0.post(m);
|
||||
b0.post(new EndOfStreamMessage());
|
||||
|
||||
// dimension 1
|
||||
m = new DataMessage(m1);
|
||||
m.getData().add(0.2);
|
||||
b1.post(m);
|
||||
|
||||
// dimension 0
|
||||
m = new DataMessage(m0);
|
||||
m.getData().add(0.01);
|
||||
b0.post(m);
|
||||
m = new DataMessage(m0);
|
||||
m.getData().add(0.02);
|
||||
b0.post(m);
|
||||
b0.post(new EndOfStreamMessage());
|
||||
|
||||
// dimension 1
|
||||
b1.post(new EndOfStreamMessage());
|
||||
|
||||
// dimension 2
|
||||
b2.post(new EndOfStreamMessage());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,490 +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.aq;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import gov.aps.jca.CAException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.google.common.eventbus.EventBus;
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
|
||||
import ch.psi.fda.TestChannels;
|
||||
import ch.psi.fda.aq.Manipulator;
|
||||
import ch.psi.fda.core.Manipulation;
|
||||
import ch.psi.fda.core.manipulator.JythonManipulation;
|
||||
import ch.psi.fda.core.scripting.JythonParameterMapping;
|
||||
import ch.psi.fda.core.scripting.JythonParameterMappingChannel;
|
||||
import ch.psi.fda.core.scripting.JythonParameterMappingID;
|
||||
import ch.psi.fda.messages.DataMessage;
|
||||
import ch.psi.fda.messages.EndOfStreamMessage;
|
||||
import ch.psi.fda.messages.Message;
|
||||
import ch.psi.fda.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.DefaultChannelService;
|
||||
|
||||
public class ManipulatorTest {
|
||||
|
||||
private static Logger logger = Logger.getLogger(ManipulatorTest.class.getName());
|
||||
|
||||
private EventBus bus;
|
||||
private ChannelService cservice;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
bus = new EventBus();
|
||||
cservice = new DefaultChannelService();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
cservice.destroy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConstructorNoMappingNoParam() {
|
||||
String id="cid";
|
||||
String script = "import math\ndef process():\n return 0.0";
|
||||
List<JythonParameterMapping> mapping = new ArrayList<JythonParameterMapping>();
|
||||
mapping.add(new JythonParameterMappingID("o", "myid"));
|
||||
JythonManipulation manipulation = new JythonManipulation(id, script, mapping);
|
||||
|
||||
List<Manipulation> manipulations = new ArrayList<Manipulation>();
|
||||
manipulations.add(manipulation);
|
||||
new Manipulator(bus, manipulations);
|
||||
// Expect IllegalArgument Exception as there is no mapping for the parameter c
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConstructorMappingNoParam() {
|
||||
List<Metadata> dmm = new ArrayList<>();
|
||||
dmm.add(new Metadata("myid"));
|
||||
dmm.add(new Metadata("myid2"));
|
||||
|
||||
String id="cid";
|
||||
String script = "import math\ndef process():\n return 0.0";
|
||||
List<JythonParameterMapping> mapping = new ArrayList<JythonParameterMapping>();
|
||||
mapping.add(new JythonParameterMappingID("o", "myid"));
|
||||
JythonManipulation manipulation = new JythonManipulation(id, script, mapping);
|
||||
|
||||
List<Manipulation> manipulations = new ArrayList<Manipulation>();
|
||||
manipulations.add(manipulation);
|
||||
new Manipulator(bus, manipulations).onMessage(new DataMessage(dmm));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.aq.Manipulator#Manipulator()}.
|
||||
*/
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void testConstructorNoMapping() {
|
||||
List<Metadata> dmm = new ArrayList<>();
|
||||
dmm.add(new Metadata("myid"));
|
||||
dmm.add(new Metadata("myid2"));
|
||||
|
||||
String id="cid";
|
||||
String script = "import math\ndef process(o ,c):\n return math.cos(c) + math.sin(o)";
|
||||
List<JythonParameterMapping> mapping = new ArrayList<JythonParameterMapping>();
|
||||
mapping.add(new JythonParameterMappingID("o", "myid"));
|
||||
JythonManipulation manipulation = new JythonManipulation(id, script, mapping);
|
||||
|
||||
List<Manipulation> manipulations = new ArrayList<Manipulation>();
|
||||
manipulations.add(manipulation);
|
||||
new Manipulator(bus, manipulations).onMessage(new DataMessage(dmm));;
|
||||
|
||||
// Expect IllegalArgument Exception as there is no mapping for the parameter c
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.aq.Manipulator#run()}.
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
@Test
|
||||
public void testRun() throws InterruptedException {
|
||||
List<Metadata> dmm = new ArrayList<>();
|
||||
dmm.add(new Metadata("myid"));
|
||||
|
||||
String id="cid";
|
||||
String script = "import math\ndef process(o):\n return math.cos(10.0) + math.sin(o)";
|
||||
List<JythonParameterMapping> mapping = new ArrayList<JythonParameterMapping>();
|
||||
mapping.add(new JythonParameterMappingID("o", "myid"));
|
||||
JythonManipulation manipulation = new JythonManipulation(id, script, mapping);
|
||||
|
||||
List<Manipulation> manipulations = new ArrayList<Manipulation>();
|
||||
manipulations.add(manipulation);
|
||||
Manipulator manipulator = new Manipulator(bus, manipulations);
|
||||
|
||||
|
||||
bus.register(new Object(){
|
||||
boolean first = true;
|
||||
@Subscribe
|
||||
public void onMessage(Message message){
|
||||
logger.info(message.toString());
|
||||
|
||||
if(message instanceof DataMessage){
|
||||
DataMessage dm = (DataMessage) message;
|
||||
|
||||
if(first){
|
||||
first=false;
|
||||
// Check whether output queue message structur complies to expected one
|
||||
|
||||
// Test whether only the expected components are within the outgoing queue
|
||||
if(dm.getMetadata().size()!=2){
|
||||
fail("There are more than the expected components in the outgoing message");
|
||||
}
|
||||
|
||||
// Test whether the id of the first component matches the expected id
|
||||
if(!dm.getMetadata().get(0).getId().equals("myid")){
|
||||
fail("Id of the first component does not match the expected id 'myid'");
|
||||
}
|
||||
|
||||
// Test whether the id of the second component (which was computed) matches the expected id
|
||||
if(!dm.getMetadata().get(1).getId().equals("cid")){
|
||||
fail("Id of the second component does not match the expected id 'cid'");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
dm.getData().get(0);
|
||||
double res = ((Double)dm.getData().get(1)) - (Math.cos(10.0)+Math.sin(((Double)dm.getData().get(0))));
|
||||
if( Math.abs(res) > 0.000000001){
|
||||
fail("Calculation failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
EventBus b = new EventBus();
|
||||
b.register(manipulator);
|
||||
|
||||
DataMessage m = new DataMessage(dmm);
|
||||
m.getData().add(10d);
|
||||
b.post(m);
|
||||
b.post(new EndOfStreamMessage());
|
||||
|
||||
logger.info(""+(Math.cos(10.0)+Math.sin(10)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test run that returns an integer
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
@Test
|
||||
public void testRunIntegerReturn() throws InterruptedException {
|
||||
List<Metadata> dmm = new ArrayList<>();
|
||||
dmm.add(new Metadata("myid"));
|
||||
|
||||
|
||||
String id="cid";
|
||||
String script = "import math\ndef process(o):\n return 1";
|
||||
List<JythonParameterMapping> mapping = new ArrayList<JythonParameterMapping>();
|
||||
mapping.add(new JythonParameterMappingID("o", "myid"));
|
||||
JythonManipulation manipulation = new JythonManipulation(id, script, mapping);
|
||||
|
||||
List<Manipulation> manipulations = new ArrayList<Manipulation>();
|
||||
manipulations.add(manipulation);
|
||||
Manipulator manipulator = new Manipulator(bus, manipulations);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bus.register(new Object(){
|
||||
|
||||
boolean first = true;
|
||||
|
||||
@Subscribe
|
||||
public void onMessage(Message message){
|
||||
|
||||
logger.info(message.toString());
|
||||
|
||||
if(message instanceof DataMessage){
|
||||
DataMessage dm = (DataMessage) message;
|
||||
|
||||
if(first){
|
||||
first=false;
|
||||
// Check whether output queue message structur complies to expected one
|
||||
|
||||
// Test whether only the expected components are within the outgoing queue
|
||||
if(dm.getMetadata().size()!=2){
|
||||
fail("There are more than the expected components in the outgoing message");
|
||||
}
|
||||
|
||||
// Test whether the id of the first component matches the expected id
|
||||
if(!dm.getMetadata().get(0).getId().equals("myid")){
|
||||
fail("Id of the first component does not match the expected id 'myid'");
|
||||
}
|
||||
|
||||
// Test whether the id of the second component (which was computed) matches the expected id
|
||||
if(!dm.getMetadata().get(1).getId().equals("cid")){
|
||||
fail("Id of the second component does not match the expected id 'cid'");
|
||||
}
|
||||
}
|
||||
|
||||
dm.getData().get(0);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
EventBus b = new EventBus();
|
||||
b.register(manipulator);
|
||||
|
||||
DataMessage m = new DataMessage(dmm);
|
||||
m.getData().add(10d);
|
||||
b.post(m);
|
||||
b.post(new EndOfStreamMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.aq.Manipulator#run()}.
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
@Ignore
|
||||
@Test
|
||||
public void testRunLongTimeTest() throws InterruptedException {
|
||||
List<Metadata> dmm = new ArrayList<>();
|
||||
dmm.add(new Metadata("myid"));
|
||||
|
||||
String id="cid";
|
||||
String script = "import math\ndef process(o):\n return math.cos(10.0) + math.sin(o)";
|
||||
List<JythonParameterMapping> mapping = new ArrayList<JythonParameterMapping>();
|
||||
mapping.add(new JythonParameterMappingID("o", "myid"));
|
||||
JythonManipulation manipulation = new JythonManipulation(id, script, mapping);
|
||||
|
||||
List<Manipulation> manipulations = new ArrayList<Manipulation>();
|
||||
manipulations.add(manipulation);
|
||||
Manipulator manipulator = new Manipulator(bus, manipulations);
|
||||
|
||||
bus.register(new Object(){
|
||||
int count=0;
|
||||
@Subscribe
|
||||
public void onMessage(Message message){
|
||||
if(!(message instanceof EndOfStreamMessage)){
|
||||
logger.info(count+" - "+message.toString());
|
||||
count++;
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
EventBus b = new EventBus();
|
||||
b.register(manipulator);
|
||||
for(Double i=0d;i<1000000;i++){
|
||||
DataMessage m = new DataMessage(dmm);
|
||||
m.getData().add(i);
|
||||
b.post(m);
|
||||
}
|
||||
b.post(new EndOfStreamMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.aq.Manipulator#run()}.
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
@Test
|
||||
public void testRunMultipleParameter() throws InterruptedException {
|
||||
List<Metadata> dmm = new ArrayList<>();
|
||||
dmm.add(new Metadata("myid"));
|
||||
dmm.add(new Metadata("myid2"));
|
||||
|
||||
|
||||
String id="cid";
|
||||
String script = "import math\ndef process(o ,c):\n return math.cos(c) + math.sin(o)";
|
||||
List<JythonParameterMapping> mapping = new ArrayList<JythonParameterMapping>();
|
||||
mapping.add(new JythonParameterMappingID("o", "myid"));
|
||||
mapping.add(new JythonParameterMappingID("c", "myid2"));
|
||||
JythonManipulation manipulation = new JythonManipulation(id, script, mapping);
|
||||
|
||||
List<Manipulation> manipulations = new ArrayList<Manipulation>();
|
||||
manipulations.add(manipulation);
|
||||
Manipulator manipulator = new Manipulator(bus, manipulations);
|
||||
|
||||
bus.register(new Object(){
|
||||
|
||||
boolean first = true;
|
||||
|
||||
@Subscribe
|
||||
public void onMessage(Message message){
|
||||
logger.info(message.toString());
|
||||
|
||||
if(message instanceof DataMessage){
|
||||
DataMessage dm = (DataMessage) message;
|
||||
|
||||
if(first){
|
||||
first=false;
|
||||
|
||||
// Check whether output queue message structur complies to expected one
|
||||
|
||||
// Test whether only the expected components are within the outgoing queue
|
||||
if(dm.getMetadata().size()!=3){
|
||||
fail("There are more than the expected components in the outgoing message");
|
||||
}
|
||||
|
||||
// Test whether the id of the first component matches the expected id
|
||||
if(!dm.getMetadata().get(0).getId().equals("myid")){
|
||||
fail("Id of the first component does not match the expected id 'myid'");
|
||||
}
|
||||
|
||||
if(!dm.getMetadata().get(1).getId().equals("myid2")){
|
||||
fail("Id of the first component does not match the expected id 'myid'");
|
||||
}
|
||||
|
||||
// Test whether the id of the second component (which was computed) matches the expected id
|
||||
if(!dm.getMetadata().get(2).getId().equals("cid")){
|
||||
fail("Id of the second component does not match the expected id 'cid'");
|
||||
}
|
||||
}
|
||||
|
||||
dm.getData().get(0);
|
||||
double res = ((Double)dm.getData().get(2)) - (Math.cos(((Double)dm.getData().get(1)))+Math.sin(((Double)dm.getData().get(0))));
|
||||
if( Math.abs(res) > 0.000000001){
|
||||
fail("Calculation failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
EventBus b = new EventBus();
|
||||
b.register(manipulator);
|
||||
|
||||
DataMessage m = new DataMessage(dmm);
|
||||
m.getData().add(10d);
|
||||
m.getData().add(0.2d);
|
||||
b.post(m);
|
||||
b.post(new EndOfStreamMessage());
|
||||
|
||||
logger.info(""+(Math.cos(0.2)+Math.sin(10)));
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.aq.Manipulator#run()}.
|
||||
* @throws InterruptedException
|
||||
* @throws CAException
|
||||
* @throws TimeoutException
|
||||
* @throws ChannelException
|
||||
* @throws ExecutionException
|
||||
*/
|
||||
@Test
|
||||
public void testRunMultipleParameterAndChannel() throws InterruptedException, CAException, ChannelException, TimeoutException, ExecutionException {
|
||||
|
||||
Double setValue = 12.22;
|
||||
|
||||
Channel<Double> channel = cservice.createChannel(new ChannelDescriptor<>(Double.class, TestChannels.ANALOG_OUT));
|
||||
|
||||
|
||||
List<Metadata> dmm = new ArrayList<>();
|
||||
dmm.add(new Metadata("myid"));
|
||||
dmm.add(new Metadata("myid2"));
|
||||
|
||||
String id="cid";
|
||||
String script = "import math\ndef process(o ,c,d):\n d.setValue("+setValue+")\n return math.cos(c) + math.sin(o)";
|
||||
List<JythonParameterMapping> mapping = new ArrayList<JythonParameterMapping>();
|
||||
mapping.add(new JythonParameterMappingID("o", "myid"));
|
||||
mapping.add(new JythonParameterMappingID("c", "myid2"));
|
||||
mapping.add(new JythonParameterMappingChannel<Double>("d", channel));
|
||||
JythonManipulation manipulation = new JythonManipulation(id, script, mapping);
|
||||
|
||||
List<Manipulation> manipulations = new ArrayList<Manipulation>();
|
||||
manipulations.add(manipulation);
|
||||
Manipulator manipulator = new Manipulator(bus, manipulations);
|
||||
|
||||
// Change something different on the channel than the value that will be set in the manipulator script
|
||||
channel.setValue(setValue+1);
|
||||
|
||||
bus.register(new Object(){
|
||||
|
||||
boolean first = true;
|
||||
|
||||
@Subscribe
|
||||
public void onMessage(Message message){
|
||||
logger.info(message.toString());
|
||||
|
||||
if(message instanceof DataMessage){
|
||||
DataMessage dm = (DataMessage) message;
|
||||
|
||||
if(first){
|
||||
first=false;
|
||||
|
||||
// Check whether output queue message structur complies to expected one
|
||||
// Test whether only the expected components are within the outgoing queue
|
||||
if(dm.getMetadata().size()!=3){
|
||||
fail("There are more than the expected components in the outgoing message");
|
||||
}
|
||||
|
||||
// Test whether the id of the first component matches the expected id
|
||||
if(!dm.getMetadata().get(0).getId().equals("myid")){
|
||||
fail("Id of the first component does not match the expected id 'myid'");
|
||||
}
|
||||
|
||||
if(!dm.getMetadata().get(1).getId().equals("myid2")){
|
||||
fail("Id of the first component does not match the expected id 'myid'");
|
||||
}
|
||||
|
||||
// Test whether the id of the second component (which was computed) matches the expected id
|
||||
if(!dm.getMetadata().get(2).getId().equals("cid")){
|
||||
fail("Id of the second component does not match the expected id 'cid'");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
dm.getData().get(0);
|
||||
double res = ((Double)dm.getData().get(2)) - (Math.cos(((Double)dm.getData().get(1)))+Math.sin(((Double)dm.getData().get(0))));
|
||||
if( Math.abs(res) > 0.000000001){
|
||||
fail("Calculation failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
EventBus b = new EventBus();
|
||||
b.register(manipulator);
|
||||
DataMessage m = new DataMessage(dmm);
|
||||
m.getData().add(10d);
|
||||
m.getData().add(0.2d);
|
||||
b.post(m);
|
||||
b.post(new EndOfStreamMessage());
|
||||
|
||||
logger.info(""+(Math.cos(0.2)+Math.sin(10)));
|
||||
|
||||
// Check whether the channel was set correctly by the manipulator script
|
||||
if(Math.abs(channel.getValue()-setValue)>0.00000001){
|
||||
fail("Channel was not set correctly in the manipulator script");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,59 +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;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import ch.psi.fda.aq.NotificationAgent;
|
||||
import ch.psi.fda.model.v1.Recipient;
|
||||
|
||||
/**
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
public class NotificationAgentTest {
|
||||
|
||||
/**
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
}
|
||||
|
||||
@Ignore
|
||||
@Test
|
||||
public void testSendNotification() {
|
||||
NotificationAgent a = new NotificationAgent("mail.psi.ch", "supertoll@psi.ch");
|
||||
Recipient r = new Recipient();
|
||||
r.setValue("simon.ebner@psi.ch");
|
||||
a.getRecipients().add(r);
|
||||
a.sendNotification("super","hello worl this is a test", true, true);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package ch.psi.fda.aq;
|
||||
|
||||
import java.util.ServiceLoader;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import ch.psi.fda.EContainerFactory;
|
||||
|
||||
public class XScanDescriptorProviderTest {
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
ServiceLoader<EContainerFactory> factories = ServiceLoader.load(EContainerFactory.class);
|
||||
for (EContainerFactory factory : factories) {
|
||||
System.out.println(factory.getClass().getName());
|
||||
}
|
||||
System.out.println("done");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,236 +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 static org.junit.Assert.fail;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import gov.aps.jca.CAException;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import ch.psi.fda.TestChannels;
|
||||
import ch.psi.fda.core.actions.ChannelAccessCondition;
|
||||
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.util.ComparatorREGEX;
|
||||
|
||||
/**
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
public class ChannelAccessConditionTest {
|
||||
|
||||
private static Logger logger = Logger.getLogger(ChannelAccessConditionTest.class.getName());
|
||||
|
||||
private ChannelService cservice;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
cservice = new DefaultChannelService();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
cservice.destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actions.ChannelAccessStringCondition#ChannelAccessStringCondition(java.lang.String, java.lang.String, long)}.
|
||||
* @throws InterruptedException
|
||||
* @throws CAException
|
||||
* @throws TimeoutException
|
||||
* @throws ChannelException
|
||||
* @throws ExecutionException
|
||||
*/
|
||||
@Test
|
||||
public void testChannelAccessStringCondition() throws InterruptedException, CAException, ChannelException, TimeoutException, ExecutionException {
|
||||
final Channel<String> channel = cservice.createChannel(new ChannelDescriptor<>(String.class, TestChannels.STRING_OUT));
|
||||
channel.setValue("SomeValue");
|
||||
ChannelAccessCondition<String> c = new ChannelAccessCondition<String>(channel, "SomeValue", 1000l);
|
||||
c.execute();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChannelAccessStringConditionRegex() throws InterruptedException, CAException, ExecutionException, ChannelException, TimeoutException {
|
||||
final Channel<String> channel = cservice.createChannel(new ChannelDescriptor<>(String.class, TestChannels.STRING_OUT));
|
||||
channel.setValue("SomeValue");
|
||||
ChannelAccessCondition<String> c = new ChannelAccessCondition<>(channel, "Some.*",new ComparatorREGEX(), 1000l);
|
||||
c.execute();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actions.ChannelAccessStringCondition#execute()}.
|
||||
* @throws CAException
|
||||
* @throws InterruptedException
|
||||
* @throws TimeoutException
|
||||
* @throws ChannelException
|
||||
* @throws ExecutionException
|
||||
*/
|
||||
@Test
|
||||
public void testExecute() throws CAException, InterruptedException, ChannelException, TimeoutException, ExecutionException {
|
||||
String value = "SomeValue";
|
||||
|
||||
final Channel<String> channel = cservice.createChannel(new ChannelDescriptor<>(String.class, TestChannels.STRING_OUT));
|
||||
final ChannelAccessCondition<String> action = new ChannelAccessCondition<String>(channel, value, 10000l);
|
||||
|
||||
|
||||
Thread t = new Thread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
action.execute();
|
||||
} catch (InterruptedException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Set the value to something else than the expected value
|
||||
channel.setValue(value+"hello");
|
||||
|
||||
// Start new thread that is executing the actions execute() method
|
||||
logger.fine("Execute action");
|
||||
t.start();
|
||||
|
||||
// Wait some time and set the channel to the expected value
|
||||
Thread.sleep(1000);
|
||||
logger.fine("Set channel value to "+value);
|
||||
channel.setValue(value);
|
||||
|
||||
// Wait thread to join and check whether the thread has terminated
|
||||
t.join(100);
|
||||
if(t.isAlive()){
|
||||
fail("Action did not return although the value was reached");
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected=RuntimeException.class)
|
||||
public void testExecuteFail() throws CAException, InterruptedException, ExecutionException, ChannelException, TimeoutException {
|
||||
String value = "SomeValue";
|
||||
|
||||
final Channel<String> channel = cservice.createChannel(new ChannelDescriptor<>(String.class, TestChannels.STRING_OUT));
|
||||
final ChannelAccessCondition<String> action = new ChannelAccessCondition<String>(channel, value, 9000l);
|
||||
|
||||
|
||||
|
||||
// Set the value to something else than the expected value
|
||||
channel.setValue(value+"hello");
|
||||
action.execute();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actions.ChannelAccessStringCondition#execute()}.
|
||||
* @throws CAException
|
||||
* @throws InterruptedException
|
||||
* @throws TimeoutException
|
||||
* @throws ChannelException
|
||||
* @throws ExecutionException
|
||||
*/
|
||||
@Test
|
||||
public void testExecuteInteger() throws CAException, InterruptedException, ChannelException, TimeoutException, ExecutionException {
|
||||
Integer value = 12;
|
||||
|
||||
final Channel<Integer> channel = cservice.createChannel(new ChannelDescriptor<>(Integer.class, TestChannels.STRING_OUT));
|
||||
final ChannelAccessCondition<Integer> action = new ChannelAccessCondition<Integer>(channel, value, 10000l);
|
||||
|
||||
|
||||
Thread t = new Thread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
action.execute();
|
||||
} catch (InterruptedException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Set the value to something else than the expected value
|
||||
channel.setValue(value+1);
|
||||
|
||||
// Start new thread that is executing the actions execute() method
|
||||
logger.fine("Execute action");
|
||||
t.start();
|
||||
|
||||
// Wait some time and set the channel to the expected value
|
||||
Thread.sleep(1000);
|
||||
logger.fine("Set channel value to "+value);
|
||||
channel.setValue(value);
|
||||
|
||||
// Wait thread to join and check whether the thread has terminated
|
||||
t.join(100);
|
||||
if(t.isAlive()){
|
||||
fail("Action did not return although the value was reached");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to ensure that the abort function is working correctly
|
||||
* @throws CAException
|
||||
* @throws InterruptedException
|
||||
* @throws TimeoutException
|
||||
* @throws ChannelException
|
||||
* @throws ExecutionException
|
||||
*/
|
||||
@Test
|
||||
public void testWaitAbort() throws CAException, InterruptedException, ChannelException, TimeoutException, ExecutionException {
|
||||
|
||||
final Channel<Integer> channel = cservice.createChannel(new ChannelDescriptor<>(Integer.class, TestChannels.BINARY_OUT));
|
||||
final ChannelAccessCondition<Integer> action = new ChannelAccessCondition<Integer>(channel, 1, 10000l);
|
||||
|
||||
|
||||
Thread t = new Thread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Thread.sleep(2000);
|
||||
logger.info("Send abort ...");
|
||||
action.abort();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Set wait channel to 0
|
||||
channel.setValue(0);
|
||||
|
||||
t.start();
|
||||
action.execute(); // timeouts after 10 seconds
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,163 +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 static org.junit.Assert.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import ch.psi.fda.TestChannels;
|
||||
import ch.psi.fda.core.actions.ChannelAccessPut;
|
||||
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;
|
||||
|
||||
public class ChannelAccessPutTest {
|
||||
|
||||
private ChannelService cservice;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
cservice = new DefaultChannelService();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
cservice.destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actions.ChannelAccessStringPut#ChannelAccessStringPut(java.lang.String, java.lang.String, boolean)}.
|
||||
* Test correct initialization
|
||||
* @throws TimeoutException
|
||||
* @throws InterruptedException
|
||||
* @throws ChannelException
|
||||
*/
|
||||
@Test
|
||||
public void testChannelAccessStringPutStringStringBoolean() throws ChannelException, InterruptedException, TimeoutException {
|
||||
new ChannelAccessPut<String>(cservice.createChannel(new ChannelDescriptor<>(String.class,TestChannels.STRING_OUT)), "SomeValue", true, null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actions.ChannelAccessStringPut#ChannelAccessStringPut(java.lang.String, java.lang.String)}.
|
||||
* Test correct initialization
|
||||
* @throws TimeoutException
|
||||
* @throws InterruptedException
|
||||
* @throws ChannelException
|
||||
*/
|
||||
@Test
|
||||
public void testChannelAccessStringPutStringString() throws ChannelException, InterruptedException, TimeoutException {
|
||||
new ChannelAccessPut<String>(cservice.createChannel(new ChannelDescriptor<>(String.class,TestChannels.STRING_OUT)), "SomeValue");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actions.ChannelAccessStringPut#ChannelAccessStringPut(java.lang.String, java.lang.String)}.
|
||||
* Test whether the correct Exception is thrown if a non existing channel is specified at creation time
|
||||
* @throws TimeoutException
|
||||
* @throws InterruptedException
|
||||
* @throws ChannelException
|
||||
*/
|
||||
@Test(expected=ChannelException.class)
|
||||
public void testChannelAccessStringPutStringStringNotExist() throws ChannelException, InterruptedException, TimeoutException {
|
||||
new ChannelAccessPut<String>(cservice.createChannel(new ChannelDescriptor<>(String.class, TestChannels.STRING_OUT_NOT_EXIST)), "SomeValue");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actions.ChannelAccessStringPut#execute()}.
|
||||
* @throws CAException
|
||||
* @throws InterruptedException
|
||||
* @throws TimeoutException
|
||||
* @throws ChannelException
|
||||
* @throws ExecutionException
|
||||
*/
|
||||
@Test
|
||||
public void testExecute() throws InterruptedException, ChannelException, TimeoutException, ExecutionException {
|
||||
|
||||
String setValue = "MyTestString";
|
||||
Channel<String> channel = cservice.createChannel(new ChannelDescriptor<>(String.class, TestChannels.STRING_OUT));
|
||||
ChannelAccessPut<String> action = new ChannelAccessPut<String>(channel, setValue);
|
||||
action.execute();
|
||||
|
||||
String value = channel.getValue();
|
||||
|
||||
if(!value.equals(setValue)){
|
||||
fail("Test string was not set correctly");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actions.ChannelAccessStringPut#execute()}.
|
||||
* @throws CAException
|
||||
* @throws TimeoutException
|
||||
* @throws ChannelException
|
||||
* @throws ExecutionException
|
||||
*/
|
||||
@Test
|
||||
public void testExecuteString() throws InterruptedException, ChannelException, TimeoutException, ExecutionException {
|
||||
|
||||
String setValue = "MyTestString";
|
||||
|
||||
Channel<String> channel = cservice.createChannel(new ChannelDescriptor<>(String.class, TestChannels.STRING_OUT));
|
||||
// Set channel to something else
|
||||
channel.setValue(setValue+"test");
|
||||
|
||||
ChannelAccessPut<String> action = new ChannelAccessPut<String>(channel, setValue);
|
||||
action.execute();
|
||||
|
||||
|
||||
String value = channel.getValue();
|
||||
|
||||
if(!value.equals(setValue)){
|
||||
fail("Test string was not set correctly");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actions.ChannelAccessStringPut#execute()}.
|
||||
* @throws CAException
|
||||
* @throws InterruptedException
|
||||
* @throws TimeoutException
|
||||
* @throws ChannelException
|
||||
*/
|
||||
@Test
|
||||
public void testExecuteMulti() throws InterruptedException, ChannelException, TimeoutException {
|
||||
|
||||
List<ChannelAccessPut<String>> actions = new ArrayList<ChannelAccessPut<String>>();
|
||||
for(int i=0;i<20;i++){
|
||||
actions.add(new ChannelAccessPut<String>(cservice.createChannel(new ChannelDescriptor<>(String.class, TestChannels.STRING_OUT)), i+""));
|
||||
}
|
||||
|
||||
for(ChannelAccessPut<String> action: actions){
|
||||
action.execute();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,104 +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 static org.junit.Assert.*;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import ch.psi.fda.core.actions.Delay;
|
||||
|
||||
/**
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
public class DelayTest {
|
||||
|
||||
// Get Logger
|
||||
private static Logger logger = Logger.getLogger(DelayTest.class.getName());
|
||||
|
||||
/**
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actions.Delay#Delay(long)}.
|
||||
* Test correct initialization
|
||||
*/
|
||||
@Test
|
||||
public void testDelay() {
|
||||
new Delay(1000);
|
||||
new Delay(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actions.Delay#Delay(long)}.
|
||||
* Test initialization with time = 0
|
||||
*/
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void testDelayZeroWait() {
|
||||
new Delay(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actions.Delay#Delay(long)}.
|
||||
* Test initialization with time < 0
|
||||
*/
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void testDelayNegativeWait() {
|
||||
new Delay(-10000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actions.Delay#execute()}.
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
@Test
|
||||
public void testExecute() throws InterruptedException {
|
||||
long wait = 1000;
|
||||
Delay action = new Delay(wait);
|
||||
long start = System.currentTimeMillis();
|
||||
action.execute();
|
||||
long end = System.currentTimeMillis();
|
||||
|
||||
// Check whether wait was of the correct length
|
||||
// Accept 10% "jitter" because of the delays of the function calls, etc.
|
||||
long elapsed = end-start;
|
||||
logger.fine("Elapsed wait time: "+elapsed+" - Specified wait time: "+wait);
|
||||
if(elapsed>(wait*1.1)){
|
||||
fail("Wait was not of the correct length");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,111 +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.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import ch.psi.fda.TestChannels;
|
||||
import ch.psi.fda.core.actions.JythonAction;
|
||||
import ch.psi.jcae.ChannelDescriptor;
|
||||
import ch.psi.jcae.ChannelException;
|
||||
import ch.psi.jcae.ChannelService;
|
||||
import ch.psi.jcae.impl.DefaultChannelService;
|
||||
|
||||
public class JythonActionTest {
|
||||
|
||||
private static String SCRIPT = "import math\ndef process(o):\n print o.getValue()\n o.setValue(-1.0)\n print o.getValue()\n val=math.cos(10.0) + math.sin(o.getValue())\n print val\n o.setValue(val)";
|
||||
private ChannelService cservice;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
cservice = new DefaultChannelService();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
cservice.destroy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExecute() throws ChannelException, InterruptedException, TimeoutException {
|
||||
try{
|
||||
Map<String,Object> mapping = new HashMap<>();
|
||||
mapping.put("o", cservice.createChannel(new ChannelDescriptor<>(Double.class, TestChannels.ANALOG_OUT)));
|
||||
|
||||
JythonAction action = new JythonAction(SCRIPT, mapping);
|
||||
|
||||
action.execute();
|
||||
}
|
||||
catch(Exception e){
|
||||
e.printStackTrace();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void testWrongMapping1() throws ChannelException, InterruptedException, TimeoutException {
|
||||
Map<String,Object> mapping = new HashMap<>();
|
||||
mapping.put("o", cservice.createChannel(new ChannelDescriptor<>(Double.class, TestChannels.ANALOG_OUT)));
|
||||
mapping.put("b", cservice.createChannel(new ChannelDescriptor<>(Double.class, TestChannels.ANALOG_OUT)));
|
||||
|
||||
String script = "import math\ndef process(o):\n print o.getValue()\n o.setValue(-1.0)\n print o.getValue()\n val=math.cos(10.0) + math.sin(o.getValue())\n print val\n o.setValue(val)";
|
||||
JythonAction action = new JythonAction(script, mapping);
|
||||
|
||||
action.execute();
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void testWrongMapping2() {
|
||||
Map<String,Object> mapping = new HashMap<>();
|
||||
mapping.put("ooo", new String());
|
||||
String script = "import math\ndef process(o):\n print o.getValue()\n o.setValue(-1.0)\n print o.getValue()\n val=math.cos(10.0) + math.sin(o.getValue())\n print val\n o.setValue(val)";
|
||||
JythonAction action = new JythonAction(script, mapping);
|
||||
|
||||
action.execute();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExecuteGlobalObjects() throws ChannelException, InterruptedException, TimeoutException {
|
||||
try{
|
||||
Map<String,Object> mapping = new HashMap<>();
|
||||
mapping.put("o", cservice.createChannel(new ChannelDescriptor<>(Double.class, TestChannels.ANALOG_OUT)));
|
||||
|
||||
Map<String,Object> gobjects = new HashMap<>();
|
||||
gobjects.put("TESTVAR", "salli!");
|
||||
|
||||
|
||||
String script = SCRIPT = "def process(o):\n print TESTVAR";
|
||||
JythonAction action = new JythonAction(script, mapping, gobjects);
|
||||
|
||||
action.execute();
|
||||
}
|
||||
catch(Exception e){
|
||||
e.printStackTrace();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,136 +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.io.File;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import ch.psi.fda.core.actions.ShellAction;
|
||||
|
||||
/**
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
public class ShellActionTest {
|
||||
|
||||
/**
|
||||
* Test Shell Script that returns with an exit code of 0
|
||||
*/
|
||||
private String[] testscripts;
|
||||
/**
|
||||
* Test Shell Script that returns with an exit code of 1
|
||||
*/
|
||||
private String testscriptError;
|
||||
/**
|
||||
* Test Shell Script that does not exist
|
||||
*/
|
||||
private String testscriptNotExist;
|
||||
|
||||
/**
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
URL url = this.getClass().getClassLoader().getResource("testscripts");
|
||||
String file = new File(new URI(url.toString())).getAbsolutePath()+"/../../../src/test/resources/testscripts";
|
||||
// need to perform this hack as the copied scripts in the target directory do not have the execute permissions
|
||||
|
||||
// test scripts also need to be able to accept options !!!!
|
||||
testscripts = new String[]{file+"/testscript1.sh", file+"/testscript1.sh -option opt a b "};
|
||||
testscriptError = file+"/testscript2-error.sh";
|
||||
testscriptNotExist = file+"/testscriptNotExist.sh";
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actions.ShellAction#ScriptAction(java.lang.String)}.
|
||||
* Test the creation of a ScriptAction object with an existing script.
|
||||
*/
|
||||
@Test
|
||||
public void testScriptAction() {
|
||||
for(String testscript: testscripts){
|
||||
new ShellAction(testscript);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actions.ShellAction#ScriptAction(java.lang.String)}.
|
||||
* Test the creation of a ScriptAction object with a non existing script. IllegalArgumentException expected ...
|
||||
*/
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void testScriptActionScriptNotExit() {
|
||||
new ShellAction(testscriptNotExist);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actions.ShellAction#execute()}.
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
@Test
|
||||
public void testExecute() throws InterruptedException {
|
||||
for(String testscript: testscripts){
|
||||
File f = new File(testscript);
|
||||
f.setExecutable(true); // Make file executable
|
||||
ShellAction action = new ShellAction(testscript);
|
||||
action.execute();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actions.ShellAction#execute()}.
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
@Test(expected=RuntimeException.class)
|
||||
public void testExecuteError() throws InterruptedException {
|
||||
ShellAction action = new ShellAction(testscriptError);
|
||||
action.execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actions.ShellAction#execute()}.
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
@Test
|
||||
public void testExecuteErrorDisabledCheck() throws InterruptedException {
|
||||
ShellAction action = new ShellAction(testscriptError);
|
||||
action.setCheckExitValue(false);
|
||||
action.execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actions.ShellAction#abort()}.
|
||||
*/
|
||||
@Test
|
||||
public void testAbort() {
|
||||
// Abort function in ScriptAction is not implemented - therefore there is nothing to test.
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,780 +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 static org.junit.Assert.fail;
|
||||
|
||||
import java.net.SocketException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import ch.psi.fda.TestChannels;
|
||||
import ch.psi.fda.core.actors.ChannelAccessFunctionActuator;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Test class specific for the FunctionActuatorChannelAccess implementation.
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
public class ChannelAccessFunctionActuatorTest {
|
||||
|
||||
private static Logger logger = Logger.getLogger(ChannelAccessFunctionActuatorTest.class.getName());
|
||||
|
||||
private static final String channelName = TestChannels.ANALOG_OUT;
|
||||
private static final String channelNameDone = TestChannels.BINARY_OUT;
|
||||
private static final int doneValue = 1;
|
||||
private static final double doneDelay = 0;
|
||||
private static final Long timeout = 1800000l; // 30 minutes
|
||||
|
||||
private ChannelService cservice;
|
||||
private Channel<Double> channel;
|
||||
private Channel<Integer> doneChannel;
|
||||
|
||||
private Function function;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
cservice = new DefaultChannelService();
|
||||
channel = cservice.createChannel(new ChannelDescriptor<>(Double.class, channelName));
|
||||
doneChannel = cservice.createChannel(new ChannelDescriptor<>(Integer.class, channelNameDone));
|
||||
|
||||
function = new Function() {
|
||||
|
||||
@Override
|
||||
public double calculate(double parameter) {
|
||||
return parameter+2; // Translation by 2
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
cservice.destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.ChannelAccessFunctionActuator#FunctionActuatorChannelAccess(String, double, double, double)}.
|
||||
* Check whether Exception is thrown if a negative step size is specified.
|
||||
*/
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void testChannelAccessFunctionActuatorNegativeStepSize() throws SocketException, Exception {
|
||||
// Need to throw exception because of negative step size
|
||||
new ChannelAccessFunctionActuator<Object>(channel, function,0, 1, -0.1, timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.ChannelAccessFunctionActuator#FunctionActuatorChannelAccess(String, double, double, double)}.
|
||||
*/
|
||||
@Test
|
||||
public void testChannelAccessFunctionActuatorTimeout() throws SocketException, Exception {
|
||||
|
||||
// Negative timeout
|
||||
boolean flag = false;
|
||||
try{
|
||||
// Need to return IllegalArgumentException due to negative Timeout
|
||||
new ChannelAccessFunctionActuator<Object>(channel, function, 0, 1, 0.1, -1l);
|
||||
}
|
||||
catch(IllegalArgumentException e){
|
||||
flag=true;
|
||||
}
|
||||
if(!flag){
|
||||
fail("Negative timeout is not handeled correctly");
|
||||
}
|
||||
|
||||
// 0 timeout
|
||||
flag=false;
|
||||
try{
|
||||
// Need to return IllegalArgumentException
|
||||
new ChannelAccessFunctionActuator<Object>(channel, function, 0, 1, 0.1, -0l);
|
||||
}
|
||||
catch(IllegalArgumentException e){
|
||||
flag=true;
|
||||
}
|
||||
if(!flag){
|
||||
fail("0 timeout is not handled correctly");
|
||||
}
|
||||
|
||||
// Accept null timeout
|
||||
new ChannelAccessFunctionActuator<Object>(channel, function, 0, 1, 0.1, null);
|
||||
|
||||
// Accept positive timeout
|
||||
new ChannelAccessFunctionActuator<Object>(channel, function, 0, 1, 0.1, 1l);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.ChannelAccessFunctionActuator#FunctionActuatorChannelAccess(String, double, double, double)}.
|
||||
* Check whether Exception is thrown if a zero step size is specified.
|
||||
*/
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void testChannelAccessFunctionActuatorZeroStepSize() throws SocketException, Exception {
|
||||
// Zero step size need to cause an exception
|
||||
new ChannelAccessFunctionActuator<Object>(channel, function, 0, 1, 0, timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.ChannelAccessFunctionActuator#FunctionActuatorChannelAccess(String, double, double, double)}.
|
||||
* Check correct initialization
|
||||
*/
|
||||
public void testChannelAccessFunctionActuator() throws SocketException, Exception {
|
||||
// Zero step size need to cause an exception
|
||||
new ChannelAccessFunctionActuator<Object>(channel, function, 0, 10, 1, timeout);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.ChannelAccessFunctionActuator#set()}.
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
@Test
|
||||
public void testSet() throws InterruptedException {
|
||||
ChannelAccessFunctionActuator<Object> actuator = new ChannelAccessFunctionActuator<Object>(channel, function, 0, 0.09999, 0.1, timeout);
|
||||
actuator.set();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.ChannelAccessFunctionActuator#hasNext()}.
|
||||
* Check whether the actuator throws an Exception if there is no next point but set() is called
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
@Test(expected=IllegalStateException.class)
|
||||
public void testSetNoNext() throws InterruptedException {
|
||||
ChannelAccessFunctionActuator<Object> actuator = new ChannelAccessFunctionActuator<Object>(channel, function, 0, 0.09999, 0.1, timeout);
|
||||
actuator.set();
|
||||
actuator.set();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.ChannelAccessFunctionActuator#hasNext()}.
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
@Test
|
||||
public void testHasNextOneStep() throws InterruptedException {
|
||||
ChannelAccessFunctionActuator<Object> actuator = new ChannelAccessFunctionActuator<Object>(channel, function, 0, 0.09999, 0.1, timeout);
|
||||
// Execute first set (because there is always a first move)
|
||||
actuator.set();
|
||||
|
||||
// Check whether actuator returns that there is no next point
|
||||
boolean next = actuator.hasNext();
|
||||
if(next){
|
||||
fail("There must be no next step");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.ChannelAccessFunctionActuator#hasNext()}.
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
@Test
|
||||
public void testHasNext() throws InterruptedException {
|
||||
ChannelAccessFunctionActuator<Object> actuator = new ChannelAccessFunctionActuator<Object>(channel, function, 0, 10, 0.1, timeout);
|
||||
|
||||
int count = 0;
|
||||
int steps = (int) ((10-0)/0.1)+1;
|
||||
while(actuator.hasNext()){
|
||||
actuator.set();
|
||||
count++;
|
||||
}
|
||||
|
||||
logger.fine("Actual steps: "+count+" - Needed steps: "+steps);
|
||||
if(count != steps){
|
||||
fail("Actuator set more steps than specified");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.ChannelAccessFunctionActuator#set()}.
|
||||
* Test actuator move start<end and start>end ...
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
@Test
|
||||
public void testSetLoop() throws InterruptedException {
|
||||
|
||||
List<double[]> settings = new ArrayList<double[]>();
|
||||
// start end stepsize
|
||||
settings.add(new double[] {0, 10, 0.1});
|
||||
settings.add(new double[] {0, -1, 0.1});
|
||||
|
||||
|
||||
for(double[] svalue: settings){
|
||||
ChannelAccessFunctionActuator<Object> actuator = new ChannelAccessFunctionActuator<Object>(channel, function, svalue[0], svalue[1], svalue[2], timeout);
|
||||
|
||||
int count =0;
|
||||
while(actuator.hasNext()){
|
||||
actuator.set();
|
||||
count++;
|
||||
}
|
||||
|
||||
int cnt = (int) Math.floor(Math.abs(svalue[0]-svalue[1])/svalue[2])+1;
|
||||
|
||||
if(count != cnt){
|
||||
fail("Actuator did not move required steps [actual count: "+count+" needed count: "+cnt+" ]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.ChannelAccessFunctionActuator#set()}.
|
||||
* Test actuator move start<end and start>end ...
|
||||
* @throws ExecutionException
|
||||
* @throws ChannelException
|
||||
* @throws TimeoutException
|
||||
* @throws CAException
|
||||
*/
|
||||
@Test
|
||||
public void testReverse() throws InterruptedException, TimeoutException, ChannelException, ExecutionException {
|
||||
|
||||
List<double[]> settings = new ArrayList<double[]>();
|
||||
// start end stepsize
|
||||
settings.add(new double[] {0, 10, 0.1});
|
||||
settings.add(new double[] {0, -1, 0.1});
|
||||
|
||||
|
||||
for(double[] svalue: settings){
|
||||
ChannelAccessFunctionActuator<Object> actuator = new ChannelAccessFunctionActuator<Object>(channel, function, svalue[0], svalue[1], svalue[2], timeout);
|
||||
actuator.init();
|
||||
|
||||
int count =0;
|
||||
while(actuator.hasNext()){
|
||||
actuator.set();
|
||||
|
||||
// Check set value
|
||||
double val = channel.getValue();
|
||||
logger.info("Value: "+val);
|
||||
if(svalue[0]<svalue[1]){
|
||||
double sval = function.calculate(svalue[0]+(count*svalue[2]));
|
||||
if(Math.abs(val-sval) > 0.001){ // 0.001 is precision
|
||||
fail("Set value ["+sval+"] does not match actual value ["+val+"]");
|
||||
}
|
||||
}
|
||||
else{
|
||||
double sval = function.calculate(svalue[0]-(count*svalue[2]));
|
||||
if(Math.abs(val-sval) > 0.001){ // 0.001 is precision
|
||||
fail("Set value ["+sval+"] does not match actual value ["+val+"]");
|
||||
}
|
||||
}
|
||||
count++;
|
||||
}
|
||||
|
||||
int cnt = (int) Math.floor(Math.abs(svalue[0]-svalue[1])/svalue[2])+1;
|
||||
|
||||
if(count != cnt){
|
||||
fail("Actuator did not move required steps [actual count: "+count+" needed count: "+cnt+" ]");
|
||||
}
|
||||
|
||||
|
||||
actuator.reverse();
|
||||
actuator.init();
|
||||
count =0;
|
||||
while(actuator.hasNext()){
|
||||
actuator.set();
|
||||
|
||||
// Check set value
|
||||
double val = channel.getValue();
|
||||
logger.info("Value: "+val);
|
||||
if(svalue[1]<svalue[0]){
|
||||
double sval = function.calculate(svalue[1]+(count*svalue[2]));
|
||||
if(Math.abs(val-sval) > 0.001){ // 0.001 is precision
|
||||
fail("Set value ["+sval+"] does not match actual value ["+val+"]");
|
||||
}
|
||||
}
|
||||
else{
|
||||
double sval = function.calculate(svalue[1]-(count*svalue[2]));
|
||||
if(Math.abs(val-sval) > 0.001){ // 0.001 is precision
|
||||
fail("Set value ["+sval+"] does not match actual value ["+val+"]");
|
||||
}
|
||||
}
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
cnt = (int) Math.floor(Math.abs(svalue[0]-svalue[1])/svalue[2])+1;
|
||||
|
||||
if(count != cnt){
|
||||
fail("Actuator did not move required steps [actual count: "+count+" needed count: "+cnt+" ]");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.ChannelAccessFunctionActuator#set()}.
|
||||
* Test actuator move start<end and start>end ...
|
||||
* @throws ExecutionException
|
||||
* @throws ChannelException
|
||||
* @throws TimeoutException
|
||||
* @throws CAException
|
||||
*/
|
||||
@Test
|
||||
public void testReverseReset() throws InterruptedException, TimeoutException, ChannelException, ExecutionException {
|
||||
|
||||
List<double[]> settings = new ArrayList<double[]>();
|
||||
// start end stepsize
|
||||
settings.add(new double[] {0, 10, 0.1});
|
||||
settings.add(new double[] {0, -1, 0.1});
|
||||
|
||||
|
||||
for(double[] svalue: settings){
|
||||
ChannelAccessFunctionActuator<Object> actuator = new ChannelAccessFunctionActuator<Object>(channel, function, svalue[0], svalue[1], svalue[2], timeout);
|
||||
actuator.init();
|
||||
|
||||
int count =0;
|
||||
while(actuator.hasNext()){
|
||||
actuator.set();
|
||||
|
||||
// Check set value
|
||||
double val = channel.getValue();
|
||||
logger.info("Value: "+val);
|
||||
if(svalue[0]<svalue[1]){
|
||||
double sval = function.calculate(svalue[0]+(count*svalue[2]));
|
||||
if(Math.abs(val-sval) > 0.001){ // 0.001 is precision
|
||||
fail("Set value ["+sval+"] does not match actual value ["+val+"]");
|
||||
}
|
||||
}
|
||||
else{
|
||||
double sval = function.calculate(svalue[0]-(count*svalue[2]));
|
||||
if(Math.abs(val-sval) > 0.001){ // 0.001 is precision
|
||||
fail("Set value ["+sval+"] does not match actual value ["+val+"]");
|
||||
}
|
||||
}
|
||||
count++;
|
||||
}
|
||||
|
||||
int cnt = (int) Math.floor(Math.abs(svalue[0]-svalue[1])/svalue[2])+1;
|
||||
|
||||
if(count != cnt){
|
||||
fail("Actuator did not move required steps [actual count: "+count+" needed count: "+cnt+" ]");
|
||||
}
|
||||
|
||||
|
||||
actuator.reverse();
|
||||
actuator.reset();
|
||||
actuator.init();
|
||||
count =0;
|
||||
while(actuator.hasNext()){
|
||||
actuator.set();
|
||||
|
||||
// Check set value
|
||||
double val = channel.getValue();
|
||||
logger.info("Value: "+val);
|
||||
if(svalue[0]<svalue[1]){
|
||||
double sval = function.calculate(svalue[0]+(count*svalue[2]));
|
||||
if(Math.abs(val-sval) > 0.001){ // 0.001 is precision
|
||||
fail("Set value ["+sval+"] does not match actual value ["+val+"]");
|
||||
}
|
||||
}
|
||||
else{
|
||||
double sval = function.calculate(svalue[0]-(count*svalue[2]));
|
||||
if(Math.abs(val-sval) > 0.001){ // 0.001 is precision
|
||||
fail("Set value ["+sval+"] does not match actual value ["+val+"]");
|
||||
}
|
||||
}
|
||||
count++;
|
||||
}
|
||||
|
||||
cnt = (int) Math.floor(Math.abs(svalue[0]-svalue[1])/svalue[2])+1;
|
||||
|
||||
if(count != cnt){
|
||||
fail("Actuator did not move required steps [actual count: "+count+" needed count: "+cnt+" ]");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// TODO Check if actuator makes the required number of steps
|
||||
// TODO Check if actuator makes the steps in the right direction
|
||||
// TODO Check if actuator really blocks until motor/actuator is moved.
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.ChannelAccessGPFunctionActuator#FunctionActuatorChannelAccess(String, double, double, double)}.
|
||||
* Check whether Exception is thrown if a negative step size is specified.
|
||||
*/
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void testChannelAccessGPFunctionActuatorNegativeStepSize() throws SocketException, Exception {
|
||||
// Need to throw exception because of negative step size
|
||||
new ChannelAccessFunctionActuator<>(channel, doneChannel, doneValue, doneDelay, function, 0, 1, -0.1, timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.ChannelAccessGPFunctionActuator#FunctionActuatorChannelAccess(String, double, double, double)}.
|
||||
* Check whether Exception is thrown if a zero step size is specified.
|
||||
*/
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void testChannelAccessGPFunctionActuatorZeroStepSize() throws SocketException, Exception {
|
||||
// Zero step size need to cause an exception
|
||||
new ChannelAccessFunctionActuator<>(channel, doneChannel, doneValue, doneDelay, function, 0, 1, 0, timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.ChannelAccessGPFunctionActuator#FunctionActuatorChannelAccess(String, double, double, double)}.
|
||||
* Check correct initialization
|
||||
*/
|
||||
public void testChannelAccessGPFunctionActuator() throws SocketException, Exception {
|
||||
// Zero step size need to cause an exception
|
||||
new ChannelAccessFunctionActuator<>(channel, doneChannel, doneValue, doneDelay, function, 0, 10, 1, timeout);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.ChannelAccessGPFunctionActuator#set()}.
|
||||
* @throws ChannelException
|
||||
* @throws ExecutionException
|
||||
* @throws CAException
|
||||
*/
|
||||
@Test
|
||||
public void testDoneSet() throws InterruptedException, ExecutionException, ChannelException {
|
||||
|
||||
ChannelAccessFunctionActuator<Integer> actuator = new ChannelAccessFunctionActuator<>(channel, doneChannel, doneValue, doneDelay, function, 0, 0.09999, 0.1, timeout);
|
||||
|
||||
// Simulate done channel
|
||||
doneChannel.setValue(0);
|
||||
new Thread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
try {
|
||||
Thread.sleep(3000);
|
||||
doneChannel.setValue(1);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
}
|
||||
}).start();
|
||||
|
||||
actuator.set();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.ChannelAccessGPFunctionActuator#set()}.
|
||||
* @throws ChannelException
|
||||
* @throws ExecutionException
|
||||
* @throws CAException
|
||||
*/
|
||||
@Test
|
||||
public void testDoneDelay() throws InterruptedException, ExecutionException, ChannelException {
|
||||
|
||||
ChannelAccessFunctionActuator<Integer> actuator = new ChannelAccessFunctionActuator<>(channel, doneChannel, doneValue, 1.5, function, 0, 1, 0.1, timeout);
|
||||
|
||||
// Simulate done channel
|
||||
doneChannel.setValue(1);
|
||||
new Thread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
doneChannel.setValue(0);
|
||||
Thread.sleep(4000);
|
||||
doneChannel.setValue(1);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
}
|
||||
}).start();
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
actuator.set();
|
||||
long end = System.currentTimeMillis();
|
||||
|
||||
logger.fine("Elapsed time: "+(end-start));
|
||||
if((end-start)<4000){ // Check whether all the moves took less than 6 seconds (thats the delay the done is set to 1)
|
||||
fail("Done delay does not work");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.ChannelAccessGPFunctionActuator#hasNext()}.
|
||||
* Check whether the actuator throws an Exception if there is no next point but set() is called
|
||||
* @throws ChannelException
|
||||
* @throws ExecutionException
|
||||
* @throws CAException
|
||||
*/
|
||||
@Test(expected=IllegalStateException.class)
|
||||
public void testDoneSetNoNext() throws InterruptedException, ExecutionException, ChannelException {
|
||||
|
||||
ChannelAccessFunctionActuator<Integer> actuator = new ChannelAccessFunctionActuator<>(channel, doneChannel, doneValue, doneDelay, function,0, 0.09999, 0.1, timeout);
|
||||
|
||||
|
||||
// Simulate done channel
|
||||
doneChannel.setValue(0);
|
||||
new Thread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
try {
|
||||
Thread.sleep(3000);
|
||||
doneChannel.setValue(1);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
}
|
||||
}).start();
|
||||
|
||||
actuator.set();
|
||||
|
||||
|
||||
// Simulate done channel
|
||||
doneChannel.setValue(0);
|
||||
new Thread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
try {
|
||||
Thread.sleep(3000);
|
||||
doneChannel.setValue(1);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
}
|
||||
}).start();
|
||||
|
||||
actuator.set();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.ChannelAccessGPFunctionActuator#hasNext()}.
|
||||
* @throws ChannelException
|
||||
* @throws ExecutionException
|
||||
* @throws CAException
|
||||
*/
|
||||
@Test
|
||||
public void testDoneHasNextOneStep() throws InterruptedException, ExecutionException, ChannelException {
|
||||
ChannelAccessFunctionActuator<Integer> actuator = new ChannelAccessFunctionActuator<>(channel, doneChannel, doneValue, doneDelay, function, 0, 0.09999, 0.1, timeout);
|
||||
|
||||
// Simulate done channel
|
||||
doneChannel.setValue(0);
|
||||
new Thread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
try {
|
||||
Thread.sleep(3000);
|
||||
doneChannel.setValue(1);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
}
|
||||
}).start();
|
||||
|
||||
// Execute first set (because there is always a first move)
|
||||
actuator.set();
|
||||
|
||||
// Check whether actuator returns that there is no next point
|
||||
boolean next = actuator.hasNext();
|
||||
if(next){
|
||||
fail("There must be no next step");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.ChannelAccessGPFunctionActuator#hasNext()}.
|
||||
* @throws ChannelException
|
||||
* @throws ExecutionException
|
||||
* @throws CAException
|
||||
*/
|
||||
@Test
|
||||
public void testDoneHasNext() throws InterruptedException, ExecutionException, ChannelException {
|
||||
ChannelAccessFunctionActuator<Integer> actuator = new ChannelAccessFunctionActuator<>(channel, doneChannel, doneValue, doneDelay, function,0, 10, 0.1, timeout);
|
||||
|
||||
int count = 0;
|
||||
int steps = (int) ((10-0)/0.1)+1;
|
||||
while(actuator.hasNext()){
|
||||
|
||||
// Simulate done channel
|
||||
doneChannel.setValue(0);
|
||||
new Thread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
try {
|
||||
Thread.sleep(10);
|
||||
doneChannel.setValue(1);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
}
|
||||
}).start();
|
||||
|
||||
actuator.set();
|
||||
count++;
|
||||
}
|
||||
|
||||
logger.fine("Actual steps: "+count+" - Needed steps: "+steps);
|
||||
if(count != steps){
|
||||
fail("Actuator set more steps than specified");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.ChannelAccessGPFunctionActuator#set()}.
|
||||
* Test actuator move start<end and start>end ...
|
||||
* @throws ChannelException
|
||||
* @throws ExecutionException
|
||||
* @throws CAException
|
||||
*/
|
||||
@Test
|
||||
public void testDoneSetLoop() throws InterruptedException, ExecutionException, ChannelException {
|
||||
|
||||
List<double[]> settings = new ArrayList<double[]>();
|
||||
// start end stepsize
|
||||
settings.add(new double[] {0, 10, 0.1});
|
||||
settings.add(new double[] {0, -1, 0.1});
|
||||
|
||||
|
||||
for(double[] svalue: settings){
|
||||
ChannelAccessFunctionActuator<Integer> actuator = new ChannelAccessFunctionActuator<>(channel, doneChannel, doneValue, doneDelay, function, svalue[0], svalue[1], svalue[2], timeout);
|
||||
|
||||
int count =0;
|
||||
while(actuator.hasNext()){
|
||||
|
||||
// Simulate done channel
|
||||
doneChannel.setValue(0);
|
||||
new Thread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
try {
|
||||
Thread.sleep(10);
|
||||
doneChannel.setValue(1);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
}
|
||||
}).start();
|
||||
|
||||
actuator.set();
|
||||
count++;
|
||||
}
|
||||
|
||||
int cnt = (int) Math.floor(Math.abs(svalue[0]-svalue[1])/svalue[2])+1;
|
||||
|
||||
if(count != cnt){
|
||||
fail("Actuator did not move required steps [actual count: "+count+" needed count: "+cnt+" ]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.ChannelAccessGPFunctionActuator#set()}.
|
||||
* Test whether the actuator returns if the actuator is already on the position it should be before the move ...
|
||||
* (see issue XASEC-278)
|
||||
* @throws ExecutionException
|
||||
* @throws ChannelException
|
||||
* @throws TimeoutException
|
||||
* @throws CAException
|
||||
*/
|
||||
@Test
|
||||
public void testMoveToActualPosition() throws InterruptedException, TimeoutException, ChannelException, ExecutionException {
|
||||
|
||||
double start = 0;
|
||||
double end = 2;
|
||||
double stepSize = 1;
|
||||
|
||||
channel.setValue(start);
|
||||
|
||||
Thread.sleep(1000);
|
||||
|
||||
logger.info("Current channel value: "+channel.getValue());
|
||||
|
||||
ChannelAccessFunctionActuator<Integer> actuator = new ChannelAccessFunctionActuator<>(channel, doneChannel, doneValue, doneDelay, function, start, end, stepSize, timeout);
|
||||
while(actuator.hasNext()){
|
||||
|
||||
// Simulate done channel
|
||||
doneChannel.setValue(1);
|
||||
// new Thread(new Runnable() {
|
||||
//
|
||||
// @Override
|
||||
// public void run() {
|
||||
//
|
||||
// try {
|
||||
// Thread.sleep(10);
|
||||
//// doneChannel.setValue(1);
|
||||
// } catch (Exception e) {
|
||||
// }
|
||||
//
|
||||
// }
|
||||
// }).start();
|
||||
|
||||
actuator.set();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSetLoop2() throws InterruptedException {
|
||||
|
||||
Function function = new Function() {
|
||||
|
||||
@Override
|
||||
public double calculate(double parameter) {
|
||||
return parameter+2;
|
||||
}
|
||||
};
|
||||
|
||||
List<double[]> settings = new ArrayList<double[]>();
|
||||
// start end stepsize
|
||||
settings.add(new double[] {0, 10, 0.1});
|
||||
settings.add(new double[] {0, -1, 0.1});
|
||||
|
||||
|
||||
for(double[] svalue: settings){
|
||||
ChannelAccessFunctionActuator<Object> actuator = new ChannelAccessFunctionActuator<>(channel, function, svalue[0], svalue[1], svalue[2], timeout);
|
||||
|
||||
int count =0;
|
||||
while(actuator.hasNext()){
|
||||
actuator.set();
|
||||
count++;
|
||||
}
|
||||
|
||||
int cnt = (int) Math.floor(Math.abs(svalue[0]-svalue[1])/svalue[2])+1;
|
||||
|
||||
if(count != cnt){
|
||||
fail("Actuator did not move required steps [actual count: "+count+" needed count: "+cnt+" ]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,731 +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 static org.junit.Assert.fail;
|
||||
|
||||
import java.net.SocketException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import ch.psi.fda.TestChannels;
|
||||
import ch.psi.fda.core.actors.ChannelAccessLinearActuator;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Test class specific for the LinearActuatorChannelAccess implementation.
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
public class ChannelAccessLinearActuatorTest {
|
||||
|
||||
// Get Logger
|
||||
private static Logger logger = Logger.getLogger(ChannelAccessLinearActuatorTest.class.getName());
|
||||
|
||||
private static final String channelName = TestChannels.ANALOG_OUT;
|
||||
private static final String channelNameDone = TestChannels.BINARY_OUT;
|
||||
private static final int doneValue = 1;
|
||||
private static final double doneDelay = 0;
|
||||
private static final Long timeout = 1800000l; // 30 minutes
|
||||
|
||||
private ChannelService cservice;
|
||||
private Channel<Double> channel;
|
||||
private Channel<Integer> doneChannel;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
cservice = new DefaultChannelService();
|
||||
channel = cservice.createChannel(new ChannelDescriptor<>(Double.class, channelName));
|
||||
doneChannel = cservice.createChannel(new ChannelDescriptor<>(Integer.class, channelNameDone));
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
cservice.destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.ChannelAccessLinearActuator#LinearActuatorChannelAccess(String, double, double, double)}.
|
||||
* Check whether Exception is thrown if a negative step size is specified.
|
||||
*/
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void testChannelAccessLinearActuatorNegativeStepSize() throws SocketException, Exception {
|
||||
// Need to throw exception because of negative step size
|
||||
new ChannelAccessLinearActuator<Object>(channel, null, 1,0, 0, 1, -0.1, timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.ChannelAccessLinearActuator#LinearActuatorChannelAccess(String, double, double, double)}.
|
||||
*/
|
||||
@Test
|
||||
public void testChannelAccessLinearActuatorTimeout() throws SocketException, Exception {
|
||||
|
||||
// Negative timeout
|
||||
boolean flag = false;
|
||||
try{
|
||||
// Need to return IllegalArgumentException due to negative Timeout
|
||||
new ChannelAccessLinearActuator<Object>(channel, null, 1,0, 0, 1, 0.1, -1l);
|
||||
}
|
||||
catch(IllegalArgumentException e){
|
||||
flag=true;
|
||||
}
|
||||
if(!flag){
|
||||
fail("Negative timeout is not handeled correctly");
|
||||
}
|
||||
|
||||
// 0 timeout
|
||||
flag=false;
|
||||
try{
|
||||
// Need to return IllegalArgumentException
|
||||
new ChannelAccessLinearActuator<Object>(channel, null, 1,0, 0, 1, 0.1, -0l);
|
||||
}
|
||||
catch(IllegalArgumentException e){
|
||||
flag=true;
|
||||
}
|
||||
if(!flag){
|
||||
fail("0 timeout is not handled correctly");
|
||||
}
|
||||
|
||||
// Accept null timeout
|
||||
new ChannelAccessLinearActuator<Object>(channel, null, 1,0, 0, 1, 0.1, null);
|
||||
|
||||
// Accept positive timeout
|
||||
new ChannelAccessLinearActuator<Object>(channel, null, 1,0, 0, 1, 0.1, 1l);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.ChannelAccessLinearActuator#LinearActuatorChannelAccess(String, double, double, double)}.
|
||||
* Check whether Exception is thrown if a zero step size is specified.
|
||||
*/
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void testChannelAccessLinearActuatorZeroStepSize() throws SocketException, Exception {
|
||||
// Zero step size need to cause an exception
|
||||
new ChannelAccessLinearActuator<Object>(channel, null, 1,0, 0, 1, 0, timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.ChannelAccessLinearActuator#LinearActuatorChannelAccess(String, double, double, double)}.
|
||||
* Check correct initialization
|
||||
*/
|
||||
public void testChannelAccessLinearActuator() throws SocketException, Exception {
|
||||
// Zero step size need to cause an exception
|
||||
new ChannelAccessLinearActuator<Object>(channel, null, 1,0, 0, 10, 1, timeout);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.ChannelAccessLinearActuator#set()}.
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
@Test
|
||||
public void testSet() throws InterruptedException {
|
||||
ChannelAccessLinearActuator<Object> actuator = new ChannelAccessLinearActuator<Object>(channel, null, 1,0, 0, 0.09999, 0.1, timeout);
|
||||
actuator.set();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.ChannelAccessLinearActuator#hasNext()}.
|
||||
* Check whether the actuator throws an Exception if there is no next point but set() is called
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
@Test(expected=IllegalStateException.class)
|
||||
public void testSetNoNext() throws InterruptedException {
|
||||
ChannelAccessLinearActuator<Object> actuator = new ChannelAccessLinearActuator<Object>(channel, null, 1,0, 0, 0.09999, 0.1, timeout);
|
||||
actuator.set();
|
||||
actuator.set();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.ChannelAccessLinearActuator#hasNext()}.
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
@Test
|
||||
public void testHasNextOneStep() throws InterruptedException {
|
||||
ChannelAccessLinearActuator<Object> actuator = new ChannelAccessLinearActuator<Object>(channel, null, 1,0, 0, 0.09999, 0.1, timeout);
|
||||
// Execute first set (because there is always a first move)
|
||||
actuator.set();
|
||||
|
||||
// Check whether actuator returns that there is no next point
|
||||
boolean next = actuator.hasNext();
|
||||
if(next){
|
||||
fail("There must be no next step");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.ChannelAccessLinearActuator#hasNext()}.
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
@Test
|
||||
public void testHasNext() throws InterruptedException {
|
||||
ChannelAccessLinearActuator<Object> actuator = new ChannelAccessLinearActuator<Object>(channel, null, 1,0, 0, 10, 0.1, timeout);
|
||||
|
||||
int count = 0;
|
||||
int steps = (int) ((10-0)/0.1)+1;
|
||||
while(actuator.hasNext()){
|
||||
actuator.set();
|
||||
count++;
|
||||
}
|
||||
|
||||
logger.fine("Actual steps: "+count+" - Needed steps: "+steps);
|
||||
if(count != steps){
|
||||
fail("Actuator set more steps than specified");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.ChannelAccessLinearActuator#set()}.
|
||||
* Test actuator move start<end and start>end ...
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
@Test
|
||||
public void testSetLoop() throws InterruptedException {
|
||||
|
||||
List<double[]> settings = new ArrayList<double[]>();
|
||||
// start end stepsize
|
||||
settings.add(new double[] {0, 10, 0.1});
|
||||
settings.add(new double[] {0, -1, 0.1});
|
||||
|
||||
|
||||
for(double[] svalue: settings){
|
||||
ChannelAccessLinearActuator<Integer> actuator = new ChannelAccessLinearActuator<Integer>(channel, null, 1,0, svalue[0], svalue[1], svalue[2], timeout);
|
||||
|
||||
int count =0;
|
||||
while(actuator.hasNext()){
|
||||
actuator.set();
|
||||
count++;
|
||||
}
|
||||
|
||||
int cnt = (int) Math.floor(Math.abs(svalue[0]-svalue[1])/svalue[2])+1;
|
||||
|
||||
if(count != cnt){
|
||||
fail("Actuator did not move required steps [actual count: "+count+" needed count: "+cnt+" ]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.ChannelAccessLinearActuator#set()}.
|
||||
* Test actuator move start<end and start>end ...
|
||||
* @throws ExecutionException
|
||||
* @throws ChannelException
|
||||
* @throws TimeoutException
|
||||
* @throws CAException
|
||||
*/
|
||||
@Test
|
||||
public void testReverse() throws InterruptedException, TimeoutException, ChannelException, ExecutionException {
|
||||
|
||||
List<double[]> settings = new ArrayList<double[]>();
|
||||
// start end stepsize
|
||||
settings.add(new double[] {0, 10, 0.1});
|
||||
settings.add(new double[] {0, -1, 0.1});
|
||||
|
||||
|
||||
for(double[] svalue: settings){
|
||||
ChannelAccessLinearActuator<Object> actuator = new ChannelAccessLinearActuator<Object>(channel, null, 1,0, svalue[0], svalue[1], svalue[2], timeout);
|
||||
actuator.init();
|
||||
|
||||
int count =0;
|
||||
while(actuator.hasNext()){
|
||||
actuator.set();
|
||||
|
||||
// Check set value
|
||||
double val = channel.getValue();
|
||||
logger.info("Value: "+val);
|
||||
if(svalue[0]<svalue[1]){
|
||||
|
||||
if(Math.abs(val-(svalue[0]+(count*svalue[2]))) > 0.001){ // 0.001 is precision
|
||||
fail("Set value does not match actual value");
|
||||
}
|
||||
}
|
||||
else{
|
||||
if(Math.abs(val-(svalue[0]-(count*svalue[2]))) > 0.001){ // 0.001 is precision
|
||||
fail("Set value does not match actual value");
|
||||
}
|
||||
}
|
||||
count++;
|
||||
}
|
||||
|
||||
int cnt = (int) Math.floor(Math.abs(svalue[0]-svalue[1])/svalue[2])+1;
|
||||
|
||||
if(count != cnt){
|
||||
fail("Actuator did not move required steps [actual count: "+count+" needed count: "+cnt+" ]");
|
||||
}
|
||||
|
||||
|
||||
actuator.reverse();
|
||||
actuator.init();
|
||||
count =0;
|
||||
while(actuator.hasNext()){
|
||||
actuator.set();
|
||||
|
||||
// Check set value
|
||||
double val = channel.getValue();
|
||||
logger.info("Value: "+val);
|
||||
if(svalue[1]<svalue[0]){
|
||||
|
||||
if(Math.abs(val-(svalue[1]+(count*svalue[2]))) > 0.001){ // 0.001 is precision
|
||||
fail("Set value does not match actual value");
|
||||
}
|
||||
}
|
||||
else{
|
||||
if(Math.abs(val-(svalue[1]-(count*svalue[2]))) > 0.001){ // 0.001 is precision
|
||||
fail("Set value does not match actual value");
|
||||
}
|
||||
}
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
cnt = (int) Math.floor(Math.abs(svalue[0]-svalue[1])/svalue[2])+1;
|
||||
|
||||
if(count != cnt){
|
||||
fail("Actuator did not move required steps [actual count: "+count+" needed count: "+cnt+" ]");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.ChannelAccessLinearActuator#set()}.
|
||||
* Test actuator move start<end and start>end ...
|
||||
* @throws ExecutionException
|
||||
* @throws ChannelException
|
||||
* @throws TimeoutException
|
||||
* @throws CAException
|
||||
*/
|
||||
@Test
|
||||
public void testReverseReset() throws InterruptedException, TimeoutException, ChannelException, ExecutionException {
|
||||
|
||||
List<double[]> settings = new ArrayList<double[]>();
|
||||
// start end stepsize
|
||||
settings.add(new double[] {0, 10, 0.1});
|
||||
settings.add(new double[] {0, -1, 0.1});
|
||||
|
||||
|
||||
for(double[] svalue: settings){
|
||||
ChannelAccessLinearActuator<Object> actuator = new ChannelAccessLinearActuator<Object>(channel, null, 1,0, svalue[0], svalue[1], svalue[2], timeout);
|
||||
actuator.init();
|
||||
|
||||
int count =0;
|
||||
while(actuator.hasNext()){
|
||||
actuator.set();
|
||||
|
||||
// Check set value
|
||||
double val = channel.getValue();
|
||||
logger.info("Value: "+val);
|
||||
if(svalue[0]<svalue[1]){
|
||||
|
||||
if(Math.abs(val-(svalue[0]+(count*svalue[2]))) > 0.001){ // 0.001 is precision
|
||||
fail("Set value does not match actual value");
|
||||
}
|
||||
}
|
||||
else{
|
||||
if(Math.abs(val-(svalue[0]-(count*svalue[2]))) > 0.001){ // 0.001 is precision
|
||||
fail("Set value does not match actual value");
|
||||
}
|
||||
}
|
||||
count++;
|
||||
}
|
||||
|
||||
int cnt = (int) Math.floor(Math.abs(svalue[0]-svalue[1])/svalue[2])+1;
|
||||
|
||||
if(count != cnt){
|
||||
fail("Actuator did not move required steps [actual count: "+count+" needed count: "+cnt+" ]");
|
||||
}
|
||||
|
||||
|
||||
actuator.reverse();
|
||||
actuator.reset();
|
||||
actuator.init();
|
||||
count =0;
|
||||
while(actuator.hasNext()){
|
||||
actuator.set();
|
||||
|
||||
// Check set value
|
||||
double val = channel.getValue();
|
||||
logger.info("Value: "+val);
|
||||
if(svalue[0]<svalue[1]){
|
||||
|
||||
if(Math.abs(val-(svalue[0]+(count*svalue[2]))) > 0.001){ // 0.001 is precision
|
||||
fail("Set value does not match actual value");
|
||||
}
|
||||
}
|
||||
else{
|
||||
if(Math.abs(val-(svalue[0]-(count*svalue[2]))) > 0.001){ // 0.001 is precision
|
||||
fail("Set value does not match actual value");
|
||||
}
|
||||
}
|
||||
count++;
|
||||
}
|
||||
|
||||
cnt = (int) Math.floor(Math.abs(svalue[0]-svalue[1])/svalue[2])+1;
|
||||
|
||||
if(count != cnt){
|
||||
fail("Actuator did not move required steps [actual count: "+count+" needed count: "+cnt+" ]");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// TODO Check if actuator makes the required number of steps
|
||||
// TODO Check if actuator makes the steps in the right direction
|
||||
// TODO Check if actuator really blocks until motor/actuator is moved.
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.ChannelAccessGPLinearActuator#LinearActuatorChannelAccess(String, double, double, double)}.
|
||||
* Check whether Exception is thrown if a negative step size is specified.
|
||||
*/
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void testChannelAccessGPLinearActuatorNegativeStepSize() throws SocketException, Exception {
|
||||
// Need to throw exception because of negative step size
|
||||
new ChannelAccessLinearActuator<>(channel, doneChannel, doneValue, doneDelay, 0, 1, -0.1, timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.ChannelAccessGPLinearActuator#LinearActuatorChannelAccess(String, double, double, double)}.
|
||||
* Check whether Exception is thrown if a zero step size is specified.
|
||||
*/
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void testChannelAccessGPLinearActuatorZeroStepSize() throws SocketException, Exception {
|
||||
// Zero step size need to cause an exception
|
||||
new ChannelAccessLinearActuator<>(channel, doneChannel, doneValue, doneDelay, 0, 1, 0, timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.ChannelAccessGPLinearActuator#LinearActuatorChannelAccess(String, double, double, double)}.
|
||||
* Check correct initialization
|
||||
*/
|
||||
public void testChannelAccessGPLinearActuator() throws SocketException, Exception {
|
||||
// Zero step size need to cause an exception
|
||||
new ChannelAccessLinearActuator<>(channel, doneChannel, doneValue, doneDelay, 0, 10, 1, timeout);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.ChannelAccessGPLinearActuator#set()}.
|
||||
* @throws ChannelException
|
||||
* @throws ExecutionException
|
||||
* @throws CAException
|
||||
*/
|
||||
@Test
|
||||
public void testDoneSet() throws InterruptedException, ExecutionException, ChannelException {
|
||||
|
||||
ChannelAccessLinearActuator<Integer> actuator = new ChannelAccessLinearActuator<>(channel, doneChannel, doneValue, doneDelay, 0, 0.09999, 0.1, timeout);
|
||||
|
||||
// Simulate done channel
|
||||
doneChannel.setValue(0);
|
||||
new Thread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
try {
|
||||
Thread.sleep(3000);
|
||||
doneChannel.setValue(1);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
}
|
||||
}).start();
|
||||
|
||||
actuator.set();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.ChannelAccessGPLinearActuator#set()}.
|
||||
* @throws ChannelException
|
||||
* @throws ExecutionException
|
||||
* @throws CAException
|
||||
*/
|
||||
@Test
|
||||
public void testDoneDelay() throws InterruptedException, ExecutionException, ChannelException {
|
||||
|
||||
ChannelAccessLinearActuator<Integer> actuator = new ChannelAccessLinearActuator<>(channel, doneChannel, doneValue, 1.5, 0, 1, 0.1, timeout);
|
||||
|
||||
// Simulate done channel
|
||||
doneChannel.setValue(1);
|
||||
new Thread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
doneChannel.setValue(0);
|
||||
Thread.sleep(4000);
|
||||
doneChannel.setValue(1);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
}
|
||||
}).start();
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
actuator.set();
|
||||
long end = System.currentTimeMillis();
|
||||
|
||||
logger.fine("Elapsed time: "+(end-start));
|
||||
if((end-start)<4000){ // Check whether all the moves took less than 6 seconds (thats the delay the done is set to 1)
|
||||
fail("Done delay does not work");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.ChannelAccessGPLinearActuator#hasNext()}.
|
||||
* Check whether the actuator throws an Exception if there is no next point but set() is called
|
||||
* @throws ChannelException
|
||||
* @throws ExecutionException
|
||||
* @throws CAException
|
||||
*/
|
||||
@Test(expected=IllegalStateException.class)
|
||||
public void testDoneSetNoNext() throws InterruptedException, ExecutionException, ChannelException {
|
||||
|
||||
ChannelAccessLinearActuator<Integer> actuator = new ChannelAccessLinearActuator<>(channel, doneChannel, doneValue, doneDelay, 0, 0.09999, 0.1, timeout);
|
||||
|
||||
|
||||
// Simulate done channel
|
||||
doneChannel.setValue(0);
|
||||
new Thread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
try {
|
||||
Thread.sleep(3000);
|
||||
doneChannel.setValue(1);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
}
|
||||
}).start();
|
||||
|
||||
actuator.set();
|
||||
|
||||
|
||||
// Simulate done channel
|
||||
doneChannel.setValue(0);
|
||||
new Thread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
try {
|
||||
Thread.sleep(3000);
|
||||
doneChannel.setValue(1);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
}
|
||||
}).start();
|
||||
|
||||
actuator.set();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.ChannelAccessGPLinearActuator#hasNext()}.
|
||||
* @throws ChannelException
|
||||
* @throws ExecutionException
|
||||
* @throws CAException
|
||||
*/
|
||||
@Test
|
||||
public void testDoneHasNextOneStep() throws InterruptedException, ExecutionException, ChannelException {
|
||||
ChannelAccessLinearActuator<Integer> actuator = new ChannelAccessLinearActuator<>(channel, doneChannel, doneValue, doneDelay, 0, 0.09999, 0.1, timeout);
|
||||
|
||||
// Simulate done channel
|
||||
doneChannel.setValue(0);
|
||||
new Thread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
try {
|
||||
Thread.sleep(3000);
|
||||
doneChannel.setValue(1);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
}
|
||||
}).start();
|
||||
|
||||
// Execute first set (because there is always a first move)
|
||||
actuator.set();
|
||||
|
||||
// Check whether actuator returns that there is no next point
|
||||
boolean next = actuator.hasNext();
|
||||
if(next){
|
||||
fail("There must be no next step");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.ChannelAccessGPLinearActuator#hasNext()}.
|
||||
* @throws ChannelException
|
||||
* @throws ExecutionException
|
||||
* @throws CAException
|
||||
*/
|
||||
@Test
|
||||
public void testDoneHasNext() throws InterruptedException, ExecutionException, ChannelException {
|
||||
ChannelAccessLinearActuator<Integer> actuator = new ChannelAccessLinearActuator<>(channel, doneChannel, doneValue, doneDelay, 0, 10, 0.1, timeout);
|
||||
|
||||
int count = 0;
|
||||
int steps = (int) ((10-0)/0.1)+1;
|
||||
while(actuator.hasNext()){
|
||||
|
||||
// Simulate done channel
|
||||
doneChannel.setValue(0);
|
||||
new Thread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
try {
|
||||
Thread.sleep(10);
|
||||
doneChannel.setValue(1);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
}
|
||||
}).start();
|
||||
|
||||
actuator.set();
|
||||
count++;
|
||||
}
|
||||
|
||||
logger.fine("Actual steps: "+count+" - Needed steps: "+steps);
|
||||
if(count != steps){
|
||||
fail("Actuator set more steps than specified");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.ChannelAccessGPLinearActuator#set()}.
|
||||
* Test actuator move start<end and start>end ...
|
||||
* @throws ChannelException
|
||||
* @throws ExecutionException
|
||||
* @throws CAException
|
||||
*/
|
||||
@Test
|
||||
public void testDoneSetLoop() throws InterruptedException, ExecutionException, ChannelException {
|
||||
|
||||
List<double[]> settings = new ArrayList<double[]>();
|
||||
// start end stepsize
|
||||
settings.add(new double[] {0, 10, 0.1});
|
||||
settings.add(new double[] {0, -1, 0.1});
|
||||
|
||||
|
||||
for(double[] svalue: settings){
|
||||
ChannelAccessLinearActuator<Integer> actuator = new ChannelAccessLinearActuator<>(channel, doneChannel, doneValue, doneDelay, svalue[0], svalue[1], svalue[2], timeout);
|
||||
|
||||
int count =0;
|
||||
while(actuator.hasNext()){
|
||||
|
||||
// Simulate done channel
|
||||
doneChannel.setValue(0);
|
||||
new Thread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
try {
|
||||
Thread.sleep(10);
|
||||
doneChannel.setValue(1);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
}
|
||||
}).start();
|
||||
|
||||
actuator.set();
|
||||
count++;
|
||||
}
|
||||
|
||||
int cnt = (int) Math.floor(Math.abs(svalue[0]-svalue[1])/svalue[2])+1;
|
||||
|
||||
if(count != cnt){
|
||||
fail("Actuator did not move required steps [actual count: "+count+" needed count: "+cnt+" ]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.ChannelAccessGPLinearActuator#set()}.
|
||||
* Test whether the actuator returns if the actuator is already on the position it should be before the move ...
|
||||
* (see issue XASEC-278)
|
||||
* @throws ChannelException
|
||||
* @throws ExecutionException
|
||||
* @throws TimeoutException
|
||||
* @throws CAException
|
||||
*/
|
||||
@Test
|
||||
public void testMoveToActualPosition() throws InterruptedException, ExecutionException, ChannelException, TimeoutException {
|
||||
|
||||
double start = 0;
|
||||
double end = 2;
|
||||
double stepSize = 1;
|
||||
|
||||
channel.setValue(start);
|
||||
|
||||
Thread.sleep(1000);
|
||||
|
||||
logger.info("Current channel value: "+channel.getValue());
|
||||
|
||||
ChannelAccessLinearActuator<Integer> actuator = new ChannelAccessLinearActuator<>(channel, doneChannel, doneValue, doneDelay, start, end, stepSize, timeout);
|
||||
while(actuator.hasNext()){
|
||||
|
||||
// Simulate done channel
|
||||
doneChannel.setValue(1);
|
||||
// new Thread(new Runnable() {
|
||||
//
|
||||
// @Override
|
||||
// public void run() {
|
||||
//
|
||||
// try {
|
||||
// Thread.sleep(10);
|
||||
//// doneChannel.setValue(1);
|
||||
// } catch (Exception e) {
|
||||
// }
|
||||
//
|
||||
// }
|
||||
// }).start();
|
||||
|
||||
actuator.set();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,490 +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 static org.junit.Assert.*;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import ch.psi.fda.TestChannels;
|
||||
import ch.psi.fda.core.actors.ChannelAccessTableActuator;
|
||||
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;
|
||||
|
||||
public class ChannelAccessTableActuatorTest {
|
||||
|
||||
private static Logger logger = Logger.getLogger(ChannelAccessTableActuatorTest.class.getName());
|
||||
|
||||
private static final String channelName = TestChannels.BINARY_OUT;
|
||||
private static final String channelNameDone = TestChannels.BINARY_OUT_TWO;
|
||||
|
||||
private static final int doneValue = 1;
|
||||
private static final double doneDelay = 0;
|
||||
private static final Long timeout = 1800000l; // 30 minutes
|
||||
|
||||
private ChannelService cservice;
|
||||
private Channel<Double> channel;
|
||||
private Channel<Integer> doneChannel;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
cservice = new DefaultChannelService();
|
||||
channel = cservice.createChannel(new ChannelDescriptor<>(Double.class, channelName));
|
||||
doneChannel = cservice.createChannel(new ChannelDescriptor<>(Integer.class, channelNameDone));
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
cservice.destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.ChannelAccessTableActuator#ChannelAccessTableActuator(java.lang.String, double[])}.
|
||||
*/
|
||||
@Test
|
||||
public void testChannelAccessTableActuator() {
|
||||
new ChannelAccessTableActuator<>(channel, new double[]{1}, timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.ChannelAccessTableActuator#ChannelAccessTableActuator(java.lang.String, double[])}.
|
||||
*/
|
||||
@Test
|
||||
public void testChannelAccessTableActuatorTimeout() {
|
||||
// Negative timeout
|
||||
boolean flag = false;
|
||||
try{
|
||||
// Need to return IllegalArgumentException due to negative Timeout
|
||||
new ChannelAccessTableActuator<>(channel, new double[]{1}, -1l);
|
||||
}
|
||||
catch(IllegalArgumentException e){
|
||||
flag=true;
|
||||
}
|
||||
if(!flag){
|
||||
fail("Negative timeout is not handeled correctly");
|
||||
}
|
||||
|
||||
// 0 timeout
|
||||
flag=false;
|
||||
try{
|
||||
// Need to return IllegalArgumentException
|
||||
new ChannelAccessTableActuator<>(channel, new double[]{1}, 0l);
|
||||
}
|
||||
catch(IllegalArgumentException e){
|
||||
flag=true;
|
||||
}
|
||||
if(!flag){
|
||||
fail("0 timeout is not handled correctly");
|
||||
}
|
||||
|
||||
// Accept null timeout
|
||||
new ChannelAccessTableActuator<>(channel, new double[]{1}, null);
|
||||
|
||||
// Accept positive timeout
|
||||
new ChannelAccessTableActuator<>(channel, new double[]{1}, 1l);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.ChannelAccessTableActuator#ChannelAccessTableActuator(java.lang.String, double[])}.
|
||||
* Test that constructor fails while providing a null table
|
||||
*/
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void testChannelAccessTableActuatorNull() {
|
||||
new ChannelAccessTableActuator<>(channel, null, timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.ChannelAccessTableActuator#ChannelAccessTableActuator(java.lang.String, double[])}.
|
||||
* Test that constructor fails while providing an empty table
|
||||
*/
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void testChannelAccessTableActuatorEmptyTable() {
|
||||
new ChannelAccessTableActuator<>(channel, new double[0], timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.ChannelAccessTableActuator#set()}.
|
||||
* @throws ExecutionException
|
||||
* @throws ChannelException
|
||||
* @throws TimeoutException
|
||||
* @throws CAException
|
||||
*/
|
||||
@Test
|
||||
public void testSet() throws InterruptedException, TimeoutException, ChannelException, ExecutionException {
|
||||
double[] table = new double[]{1,2,3,4,5,6};
|
||||
ChannelAccessTableActuator<Object> actor = new ChannelAccessTableActuator<>(channel, table, timeout);
|
||||
|
||||
int count=0;
|
||||
while(actor.hasNext()){
|
||||
actor.set();
|
||||
|
||||
if(channel.getValue()!=table[count]){
|
||||
fail("Channel value does not match expected set value");
|
||||
}
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
if(count != table.length){
|
||||
fail("Not all points given in the table were set");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.ChannelAccessTableActuator#set()}.
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
@Test(expected=RuntimeException.class)
|
||||
public void testSetFail() throws InterruptedException {
|
||||
double[] table = new double[]{1};
|
||||
ChannelAccessTableActuator<Object> actor = new ChannelAccessTableActuator<>(channel, table, timeout);
|
||||
actor.set();
|
||||
|
||||
// This set() call has to fail with an RuntimeException
|
||||
actor.set();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.ChannelAccessTableActuator#hasNext()}.
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
@Test
|
||||
public void testHasNext() throws InterruptedException {
|
||||
|
||||
double[] table = new double[]{1};
|
||||
ChannelAccessTableActuator<Object> actor = new ChannelAccessTableActuator<>(channel, table, timeout);
|
||||
actor.set();
|
||||
|
||||
boolean next = actor.hasNext();
|
||||
if(next){
|
||||
fail("There must be no next step");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.ChannelAccessTableActuator#set()}.
|
||||
* @throws ExecutionException
|
||||
* @throws ChannelException
|
||||
* @throws TimeoutException
|
||||
* @throws CAException
|
||||
*/
|
||||
@Test
|
||||
public void testReverse() throws InterruptedException, TimeoutException, ChannelException, ExecutionException {
|
||||
double[] table = new double[]{1,2,3,4,5,6};
|
||||
ChannelAccessTableActuator<Object> actor = new ChannelAccessTableActuator<Object>(channel, table, timeout);
|
||||
actor.init();
|
||||
|
||||
int count=0;
|
||||
while(actor.hasNext()){
|
||||
actor.set();
|
||||
|
||||
if(channel.getValue()!=table[count]){
|
||||
fail("Channel value does not match expected set value");
|
||||
}
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
if(count != table.length){
|
||||
fail("Not all points given in the table were set");
|
||||
}
|
||||
|
||||
actor.reverse();
|
||||
actor.init();
|
||||
|
||||
count=0;
|
||||
while(actor.hasNext()){
|
||||
actor.set();
|
||||
|
||||
if(channel.getValue()!=table[table.length-1-count]){
|
||||
fail("Channel value does not match expected set value");
|
||||
}
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
if(count != table.length){
|
||||
fail("Not all points given in the table were set");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.ChannelAccessTableActuator#set()}.
|
||||
* @throws ExecutionException
|
||||
* @throws ChannelException
|
||||
* @throws TimeoutException
|
||||
* @throws CAException
|
||||
*/
|
||||
@Test
|
||||
public void testReverseReset() throws InterruptedException, TimeoutException, ChannelException, ExecutionException {
|
||||
double[] table = new double[]{1,2,3,4,5,6};
|
||||
ChannelAccessTableActuator<Object> actor = new ChannelAccessTableActuator<Object>(channel, table, timeout);
|
||||
actor.init();
|
||||
|
||||
int count=0;
|
||||
while(actor.hasNext()){
|
||||
actor.set();
|
||||
|
||||
if(channel.getValue()!=table[count]){
|
||||
fail("Channel value does not match expected set value");
|
||||
}
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
if(count != table.length){
|
||||
fail("Not all points given in the table were set");
|
||||
}
|
||||
|
||||
actor.reverse();
|
||||
actor.reset();
|
||||
actor.init();
|
||||
|
||||
count=0;
|
||||
while(actor.hasNext()){
|
||||
actor.set();
|
||||
|
||||
if(channel.getValue()!=table[count]){
|
||||
fail("Channel value does not match expected set value");
|
||||
}
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
if(count != table.length){
|
||||
fail("Not all points given in the table were set");
|
||||
}
|
||||
}
|
||||
|
||||
// DONE
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.ChannelAccessTableActuator#ChannelAccessTableActuator(java.lang.String, double[])}.
|
||||
*/
|
||||
@Test
|
||||
public void testDoneChannelAccessTableActuator() {
|
||||
new ChannelAccessTableActuator<>(channel, doneChannel, doneValue, doneDelay, new double[]{1}, timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.ChannelAccessTableActuator#ChannelAccessTableActuator(java.lang.String, double[])}.
|
||||
* Test that constructor fails while providing a null table
|
||||
*/
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void testDoneChannelAccessTableActuatorNull() {
|
||||
new ChannelAccessTableActuator<>(channel, doneChannel, doneValue, doneDelay, null, timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.ChannelAccessTableActuator#ChannelAccessTableActuator(java.lang.String, double[])}.
|
||||
* Test that constructor fails while providing an empty table
|
||||
*/
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void testDoneChannelAccessTableActuatorEmptyTable() {
|
||||
new ChannelAccessTableActuator<>(channel, doneChannel, doneValue, doneDelay, new double[0], timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.ChannelAccessTableActuator#set()}.
|
||||
* @throws ChannelException
|
||||
* @throws ExecutionException
|
||||
* @throws TimeoutException
|
||||
* @throws CAException
|
||||
*/
|
||||
@Test
|
||||
public void testDoneSet() throws InterruptedException, ExecutionException, ChannelException, TimeoutException {
|
||||
double[] table = new double[]{1,2,3,4,5,6};
|
||||
ChannelAccessTableActuator<Integer> actor = new ChannelAccessTableActuator<>(channel, doneChannel, doneValue, doneDelay, table, timeout);
|
||||
|
||||
int count=0;
|
||||
while(actor.hasNext()){
|
||||
// Simulate done channel
|
||||
doneChannel.setValue(0);
|
||||
new Thread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
doneChannel.setValue(1);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
}
|
||||
}).start();
|
||||
actor.set();
|
||||
|
||||
if(channel.getValue()!=table[count]){
|
||||
fail("Channel value does not match expected set value");
|
||||
}
|
||||
count++;
|
||||
}
|
||||
|
||||
if(count != table.length){
|
||||
fail("Not all points given in the table were set");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.ChannelAccessTableActuator#set()}.
|
||||
* @throws ChannelException
|
||||
* @throws ExecutionException
|
||||
* @throws TimeoutException
|
||||
* @throws CAException
|
||||
*/
|
||||
@Test
|
||||
public void testDoneDelay() throws InterruptedException, ExecutionException, ChannelException, TimeoutException {
|
||||
double[] table = new double[]{1,2,3,4,5,6};
|
||||
ChannelAccessTableActuator<Integer> actor = new ChannelAccessTableActuator<>(channel, doneChannel, doneValue, 0.1, table, timeout);
|
||||
|
||||
int count=0;
|
||||
long start = System.currentTimeMillis();
|
||||
while(actor.hasNext()){
|
||||
// Simulate done channel
|
||||
doneChannel.setValue(1);
|
||||
new Thread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
try {
|
||||
Thread.sleep(10);
|
||||
doneChannel.setValue(0);
|
||||
Thread.sleep(1000);
|
||||
doneChannel.setValue(1);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
}
|
||||
}).start();
|
||||
actor.set();
|
||||
|
||||
if(channel.getValue()!=table[count]){
|
||||
fail("Channel value does not match expected set value");
|
||||
}
|
||||
count++;
|
||||
}
|
||||
long end = System.currentTimeMillis();
|
||||
|
||||
|
||||
if(count != table.length){
|
||||
fail("Not all points given in the table were set");
|
||||
}
|
||||
|
||||
logger.fine("Elapsed time: "+(end-start));
|
||||
if((end-start)<6000){ // check whether all the moves took less than 6 seconds (thats the delay the done is set to 1)
|
||||
fail("Done delay does not work");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.ChannelAccessTableActuator#set()}.
|
||||
* @throws ChannelException
|
||||
* @throws ExecutionException
|
||||
* @throws CAException
|
||||
*/
|
||||
@Test(expected=RuntimeException.class)
|
||||
public void testDoneSetFail() throws InterruptedException, ExecutionException, ChannelException {
|
||||
double[] table = new double[]{1};
|
||||
ChannelAccessTableActuator<Integer> actor = new ChannelAccessTableActuator<>(channel, doneChannel, doneValue, doneDelay, table, timeout);
|
||||
// Simulate done channel
|
||||
doneChannel.setValue(0);
|
||||
new Thread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
try {
|
||||
Thread.sleep(3000);
|
||||
doneChannel.setValue(1);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
}
|
||||
}).start();
|
||||
actor.set();
|
||||
|
||||
// This set() call has to fail with an RuntimeException
|
||||
// Simulate done channel
|
||||
doneChannel.setValue(0);
|
||||
new Thread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
try {
|
||||
Thread.sleep(3000);
|
||||
doneChannel.setValue(1);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
}
|
||||
}).start();
|
||||
actor.set();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.ChannelAccessTableActuator#hasNext()}.
|
||||
* @throws ChannelException
|
||||
* @throws ExecutionException
|
||||
* @throws CAException
|
||||
*/
|
||||
@Test
|
||||
public void testDoneHasNext() throws InterruptedException, ExecutionException, ChannelException {
|
||||
|
||||
double[] table = new double[]{1};
|
||||
ChannelAccessTableActuator<Integer> actor = new ChannelAccessTableActuator<>(channel, doneChannel, doneValue, doneDelay, table, timeout);
|
||||
|
||||
// Simulate done channel
|
||||
doneChannel.setValue(0);
|
||||
new Thread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
try {
|
||||
Thread.sleep(3000);
|
||||
doneChannel.setValue(1);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
}
|
||||
}).start();
|
||||
actor.set();
|
||||
|
||||
boolean next = actor.hasNext();
|
||||
if(next){
|
||||
fail("There must be no next step");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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.actors;
|
||||
|
||||
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import ch.psi.fda.TestChannels;
|
||||
import ch.psi.fda.core.actors.ChannelAccessLinearActuator;
|
||||
import ch.psi.fda.core.actors.ComplexActuator;
|
||||
import ch.psi.jcae.ChannelDescriptor;
|
||||
import ch.psi.jcae.ChannelException;
|
||||
import ch.psi.jcae.ChannelService;
|
||||
import ch.psi.jcae.impl.DefaultChannelService;
|
||||
|
||||
/**
|
||||
* Prerequisites for this test are:
|
||||
* All Actors that are used inside this test (except the ComplexActuator) need to be tested and
|
||||
* fully compliant to their specification.
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
public class ComplexActorTest {
|
||||
|
||||
private static Logger logger = Logger.getLogger(ComplexActorTest.class.getName());
|
||||
|
||||
private static final Long timeout = 1800000l;
|
||||
private ChannelService cservice;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
cservice = new DefaultChannelService();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
cservice.destroy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSet() throws InterruptedException, ChannelException, TimeoutException {
|
||||
|
||||
ComplexActuator actuator = new ComplexActuator();
|
||||
|
||||
actuator.getActors().add(new ChannelAccessLinearActuator<Object>(cservice.createChannel(new ChannelDescriptor<>(Double.class, TestChannels.ANALOG_OUT)), null, 1,0, 0, 0.09999, 0.1, timeout));
|
||||
actuator.getActors().add(new ChannelAccessLinearActuator<Object>(cservice.createChannel(new ChannelDescriptor<>(Double.class, TestChannels.ANALOG_OUT)), null, 1,0, 1, 2, 0.1, timeout));
|
||||
actuator.getActors().add(new ChannelAccessLinearActuator<Object>(cservice.createChannel(new ChannelDescriptor<>(Double.class, TestChannels.ANALOG_OUT)), null, 1,0, -1, -2, 0.1, timeout));
|
||||
|
||||
// Initialize actuator
|
||||
actuator.init();
|
||||
|
||||
int count = 0;
|
||||
while(actuator.hasNext()){
|
||||
actuator.set();
|
||||
count++;
|
||||
}
|
||||
|
||||
logger.fine("Execution count: "+count);
|
||||
if(count!=23){ // There are 23 steps to do with the registered actors
|
||||
fail("Actor did not perform all the steps");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,120 +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 java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import ch.psi.fda.core.scripting.JythonGlobalVariable;
|
||||
|
||||
/**
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
public class JythonFunctionTest {
|
||||
|
||||
// Get Logger
|
||||
private static final Logger logger = Logger.getLogger(JythonFunctionTest.class.getName());
|
||||
|
||||
/**
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.JythonFunction#calculate(double)}.
|
||||
*/
|
||||
@Test
|
||||
public void testCalculate() {
|
||||
Map<String, JythonGlobalVariable> map = new HashMap<String, JythonGlobalVariable>();
|
||||
|
||||
String script = "import math\ndef "+JythonFunction.ENTRY_FUNCTION_NAME+"(parameter):\n return math.sqrt(parameter)";
|
||||
JythonFunction f = new JythonFunction(script, map);
|
||||
|
||||
double rval = f.calculate(4);
|
||||
logger.info("Return value: "+rval);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.JythonFunction#calculate(double)}.
|
||||
*/
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void testCalculateNoVariableMapping() {
|
||||
Map<String, JythonGlobalVariable> map = new HashMap<String, JythonGlobalVariable>();
|
||||
String script = "import math\ndef "+JythonFunction.ENTRY_FUNCTION_NAME+"(parameter, a):\n return math.sqrt(parameter)+a.getValue()";
|
||||
new JythonFunction(script, map); // Must throw IllegalArgumentException !!!!
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.JythonFunction#calculate(double)}.
|
||||
*/
|
||||
@Test
|
||||
public void testCalculateVariableMapping() {
|
||||
Map<String, JythonGlobalVariable> map = new HashMap<String, JythonGlobalVariable>();
|
||||
JythonGlobalVariable v = new JythonGlobalVariable();
|
||||
v.setName("a");
|
||||
v.setValue(1.5);
|
||||
map.put("a", v);
|
||||
|
||||
String script = "import math\ndef "+JythonFunction.ENTRY_FUNCTION_NAME+"(parameter, a):\n return math.sqrt(parameter)+a.getValue()";
|
||||
JythonFunction f = new JythonFunction(script, map);
|
||||
|
||||
double rval = f.calculate(4);
|
||||
logger.info("Return value: "+rval);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test whether there is a mapping of global variable that is not declared in the entry function as parameter
|
||||
*/
|
||||
@Test
|
||||
public void testVariableMappingMissingParameterDeclaration() {
|
||||
// Add two global variables a and b.
|
||||
Map<String, JythonGlobalVariable> map = new HashMap<String, JythonGlobalVariable>();
|
||||
JythonGlobalVariable v = new JythonGlobalVariable();
|
||||
v.setName("a");
|
||||
v.setValue(1.5);
|
||||
map.put(v.getName(), v);
|
||||
v = new JythonGlobalVariable();
|
||||
v.setName("b");
|
||||
v.setValue(3.5);
|
||||
map.put(v.getName(), v);
|
||||
|
||||
String script = "import math\ndef "+JythonFunction.ENTRY_FUNCTION_NAME+"(parameter, b):\n return b.getValue()";
|
||||
JythonFunction f = new JythonFunction(script, map);
|
||||
|
||||
double rval = f.calculate(4);
|
||||
logger.info("Return value: "+rval);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,138 +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 static org.junit.Assert.*;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import ch.psi.fda.core.actors.PseudoActuatorSensor;
|
||||
|
||||
/**
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
public class PseudoActorSensorTest {
|
||||
|
||||
private final String id = "xid";
|
||||
|
||||
/**
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.PseudoActuatorSensor#PseudoActor(int)}.
|
||||
*/
|
||||
@Test
|
||||
public void testPseudoActor() {
|
||||
new PseudoActuatorSensor(id, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.PseudoActuatorSensor#PseudoActor(int)}.
|
||||
*/
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void testPseudoActorFail() {
|
||||
new PseudoActuatorSensor(id, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.PseudoActuatorSensor#set()}.
|
||||
*/
|
||||
@Test
|
||||
public void testSet() {
|
||||
PseudoActuatorSensor actor = new PseudoActuatorSensor(id, 1);
|
||||
actor.set();
|
||||
if(((Double)actor.read()).intValue()!=1){
|
||||
fail("Read value does not match set value");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.PseudoActuatorSensor#set()}.
|
||||
* Check whether IllegalStateException is thrown if set() called more than allowed
|
||||
*/
|
||||
@Test(expected=IllegalStateException.class)
|
||||
public void testSetFail() {
|
||||
PseudoActuatorSensor actor = new PseudoActuatorSensor(id, 1);
|
||||
actor.set();
|
||||
if(((Double)actor.read()).intValue()!=1){
|
||||
fail("Read value does not match set value");
|
||||
}
|
||||
actor.set();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.PseudoActuatorSensor#hasNext()}.
|
||||
*/
|
||||
@Test
|
||||
public void testHasNext() {
|
||||
PseudoActuatorSensor actor = new PseudoActuatorSensor(id, 1);
|
||||
|
||||
if(!actor.hasNext()){
|
||||
fail("Actor has no step when he should have one");
|
||||
}
|
||||
actor.set();
|
||||
if(((Double)actor.read()).intValue()!=1){
|
||||
fail("Read value does not match set value");
|
||||
}
|
||||
if(actor.hasNext()){
|
||||
fail("Actor has a step when he should not have one");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.actors.PseudoActuatorSensor#init()}.
|
||||
*/
|
||||
@Test
|
||||
public void testInit() {
|
||||
PseudoActuatorSensor actor = new PseudoActuatorSensor(id, 1);
|
||||
actor.init();
|
||||
actor.set();
|
||||
if(((Double)actor.read()).intValue()!=1){
|
||||
fail("Read value does not match set value");
|
||||
}
|
||||
if(actor.hasNext()){
|
||||
fail("Actor has a step when he should not have one");
|
||||
}
|
||||
// Initialize actor to start
|
||||
actor.init();
|
||||
actor.set();
|
||||
if(((Double)actor.read()).intValue()!=1){
|
||||
fail("Read value does not match set value");
|
||||
}
|
||||
if(actor.hasNext()){
|
||||
fail("Actor has a step when he should not have one");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,115 +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.guard;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import ch.psi.fda.TestChannels;
|
||||
import ch.psi.fda.core.Guard;
|
||||
import ch.psi.fda.core.guard.ChannelAccessGuard;
|
||||
import ch.psi.fda.core.guard.ChannelAccessGuardCondition;
|
||||
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;
|
||||
|
||||
public class ChannelAccessGuardTest {
|
||||
|
||||
private ChannelService cservice;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
cservice = new DefaultChannelService();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
cservice.destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.guard.ChannelAccessGuard#check()}.
|
||||
* @throws InterruptedException
|
||||
* @throws ChannelException
|
||||
* @throws ExecutionException
|
||||
* @throws TimeoutException
|
||||
* @throws CAException
|
||||
*/
|
||||
@Test
|
||||
public void testCheck() throws InterruptedException, ExecutionException, ChannelException, TimeoutException {
|
||||
|
||||
String guardChannel = TestChannels.ANALOG_OUT;
|
||||
Channel<Integer> channel = cservice.createChannel(new ChannelDescriptor<>(Integer.class, guardChannel));
|
||||
|
||||
|
||||
Integer channelOkValue = 10;
|
||||
List<ChannelAccessGuardCondition<?>> conditions = new ArrayList<>();
|
||||
conditions.add(new ChannelAccessGuardCondition<>(channel, channelOkValue));
|
||||
Guard guard = new ChannelAccessGuard(conditions);
|
||||
|
||||
|
||||
channel.setValue(channelOkValue);
|
||||
|
||||
guard.init();
|
||||
|
||||
if(!guard.check()){
|
||||
fail("Guard not in correct state");
|
||||
}
|
||||
|
||||
channel.setValue(channelOkValue+1);
|
||||
channel.setValue(channelOkValue);
|
||||
|
||||
Thread.sleep(1000);
|
||||
|
||||
// Check whether guard is really on NOT OK
|
||||
if(guard.check()){
|
||||
fail("Guard not in correct state");
|
||||
}
|
||||
|
||||
channel.setValue(channelOkValue);
|
||||
|
||||
// Check if after init the guard is ok again
|
||||
guard.init();
|
||||
|
||||
if(!guard.check()){
|
||||
fail("Guard not in correct state");
|
||||
}
|
||||
|
||||
// Check if after init the guard is not ok
|
||||
channel.setValue(channelOkValue+1);
|
||||
guard.init();
|
||||
|
||||
if(guard.check()){
|
||||
fail("Guard not in correct state");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,306 +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.loops;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
|
||||
import ch.psi.fda.TestChannels;
|
||||
import ch.psi.fda.core.Actor;
|
||||
import ch.psi.fda.core.Guard;
|
||||
import ch.psi.fda.core.Sensor;
|
||||
import ch.psi.fda.core.actions.Delay;
|
||||
import ch.psi.fda.core.actors.ChannelAccessLinearActuator;
|
||||
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.sensors.ChannelAccessSensor;
|
||||
import ch.psi.fda.messages.Message;
|
||||
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;
|
||||
|
||||
/**
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
public class ActorSensorLoopTest {
|
||||
|
||||
// Get Logger
|
||||
private static Logger logger = Logger.getLogger(ActorSensorLoopTest.class.getName());
|
||||
|
||||
private static final String boChannel = TestChannels.BINARY_OUT;
|
||||
private static final String aoChannel = TestChannels.ANALOG_OUT;
|
||||
private static final String wfChannel = TestChannels.DOUBLE_WAVEFORM;
|
||||
private static final Long timeout = 1800000l; // 30 minutes
|
||||
|
||||
|
||||
private ChannelService cservice;
|
||||
private ActorSensorLoop loopOne;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
cservice = new DefaultChannelService();
|
||||
|
||||
loopOne = new ActorSensorLoop();
|
||||
|
||||
ChannelAccessLinearActuator<Integer> a = new ChannelAccessLinearActuator<>(cservice.createChannel(new ChannelDescriptor<>(Double.class, aoChannel)), null, 1,0, 0, 10, 0.1, timeout); // Positioner
|
||||
Sensor s = new ChannelAccessSensor<>("id0", cservice.createChannel(new ChannelDescriptor<>(Double.class, boChannel))); // Positioner Readback
|
||||
Sensor s1 = new ChannelAccessSensor<>("id1", cservice.createChannel(new ChannelDescriptor<>(Double.class, aoChannel))); // Scalar Detector
|
||||
Sensor s1string = new ChannelAccessSensor<>("id3", cservice.createChannel(new ChannelDescriptor<>(String.class, boChannel+".NAME"))); // Scalar String Detector
|
||||
Sensor s2 = new ChannelAccessSensor<>("id2", cservice.createChannel(new ChannelDescriptor<>(double[].class, wfChannel,false, 10)));
|
||||
|
||||
loopOne.getActors().add(a);
|
||||
loopOne.getSensors().add(s);
|
||||
loopOne.getSensors().add(s1);
|
||||
loopOne.getSensors().add(s1string);
|
||||
loopOne.getSensors().add(s2);
|
||||
|
||||
loopOne.prepare();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
cservice.destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.loops.ActorSensorLoop#execute()}.
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
@Test
|
||||
public void testExecute() throws InterruptedException {
|
||||
|
||||
loopOne.getEventBus().register(new Object(){
|
||||
@Subscribe
|
||||
public void onMessage(Message m){
|
||||
logger.info( m.toString() );
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
loopOne.execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.loops.ActorSensorLoop#execute()}.
|
||||
* @throws InterruptedException
|
||||
* @throws TimeoutException
|
||||
* @throws ChannelException
|
||||
* @throws ExecutionException
|
||||
* @throws CAException
|
||||
*/
|
||||
@Test
|
||||
public void testExecuteGuard() throws InterruptedException, ChannelException, TimeoutException, ExecutionException {
|
||||
|
||||
ActorSensorLoop loop = new ActorSensorLoop();
|
||||
|
||||
ChannelAccessLinearActuator<Integer> a = new ChannelAccessLinearActuator<>(cservice.createChannel(new ChannelDescriptor<>(Double.class, aoChannel)), null, 1,0, 0, 1.5, 0.1,timeout); // Positioner
|
||||
|
||||
Sensor s = new ChannelAccessSensor<>("id0", cservice.createChannel(new ChannelDescriptor<>(Double.class, aoChannel)));
|
||||
Sensor s1 = new ChannelAccessSensor<>("id1", cservice.createChannel(new ChannelDescriptor<>(Double.class, boChannel)));
|
||||
Sensor s2 = new ChannelAccessSensor<>("id2", cservice.createChannel(new ChannelDescriptor<>(double[].class,wfChannel, false,10)));
|
||||
|
||||
loop.getActors().add(a);
|
||||
loop.getPostActorActions().add(new Delay(500));
|
||||
loop.getSensors().add(s);
|
||||
loop.getSensors().add(s1);
|
||||
loop.getSensors().add(s2);
|
||||
|
||||
// Guard
|
||||
final Integer okValue = 0;
|
||||
final Channel<Integer> b = cservice.createChannel(new ChannelDescriptor<>(Integer.class, boChannel));
|
||||
List<ChannelAccessGuardCondition<?>> conditions = new ArrayList<>();
|
||||
conditions.add(new ChannelAccessGuardCondition<Integer>(b, 0));
|
||||
Guard guard = new ChannelAccessGuard(conditions);
|
||||
loop.setGuard(guard);
|
||||
|
||||
|
||||
|
||||
Thread tguard = new Thread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
// Wait some seconds and set channel to ok
|
||||
Thread.sleep(1000);
|
||||
b.setValue(okValue);
|
||||
|
||||
// Set channel to not ok
|
||||
Thread.sleep(1000);
|
||||
b.setValue(okValue+1);
|
||||
|
||||
// Wait some seconds and set channel to ok again
|
||||
Thread.sleep(4000);
|
||||
b.setValue(okValue);
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.SEVERE, "An Exception occured while setting guard channel", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
loop.getEventBus().register(new Object(){
|
||||
@Subscribe
|
||||
public void onMessage(Message m){
|
||||
logger.info( m.toString() );
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// Set the guard channel to not OK
|
||||
b.setValue(okValue+1);
|
||||
|
||||
tguard.start();
|
||||
loop.prepare();
|
||||
loop.execute();
|
||||
|
||||
logger.info("End of test");
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testParallelSet() throws InterruptedException, ChannelException, TimeoutException {
|
||||
|
||||
final int steps = 2;
|
||||
final HashMap<String,Long> timestamps = new HashMap<String, Long>();
|
||||
|
||||
ActorSensorLoop loop = new ActorSensorLoop();
|
||||
|
||||
ChannelAccessLinearActuator<Integer> a = new ChannelAccessLinearActuator<>(cservice.createChannel(new ChannelDescriptor<>(Double.class, aoChannel)), null, 1,0, 0, (steps*0.1), 0.1, timeout); // Positioner
|
||||
|
||||
Sensor s = new ChannelAccessSensor<>("id0", cservice.createChannel(new ChannelDescriptor<>(Double.class, aoChannel)));
|
||||
|
||||
loop.getActors().add(a);
|
||||
loop.getActors().add(new Actor() {
|
||||
int c = 0;
|
||||
@Override
|
||||
public void set() {
|
||||
logger.info("Start actor 1");
|
||||
timestamps.put("sa1", System.currentTimeMillis());
|
||||
try {
|
||||
Thread.sleep(2000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
logger.info("Done actor 1");
|
||||
timestamps.put("da1", System.currentTimeMillis());
|
||||
c++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reverse() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
if(c<steps){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
loop.getActors().add(new Actor() {
|
||||
int c=0;
|
||||
@Override
|
||||
public void set() {
|
||||
logger.info("Start actor 2");
|
||||
timestamps.put("sa2", System.currentTimeMillis());
|
||||
try {
|
||||
Thread.sleep(2000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
logger.info("Done actor 2");
|
||||
timestamps.put("da2", System.currentTimeMillis());
|
||||
c++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reverse() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
if(c<steps){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
loop.getSensors().add(s);
|
||||
|
||||
|
||||
loop.prepare();
|
||||
|
||||
long begin;
|
||||
long end;
|
||||
begin = System.currentTimeMillis();
|
||||
loop.execute();
|
||||
end = System.currentTimeMillis();
|
||||
|
||||
|
||||
logger.info("Elapsed time: "+(end-begin));
|
||||
|
||||
// Check if the timestamps are in the correct order
|
||||
if(! (timestamps.get("da1")>timestamps.get("sa2")) ){
|
||||
fail("Done 1 occured before start 2");
|
||||
}
|
||||
|
||||
if(! (timestamps.get("da2")>timestamps.get("sa1")) ){
|
||||
fail("Done 2 occured before start 1");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,146 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* Copyright 2012 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;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import ch.psi.fda.TestConfiguration;
|
||||
import ch.psi.fda.core.loops.otf.DistributedFile;
|
||||
|
||||
/**
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
public class DistributedFileTest {
|
||||
|
||||
|
||||
private static final Logger logger = Logger.getLogger(DistributedFileTest.class.getName());
|
||||
|
||||
DistributedFile file;
|
||||
DistributedFile smbfile;
|
||||
|
||||
/**
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
file = new DistributedFile("src/test/resources");
|
||||
smbfile = new DistributedFile(TestConfiguration.getInstance().getSmbShare());
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.loops.otf.DistributedFile#getCanonicalPath()}.
|
||||
* @throws IOException
|
||||
*/
|
||||
@Test
|
||||
public void testGetCanonicalPath() throws IOException {
|
||||
logger.info(file.getCanonicalPath());
|
||||
logger.info(smbfile.getCanonicalPath());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.loops.otf.DistributedFile#exists()}.
|
||||
* @throws IOException
|
||||
*/
|
||||
@Test
|
||||
public void testExists() throws IOException {
|
||||
if(!file.exists()){
|
||||
fail("Indicating wrong file status (file actually exists)");
|
||||
}
|
||||
if(!smbfile.exists()){
|
||||
fail("Indicating wrong file status (file actually exists)");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.loops.otf.DistributedFile#isDirectory()}.
|
||||
* @throws IOException
|
||||
*/
|
||||
@Test
|
||||
public void testIsDirectory() throws IOException {
|
||||
if(!file.isDirectory()){
|
||||
fail("Indicating wrong file type (file is directory)");
|
||||
}
|
||||
if(!smbfile.isDirectory()){
|
||||
fail("Indicating wrong file type (file is directory)");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.loops.otf.DistributedFile#listFiles()}.
|
||||
*/
|
||||
@Test
|
||||
public void testListFiles() {
|
||||
// fail("Not yet implemented");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.loops.otf.DistributedFile#getName()}.
|
||||
*/
|
||||
@Test
|
||||
public void testGetName() {
|
||||
logger.info(file.getName());
|
||||
logger.info(smbfile.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.loops.otf.DistributedFile#isFile()}.
|
||||
* @throws IOException
|
||||
*/
|
||||
@Test
|
||||
public void testIsFile() throws IOException {
|
||||
if(file.isFile()){
|
||||
fail("Indicating wrong file type (file is directory)");
|
||||
}
|
||||
if(smbfile.isFile()){
|
||||
fail("Indicating wrong file type (file is directory)");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.loops.otf.DistributedFile#delete()}.
|
||||
*/
|
||||
@Test
|
||||
public void testDelete() {
|
||||
// fail("Not yet implemented");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.loops.otf.DistributedFile#getInputStream()}.
|
||||
*/
|
||||
@Test
|
||||
public void testGetInputStream() {
|
||||
// fail("Not yet implemented");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,229 +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.loops;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
|
||||
import ch.psi.fda.TestConfiguration;
|
||||
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.sensors.TimestampSensor;
|
||||
import ch.psi.fda.messages.ControlMessage;
|
||||
import ch.psi.fda.messages.DataMessage;
|
||||
import ch.psi.fda.messages.Message;
|
||||
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;
|
||||
|
||||
public class OTFLoopTest {
|
||||
|
||||
private static Logger logger = Logger.getLogger(OTFLoopTest.class.getName());
|
||||
|
||||
private ChannelService cservice;
|
||||
|
||||
|
||||
|
||||
private static final TestConfiguration configuration = TestConfiguration.getInstance();
|
||||
|
||||
|
||||
private OTFLoop loopZigZag;
|
||||
private OTFLoop loop;
|
||||
private Channel<Integer> statusChannel;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
cservice = new DefaultChannelService();
|
||||
statusChannel = cservice.createChannel(new ChannelDescriptor<>(Integer.class, configuration.getOtfPrefix()+":USTAT"));
|
||||
|
||||
OTFScalerChannelSensor s2 = new OTFScalerChannelSensor("id1", 0);
|
||||
OTFScalerChannelSensor s3 = new OTFScalerChannelSensor("id2", 1);
|
||||
TimestampSensor s4 = new TimestampSensor("id3");
|
||||
OTFNamedChannelSensor s5 = new OTFNamedChannelSensor("id4", configuration.getAnalogIn1());
|
||||
|
||||
Map<String, String> macros = new HashMap<>();
|
||||
macros.put("PREFIX", configuration.getOtfPrefix());
|
||||
TemplateOTF template = new TemplateOTF();
|
||||
cservice.createAnnotatedChannels(template, macros);
|
||||
|
||||
|
||||
// ZigZag loop
|
||||
loopZigZag = new OTFLoop(template, configuration.getServer(), configuration.getShare(), configuration.getSmbShare(), true);
|
||||
loopZigZag.setActuator("id0", configuration.getMotor1(), null, 0, 8, 0.5, 0.5, 0);
|
||||
loopZigZag.getSensors().add(s2);
|
||||
loopZigZag.getSensors().add(s3);
|
||||
loopZigZag.getSensors().add(s4);
|
||||
loopZigZag.getSensors().add(s5);
|
||||
|
||||
|
||||
// Normal loop
|
||||
loop = new OTFLoop(template, configuration.getServer(), configuration.getShare(), configuration.getSmbShare(), false);
|
||||
loop.setActuator("id0", configuration.getMotor1(), null, 0, 8, 0.5, 0.5, 0);
|
||||
loop.getSensors().add(s2);
|
||||
loop.getSensors().add(s3);
|
||||
loop.getSensors().add(s4);
|
||||
loop.getSensors().add(s5);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
cservice.destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.loops.otf.OTFLoop#execute()}.
|
||||
* Test ordinary 1D OTF scan
|
||||
* @throws ExecutionException
|
||||
* @throws ChannelException
|
||||
* @throws TimeoutException
|
||||
* @throws CAException
|
||||
*/
|
||||
@Test
|
||||
public void testExecute() throws InterruptedException, TimeoutException, ChannelException, ExecutionException {
|
||||
|
||||
Object l = new Object(){
|
||||
boolean first = true;
|
||||
@Subscribe
|
||||
public void onMessage(DataMessage m) {
|
||||
if(first){
|
||||
first = false;
|
||||
|
||||
int numberOfSensors = 5;
|
||||
if(m.getMetadata().size() != numberOfSensors){
|
||||
fail("Loop returned wrong number of components inside the data message metadata");
|
||||
}
|
||||
|
||||
boolean fail = false;
|
||||
for(int x=0;x<numberOfSensors; x++){
|
||||
if(! m.getMetadata().get(x).getId().equals("id"+x)){
|
||||
fail = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(fail){
|
||||
fail("Ids of the component metadata elements inside the data message metadata is not correct");
|
||||
}
|
||||
}
|
||||
logger.info(m.toString());
|
||||
}
|
||||
};
|
||||
|
||||
loop.getEventBus().register(l);
|
||||
|
||||
loop.prepare();
|
||||
loop.execute();
|
||||
loop.cleanup();
|
||||
|
||||
if(statusChannel.getValue()!=1){
|
||||
fail("OTF C Logic status is not on INACTIVE");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.loops.otf.OTFLoop#execute()}.
|
||||
* Test OTF ZigZag mode
|
||||
* @throws ExecutionException
|
||||
* @throws ChannelException
|
||||
* @throws TimeoutException
|
||||
* @throws CAException
|
||||
*/
|
||||
@Test
|
||||
public void testExecuteZigZag() throws InterruptedException, TimeoutException, ChannelException, ExecutionException {
|
||||
|
||||
loopZigZag.getEventBus().register(new TestCollector());
|
||||
|
||||
loopZigZag.prepare();
|
||||
|
||||
loopZigZag.execute();
|
||||
loopZigZag.execute();
|
||||
|
||||
loopZigZag.cleanup();
|
||||
|
||||
if(statusChannel.getValue()!=1){
|
||||
fail("OTF C Logic status is not on INACTIVE");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.loops.otf.OTFLoop#execute()}.
|
||||
* Test abort functionality while executing an OTF scan
|
||||
* @throws ExecutionException
|
||||
* @throws ChannelException
|
||||
* @throws TimeoutException
|
||||
* @throws CAException
|
||||
*/
|
||||
@Test
|
||||
public void testExecuteAbort() throws InterruptedException, TimeoutException, ChannelException, ExecutionException {
|
||||
|
||||
loop.getEventBus().register(new TestCollector());
|
||||
|
||||
// Thread to simulate asynchronous abort operation
|
||||
Thread t1 = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Thread.sleep(6000); // Wait some seconds before aborting the loop
|
||||
loop.abort();
|
||||
} catch (InterruptedException e) {
|
||||
logger.log(Level.SEVERE, "An Exception occured while testing the abort functionality", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
t1.start();
|
||||
|
||||
loop.prepare();
|
||||
|
||||
loop.execute();
|
||||
|
||||
loop.cleanup();
|
||||
|
||||
if(statusChannel.getValue()!=1){
|
||||
fail("OTF C Logic status is not on INACTIVE");
|
||||
}
|
||||
}
|
||||
|
||||
class TestCollector {
|
||||
@Subscribe
|
||||
public void onMessage(Message m) {
|
||||
if (m instanceof DataMessage) {
|
||||
DataMessage x = (DataMessage) m;
|
||||
logger.info(x.toString());
|
||||
} else if (m instanceof ControlMessage) {
|
||||
logger.info("---- " + m.toString() + " ----");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* Copyright 2012 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;
|
||||
|
||||
//import java.util.logging.Logger;
|
||||
|
||||
//import jcifs.smb.SmbFile;
|
||||
//
|
||||
//import org.junit.Ignore;
|
||||
//import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
public class SambaTest {
|
||||
|
||||
// private static final Logger logger = Logger.getLogger(SambaTest.class.getName());
|
||||
|
||||
// @Test
|
||||
// public void testSamba() throws Exception{
|
||||
//// System.setProperty("jcifs.smb.client.dfs.disabled", "true");
|
||||
//// System.setProperty("jcifs.smb.client.ssnLimit", "1");
|
||||
//
|
||||
//// System.setProperty("jcifs.smb.client.domain", "x05la.psi.ch");
|
||||
//// System.setProperty("jcifs.smb.client.username", "x05laop");
|
||||
//// System.setProperty("jcifs.smb.client.password", "mXAS");
|
||||
////
|
||||
//// System.setProperty("jcifs.util.loglevel", "6");
|
||||
//
|
||||
//// System.setProperty("jcifs.smb.lmCompatibility", "0");
|
||||
//
|
||||
//// jcifs.smb.client.{domain,username,password
|
||||
//
|
||||
// String smbShare = "";
|
||||
//// smbShare = "smb://x05laop:mXAS@x05la/x05laop/Data1/otfTmp/";
|
||||
//// smbShare = "smb://x05la.psi.ch/x05laop/Data1/otfTmp/";
|
||||
//// smbShare = "smb://x05laop:mXAS@x05la/x05laop/Data1/otfTmp/000000.txt.lock";
|
||||
// smbShare = "smb://:@yoke.psi.ch/nfs/";
|
||||
//// NtlmPasswordAuthentication auth = new NtlmPasswordAuthentication("x05laop:mXAS");
|
||||
//// SmbFile tmpDir = new SmbFile(smbShare,auth);
|
||||
//// SmbFile tmpDir = new SmbFile(smbShare);
|
||||
//
|
||||
//// tmpDir.createNewFile();
|
||||
//// logger.info(""+tmpDir.exists());
|
||||
//// logger.info(""+tmpDir.isDirectory());
|
||||
//// SmbFile tmpFile = new SmbFile(tmpDir, "000000.txt.lock");
|
||||
//// tmpFile.exists();
|
||||
// }
|
||||
}
|
||||
@@ -1,121 +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.loops.cr;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.google.common.eventbus.EventBus;
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
|
||||
import ch.psi.fda.messages.DataMessage;
|
||||
import ch.psi.fda.messages.EndOfStreamMessage;
|
||||
import ch.psi.fda.messages.Message;
|
||||
import ch.psi.fda.messages.Metadata;
|
||||
|
||||
public class ParallelCrlogicStreamMergeTest {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(ParallelCrlogicStreamMergeTest.class.getName());
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMerge() throws InterruptedException {
|
||||
|
||||
List<Metadata> dmm = new ArrayList<>();
|
||||
dmm.add(new Metadata("cractuator"));
|
||||
dmm.add(new Metadata("tstamp"));
|
||||
|
||||
BlockingQueue<Message> dataQueue = new LinkedBlockingQueue<Message>();
|
||||
DataMessage dm = new DataMessage(dmm);
|
||||
dm.getData().add(0.0035d);
|
||||
dm.getData().add(10.000000123);
|
||||
dataQueue.add(dm);
|
||||
|
||||
dm = new DataMessage(dmm);
|
||||
dm.getData().add(0.015);
|
||||
dm.getData().add(10.000000143);
|
||||
dataQueue.add(dm);
|
||||
|
||||
dm = new DataMessage(dmm);
|
||||
dm.getData().add(0.026);
|
||||
dm.getData().add(10.000000163);
|
||||
dataQueue.add(dm);
|
||||
|
||||
dataQueue.add(new EndOfStreamMessage());
|
||||
|
||||
|
||||
List<Metadata> dmm2 = new ArrayList<>();
|
||||
dmm2.add(new Metadata("milli"));
|
||||
dmm2.add(new Metadata("nano"));
|
||||
dmm2.add(new Metadata("sensor1"));
|
||||
|
||||
BlockingQueue<Message> dataQueue2 = new LinkedBlockingQueue<Message>();
|
||||
DataMessage dm2 = new DataMessage(dmm2);
|
||||
dm2.getData().add(9000d);
|
||||
dm2.getData().add(122d);
|
||||
dm2.getData().add(0.1d);
|
||||
dataQueue2.add(dm2);
|
||||
|
||||
dm2 = new DataMessage(dmm2);
|
||||
dm2.getData().add(10000d);
|
||||
dm2.getData().add(122d);
|
||||
dm2.getData().add(1d);
|
||||
dataQueue2.add(dm2);
|
||||
|
||||
dm2 = new DataMessage(dmm2);
|
||||
dm2.getData().add(10000d);
|
||||
dm2.getData().add(153d);
|
||||
dm2.getData().add(2d);
|
||||
dataQueue2.add(dm2);
|
||||
|
||||
dm2 = new DataMessage(dmm2);
|
||||
dm2.getData().add(10000d);
|
||||
dm2.getData().add(162d);
|
||||
dm2.getData().add(3d);
|
||||
dataQueue2.add(dm2);
|
||||
|
||||
dataQueue2.add(new EndOfStreamMessage());
|
||||
|
||||
EventBus b = new EventBus();
|
||||
b.register(new Object(){
|
||||
@Subscribe
|
||||
public void onMessage(Message m){
|
||||
logger.info(m.toString());
|
||||
}
|
||||
});
|
||||
ParallelCrlogicStreamMerge streamMerge = new ParallelCrlogicStreamMerge(dataQueue, dataQueue2, b);
|
||||
streamMerge.merge();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,137 +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.loops.cr;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
|
||||
import ch.psi.fda.TestConfiguration;
|
||||
import ch.psi.fda.messages.Message;
|
||||
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;
|
||||
|
||||
public class ParallelCrlogicTest {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(ParallelCrlogicTest.class.getName());
|
||||
|
||||
private ChannelService cservice;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
cservice = new DefaultChannelService();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
cservice.destroy();
|
||||
}
|
||||
|
||||
// @Ignore
|
||||
@Test(timeout=60000)
|
||||
public void testExecute() throws InterruptedException, ChannelException, TimeoutException, ExecutionException{
|
||||
|
||||
TestConfiguration c = TestConfiguration.getInstance();
|
||||
|
||||
boolean zigZag = false;
|
||||
|
||||
String readback = null;
|
||||
double start = 0;
|
||||
double end = 2;
|
||||
double stepSize = 0.01;
|
||||
double integrationTime = 0.01;
|
||||
double additionalBacklash = 0;
|
||||
|
||||
List<String> ids = new ArrayList<>();
|
||||
List<Channel<DoubleTimestamp>> sensors = new ArrayList<>();
|
||||
|
||||
ids.add("mot1");
|
||||
ids.add("mot2");
|
||||
ids.add("mot3");
|
||||
sensors.add(cservice.createChannel(new ChannelDescriptor<>(DoubleTimestamp.class, c.getMotor1()+".RVAL")));
|
||||
sensors.add(cservice.createChannel(new ChannelDescriptor<>(DoubleTimestamp.class, c.getMotor1()+".RBV")));
|
||||
sensors.add(cservice.createChannel(new ChannelDescriptor<>(DoubleTimestamp.class, "ARIDI-PCT:CURRENT")));
|
||||
|
||||
|
||||
ScrlogicLoop scrlogic = new ScrlogicLoop(ids, sensors);
|
||||
|
||||
|
||||
CrlogicLoop crlogic = new CrlogicLoop(cservice, c.getCrlogicPrefix(), c.getServer(), c.getShare(), c.getSmbShare(), zigZag);
|
||||
crlogic.setActuator("cmot", c.getMotor1(), readback, start, end, stepSize, integrationTime, additionalBacklash);
|
||||
crlogic.getSensors().add(new CrlogicResource("trigger", "TRIGGER0"));
|
||||
crlogic.getSensors().add(new CrlogicResource("scaler0", "SCALER0", true));
|
||||
crlogic.getSensors().add(new CrlogicResource("scaler1", "SCALER1", true));
|
||||
crlogic.getSensors().add(new CrlogicResource("timestamp", "TIMESTAMP"));
|
||||
|
||||
|
||||
// Initialize scaler template
|
||||
TemplateVSC16Scaler scalertemplate = new TemplateVSC16Scaler();
|
||||
Map<String,String> macros = new HashMap<>();
|
||||
macros.put("PREFIX", c.getPrefixScaler());
|
||||
cservice.createAnnotatedChannels(scalertemplate, macros);
|
||||
|
||||
|
||||
ParallelCrlogic pcrlogic = new ParallelCrlogic(crlogic, scrlogic);
|
||||
|
||||
|
||||
pcrlogic.getEventBus().register(new Object(){
|
||||
@Subscribe
|
||||
public void onMessage(Message m){
|
||||
logger.info(m.toString());
|
||||
}
|
||||
});
|
||||
|
||||
logger.info("Start scaler");
|
||||
scalertemplate.getCommand().setValueNoWait(TemplateVSC16Scaler.Command.Count.ordinal());
|
||||
|
||||
pcrlogic.prepare();
|
||||
pcrlogic.execute();
|
||||
pcrlogic.cleanup();
|
||||
|
||||
logger.info("Stop scaler");
|
||||
scalertemplate.getCommand().setValue(TemplateVSC16Scaler.Command.Done.ordinal());
|
||||
|
||||
// System.out.println("PARALLEL CRLOGIC data:");
|
||||
// BlockingQueue<Message> queue = pcrlogic.getDataQueue().getQueue();
|
||||
// Message m = queue.take();
|
||||
// while(! (m instanceof EndOfStreamMessage)){
|
||||
// System.out.println(m.toString());
|
||||
// m = queue.take();
|
||||
// }
|
||||
|
||||
// Destroy scaler template
|
||||
cservice.destroyAnnotatedChannels(scalertemplate);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,143 +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.loops.cr;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
|
||||
import ch.psi.fda.messages.Message;
|
||||
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;
|
||||
|
||||
public class ScrlogicLoopTest {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(ScrlogicLoopTest.class.getName());
|
||||
|
||||
private ChannelService cservice;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
cservice = new DefaultChannelService();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
cservice.destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.loops.cr.ScrlogicLoop#execute()}.
|
||||
* @throws InterruptedException
|
||||
* @throws TimeoutException
|
||||
* @throws ChannelException
|
||||
* @throws CAException
|
||||
*/
|
||||
@Test
|
||||
public void testExecute() throws InterruptedException, ChannelException, TimeoutException {
|
||||
List<String> ids = new ArrayList<>();
|
||||
List<Channel<DoubleTimestamp>> sensors = new ArrayList<>();
|
||||
|
||||
ids.add("mot1");
|
||||
ids.add("mot2");
|
||||
sensors.add(cservice.createChannel(new ChannelDescriptor<>(DoubleTimestamp.class, "MTEST-HW3:MOT1")));
|
||||
sensors.add(cservice.createChannel(new ChannelDescriptor<>(DoubleTimestamp.class, "MTEST-HW3:MOT1.RBV")));
|
||||
|
||||
|
||||
|
||||
final ScrlogicLoop logic = new ScrlogicLoop(ids, sensors);
|
||||
|
||||
logic.getEventBus().register(new Object(){
|
||||
@Subscribe
|
||||
public void onMessage(Message m){
|
||||
logger.info(m.toString());
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
for(int i=0;i<2;i++){
|
||||
|
||||
logic.prepare();
|
||||
|
||||
Thread tt = new Thread(new Runnable(){
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
logic.execute();
|
||||
} catch (InterruptedException e) {
|
||||
logger.log(Level.SEVERE, "", e);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
tt.start();
|
||||
|
||||
|
||||
final CountDownLatch l = new CountDownLatch(1);
|
||||
Thread t = new Thread(new Runnable(){
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try{
|
||||
System.out.println("MOVE 1");
|
||||
Channel<Double> channel = cservice.createChannel(new ChannelDescriptor<>(Double.class, "MTEST-HW3:MOT1", false));
|
||||
// Wait some time until
|
||||
Thread.sleep(100);
|
||||
channel.setValue(1.5);
|
||||
Thread.sleep(100);
|
||||
channel.setValue(2.5);
|
||||
System.out.println("MOVE D");
|
||||
// Thread.sleep(100);
|
||||
// channel.setValue(6.5);
|
||||
// Thread.sleep(100);
|
||||
|
||||
l.countDown();
|
||||
}
|
||||
catch(Exception e){
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
t.start();
|
||||
|
||||
l.await();
|
||||
|
||||
|
||||
logic.abort();
|
||||
|
||||
tt.join();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,120 +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 static org.junit.Assert.*;
|
||||
import gov.aps.jca.CAException;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import ch.psi.fda.TestChannels;
|
||||
import ch.psi.fda.core.Sensor;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Test class for the ScalarDoubleSensorChannelAccess class.
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
public class ChannelAccessSensorTest {
|
||||
|
||||
private static Logger logger = Logger.getLogger(ChannelAccessSensorTest.class.getName());
|
||||
|
||||
private ChannelService cservice;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
cservice = new DefaultChannelService();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
cservice.destroy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadDouble() throws InterruptedException, ChannelException, TimeoutException, ExecutionException {
|
||||
final String channelName = TestChannels.ANALOG_OUT;
|
||||
|
||||
Channel<Double> channel = cservice.createChannel(new ChannelDescriptor<>(Double.class, channelName));
|
||||
Sensor sensor = new ChannelAccessSensor<>("id0", channel);
|
||||
|
||||
// Prepare sensor channel
|
||||
Double setValue = 0.1d;
|
||||
channel.setValue(setValue);
|
||||
|
||||
// Get sensor readout value
|
||||
Double value = (Double) sensor.read();
|
||||
logger.finest("Sensor value: "+value);
|
||||
if(!value.equals(setValue)){
|
||||
fail("Sensor readout value does not match actual value");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadString() throws CAException, InterruptedException, ChannelException, TimeoutException {
|
||||
final String channelName = TestChannels.ANALOG_OUT+".NAME";
|
||||
final String actualValue = TestChannels.ANALOG_OUT;
|
||||
|
||||
Channel<String> channel = cservice.createChannel(new ChannelDescriptor<>(String.class, channelName));
|
||||
Sensor sensor = new ChannelAccessSensor<>("id0", channel);
|
||||
|
||||
// Get sensor readout value
|
||||
String value = (String) sensor.read();
|
||||
logger.info("Sensor value: "+value);
|
||||
if(!value.equals(actualValue)){
|
||||
fail("Sensor readout "+value+" value does not match actual value "+actualValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testReadDoubleArray() throws CAException, InterruptedException, ChannelException, TimeoutException, ExecutionException {
|
||||
|
||||
final String channelName = TestChannels.DOUBLE_WAVEFORM;
|
||||
final int numberOfPoints = 10;
|
||||
|
||||
Channel<double[]> channel = cservice.createChannel(new ChannelDescriptor<>(double[].class, channelName, false, numberOfPoints));
|
||||
Sensor sensor = new ChannelAccessSensor<>("id0", channel);
|
||||
|
||||
// Prepare sensor channel
|
||||
double[] setValue = new double[] { 0.1,0.2,0.3,4,5,6,77,88,99,10.2};
|
||||
channel.setValue(setValue);
|
||||
|
||||
// Get sensor readout value
|
||||
double[] value = (double[]) sensor.read();
|
||||
for(int i=0;i<setValue.length;i++){
|
||||
logger.finest("Sensor value["+i+"]: "+value[i]);
|
||||
if(Math.abs(value[i] - setValue[i])>0.0000001){ // The precision of the channel is 6
|
||||
fail("Sensor readout value does not match actual value");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 java.util.logging.Logger;
|
||||
|
||||
import gov.aps.jca.CAException;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import ch.psi.fda.core.sensors.TimestampSensor;
|
||||
|
||||
/**
|
||||
* Test class for MillisecondsTimestampSensor
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
public class MillisecondTimestampSensorTest {
|
||||
|
||||
// Get Logger
|
||||
private static Logger logger = Logger.getLogger(MillisecondTimestampSensorTest.class.getName());
|
||||
|
||||
/**
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.sensors.ChannelAccessDoubleSensor#read()}.
|
||||
* @throws CAException
|
||||
*/
|
||||
@Test
|
||||
public void testRead() throws CAException {
|
||||
TimestampSensor sensor = new TimestampSensor("id0");
|
||||
|
||||
// Get sensor readout value
|
||||
Double value = (Double) sensor.read();
|
||||
logger.finest("Sensor value: "+value);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,115 +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.model;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.xml.bind.JAXBException;
|
||||
import javax.xml.bind.MarshalException;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import ch.psi.fda.model.ModelManager;
|
||||
import ch.psi.fda.model.v1.Configuration;
|
||||
import ch.psi.fda.model.v1.LinePlot;
|
||||
import ch.psi.fda.model.v1.Scan;
|
||||
|
||||
/**
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
public class ModelManagerTest {
|
||||
|
||||
private static final String tmpDirectory = "target/tmp";
|
||||
|
||||
// Get Logger
|
||||
private static Logger logger = Logger.getLogger(ModelManagerTest.class.getName());
|
||||
|
||||
/**
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
new File(tmpDirectory).mkdirs(); // Create temp directory
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.model.ModelManager#unmarshall(java.io.File)}.
|
||||
* @throws SAXException
|
||||
* @throws JAXBException
|
||||
* @throws URISyntaxException
|
||||
*/
|
||||
@Test
|
||||
public void testUnmarshall() throws JAXBException, SAXException, URISyntaxException {
|
||||
URL url = this.getClass().getClassLoader().getResource("home/scans/templates/scan1d.xml");
|
||||
Configuration c = ModelManager.unmarshall(new File(new URI(url.toString())));
|
||||
logger.info(""+c.getData().getFormat());
|
||||
|
||||
logger.info("FILENAME: "+c.getData().getFileName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.model.ModelManager#marshall(ch.psi.fda.model.v1.Configuration, java.io.File)}.
|
||||
* @throws SAXException
|
||||
* @throws JAXBException
|
||||
*/
|
||||
@Test(expected=MarshalException.class)
|
||||
public void testMarshallFail() throws JAXBException, SAXException {
|
||||
|
||||
Configuration c = new Configuration();
|
||||
c.setDescription("My Description");
|
||||
Scan s = new Scan();
|
||||
c.setScan(s);
|
||||
|
||||
// Add component that is not match to xsd
|
||||
LinePlot v = new LinePlot();
|
||||
c.getVisualization().add(v);
|
||||
|
||||
ModelManager.marshall(c, new File(tmpDirectory+"/scan.xml"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMarshall() throws JAXBException, SAXException {
|
||||
|
||||
Configuration c = new Configuration();
|
||||
c.setDescription("My Description");
|
||||
Scan s = new Scan();
|
||||
c.setScan(s);
|
||||
|
||||
ModelManager.marshall(c, new File(tmpDirectory+"/scan1234.xml"));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user