61 Commits

Author SHA1 Message Date
166e8d325a increased xscan version 2015-08-19 09:51:40 +02:00
03ac83adf6 cleanup properties and compiler warnings 2015-08-18 11:44:57 +02:00
edf3672317 updated build number and removed pom 2015-08-18 11:27:49 +02:00
10f0fcdde2 moved files to top level 2015-08-14 13:26:17 +02:00
19d2b28f25 removed eclipse specific settings 2015-08-14 13:21:34 +02:00
ac04a730a3 fixed javadoc problems and migrated to gradle 2015-08-14 13:20:48 +02:00
87ed988dfe updated zmq 2015-08-13 14:44:02 +02:00
fb21986493 updated version 2015-08-13 14:36:50 +02:00
1601fbcbfd origin crlogic 2015-05-11 13:36:17 +02:00
c25a80ddfb new version 2014-10-10 13:54:34 +02:00
ba630a44e1 new version 2014-10-10 11:07:34 +02:00
5316773104 Added title font property to plots. 2014-09-09 09:18:29 +02:00
38b60f3f5e Added title font property to plots. 2014-09-09 09:17:58 +02:00
31d37c7c45 Fixed bug in chained manipulations 2014-09-04 09:16:31 +02:00
366a7f2a74 Added visualization to Fdaq 2014-08-29 16:51:59 +02:00
e5cc3126ab Added visualization to Fdaq 2014-08-29 16:28:06 +02:00
45505b511d Added item count to LinePlotSeries & Subsampling to visualizer 2014-08-29 16:15:50 +02:00
e21b3d64ee Several bug fixes and small improvements 2014-08-28 14:25:18 +02:00
1a294a1a75 Fixed bugs on MatrixPlotArray 7 LinePlotArray 2014-08-22 09:26:16 +02:00
fb5b2ff257 Upgraded xscan code 2014-08-19 13:16:01 +02:00
8d9fba4be6 updated pom to require source level 1.8 2014-08-13 08:15:45 +02:00
065ed130a6 Adapting to plot v2: Abstraction of graphs & new implementations: JZY3D, JavaFX, JFreeChart 2014-08-12 16:41:58 +02:00
074ac2caff Update version in release notes 2014-08-07 14:38:35 +02:00
f2e3bf23e8 Added an release notes file 2014-08-07 14:28:07 +02:00
f39822ec74 updated referenced library 2014-07-28 16:29:25 +02:00
5038912472 updated pom deploy url 2014-07-28 12:38:34 +02:00
8ab87b8332 Updated version ... 2014-07-28 11:13:23 +02:00
8f698e82ba upgraded xscan version 2014-05-12 11:40:15 +02:00
58e92684ad Updated version 2014-05-12 11:17:19 +02:00
5a6396cfb7 Added initial administration web page. 2014-05-09 09:29:41 +02:00
57ecb121b2 improved return values ... 2014-05-06 16:14:21 +02:00
3ce7282214 Improved logging 2014-05-06 13:50:50 +02:00
16d18288b6 improved termination of the execution container 2014-05-06 13:15:51 +02:00
76ce595f87 removed author comment 2014-04-30 07:51:53 +02:00
486d11db2b Finished cleanup 2014-04-30 07:45:16 +02:00
fa2416492e Refactored test packages 2014-04-30 07:34:31 +02:00
db097eba8f added new startup script 2014-04-30 07:29:33 +02:00
838f6fd385 moved classes to ui package 2014-04-30 07:28:14 +02:00
1c9eca2a1c handle end of stream correctly 2014-04-30 07:27:43 +02:00
f30aa6495f refactored classes 2014-04-30 07:17:06 +02:00
a15356190d moved classes 2014-04-30 07:07:33 +02:00
88f4dd2b19 cleaned up configuraiton management and startup scripts 2014-04-30 07:00:25 +02:00
9f4c6c0356 re-organized some stuff ... 2014-04-29 11:44:10 +02:00
84fb119932 cleaned up cleanup procedure 2014-04-29 11:26:22 +02:00
311eae3cbc changes ... 2014-04-29 11:06:21 +02:00
9529d7f088 Renamed classes to better represent what they are doing 2014-04-29 10:34:26 +02:00
e597b5cd12 stuff 2014-04-28 16:06:10 +02:00
8ab6f7965b moved to correct package 2014-04-28 13:57:40 +02:00
4bb984cc1c Removed lots of stuff from the project 2014-04-28 13:56:52 +02:00
b64f31e778 some more cleanups and fixes
-- however still lots of bugs in there !
2014-04-28 11:46:36 +02:00
43a8347924 added gitignore file 2014-04-25 12:44:22 +02:00
f520ff4337 removed xmlscan based classes and imported ch.psi.fda.xscan library
instead
2014-04-25 12:39:49 +02:00
5995b2ed5c use of edescriptor also for the server/client setup of FDA 2014-04-22 08:43:14 +02:00
e20cab4874 Fixed viewer 2014-04-16 08:43:58 +02:00
576d7eb048 Refactored visualizer to support vdescriptor 2014-04-16 08:34:24 +02:00
21f86d7d69 Updated provider to also generate a vdescriptor 2014-04-14 13:14:45 +02:00
aa1681aaf3 Cleaned messed up stuff 2014-04-11 16:15:38 +02:00
da182adcd2 updated edescriptor thingi 2014-04-11 15:47:09 +02:00
8d1bd4e816 moved certain rest related classes 2014-04-10 15:23:15 +02:00
07d6b47885 added injection and fixed shutdown problems 2014-04-10 15:19:39 +02:00
87781b8f06 Added new abstraction layer 2014-04-10 14:11:40 +02:00
282 changed files with 11002 additions and 26323 deletions

7
.gitignore vendored Normal file
View File

@@ -0,0 +1,7 @@
/bin
/target
/build
.gradle
.settings
.project
.classpath

63
build.gradle Normal file
View File

@@ -0,0 +1,63 @@
apply plugin: 'java'
apply plugin: 'eclipse'
sourceCompatibility = 1.7
version = '2.6.2'
repositories {
mavenCentral()
maven { url "http://artifacts.psi.ch/artifactory/libs-releases" }
maven { url "http://artifacts.psi.ch/artifactory/libs-snapshots" }
}
dependencies {
compile 'ch.psi:ch.psi.fda.core:2.3.4'
compile 'ch.psi.fda:ch.psi.fda.xscan:2.6.2'
compile 'ch.psi:ch.psi.fda.cdump:2.3.4'
compile 'ch.psi:ch.psi.fda.fdaq:2.3.4'
compile 'ch.psi:jcae:2.4.1'
compile 'com.google.inject:guice:3.0'
compile 'org.glassfish.jersey.containers:jersey-container-grizzly2-http:2.5.1'
compile 'org.glassfish.jersey.media:jersey-media-sse:2.5.1'
compile 'org.glassfish.jersey.media:jersey-media-json-jackson:2.5.1'
compile 'org.zeromq:jeromq:0.3.5'
compile 'org.apache.commons:cli:1.2'
// For reading/writing Matlab files
compile 'com.jmatio:jmatio:0.2u2psi1'
// Library for reading/writing XDR Format (MDA)
compile 'org.freehep:freehep-xdr:2.0.4'
compile 'ch.psi:plot:2.1-SNAPSHOT'
testCompile 'junit:junit:4.+'
}
task sourcesJar(type: Jar, dependsOn: classes) {
classifier = 'sources'
from sourceSets.main.allSource
}
task javadocJar(type: Jar, dependsOn: javadoc) {
classifier = 'javadoc'
from javadoc.destinationDir
}
artifacts {
archives sourcesJar
archives javadocJar
}
apply plugin: 'maven'
uploadArchives {
repositories {
mavenDeployer {
repository(url: "http://artifacts.psi.ch/artifactory/libs-releases-local"){
authentication(userName: "upload", password: "{DESede}eWKHxAtQ2Dc=")
}
pom.groupId = 'ch.psi'
pom.artifactId = 'fda'
}
}
}

View File

@@ -1,37 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="target/classes" path="src/main/java">
<attributes>
<attribute name="optional" value="true"/>
<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"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
</classpath>

View File

@@ -1 +0,0 @@
/target

View File

@@ -1,23 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>ch.psi.fda</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.m2e.core.maven2Nature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View File

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

View File

@@ -1,5 +0,0 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
org.eclipse.jdt.core.compiler.compliance=1.7
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.source=1.7

View File

@@ -1,5 +0,0 @@
#Tue Oct 18 15:52:42 CEST 2011
activeProfiles=
eclipse.preferences.version=1
resolveWorkspaceProjects=true
version=1

View File

@@ -1,257 +0,0 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>ch.psi</groupId>
<artifactId>fda</artifactId>
<version>2.1.1</version>
<dependencies>
<dependency>
<groupId>ch.psi</groupId>
<artifactId>ch.psi.fda.core</artifactId>
<version>0.0.1-SNAPSHOT</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>
<version>1.0.5</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-grizzly2-http</artifactId>
<version>2.5.1</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-sse</artifactId>
<version>2.5.1</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<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>
<version>1.2</version>
</dependency>
<!-- Library to Read Matlab Files -->
<dependency>
<groupId>com.jmatio</groupId>
<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>
<artifactId>freehep-xdr</artifactId>
<version>2.0.4</version>
</dependency>
<!-- JUnit test library -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<encoding>UTF-8</encoding>
<source>1.7</source>
<target>1.7</target>
</configuration>
</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>
<version>2.1.2</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</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>
<snapshotRepository>
<id>i.snapshots</id>
<name>Artifactory Snapshots</name>
<url>http://yoke/artifactory/libs-snapshots-local</url>
</snapshotRepository>
<repository>
<id>i.releases</id>
<name>Atrifactory Releases</name>
<url>http://yoke/artifactory/libs-releases-local</url>
</repository>
</distributionManagement>
</project>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,251 +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.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Properties;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class AcquisitionConfiguration {
private static final Logger logger = Logger.getLogger(AcquisitionConfiguration.class.getName());
public final static String FDA_CONFIG_FILE = "ch.psi.fda.config.file";
private String otfChannelPrefix;
private String otfNfsServer;
private String otfNfsShare;
private String otfSmbShare;
private String otfScalerPrefix;
private boolean otfUseCrlogic;
private String otfCrlogicPrefix;
private boolean otfCrlogicKeepTmpFiles;
/**
* Base directory for data. The directory may contain date macros. The string may contain any @see java.text.SimpleDateFormat
* patterns within ${ } brackets. The macros are resolved with the actual time while the get method
* of this property is called.
*/
private String dataBaseDirectory = System.getProperty("user.home");
/**
* Prefix of the data file. The prefix may contain date macros. The string may contain any @see java.text.SimpleDateFormat
* patterns within ${ } brackets. The macros are resolved with the actual time while the get method
* of this property is called.
*/
private String dataFilePrefix = "";
/**
* Maximum time for a actor move
*/
private Long actorMoveTimeout = 600000l; // 10 Minutes maximum move time
private String smptServer;
/**
* Default Constructor
* The constructor will read the configuration from the /fda.properties file (resource) located in the classpath.
*/
public AcquisitionConfiguration(){
loadConfiguration(System.getProperty(FDA_CONFIG_FILE));
}
/**
* Load configuration from properties file
*/
public void loadConfiguration(String file) {
Properties properties = new Properties();
File cfile = null;
// Only read in the property file if a file is specified
if(file != null){
cfile = new File(file);
try {
properties.load(new FileReader(cfile));
} catch (FileNotFoundException e) {
throw new RuntimeException("Configuration file "+file+" not found", e);
} catch (IOException e) {
throw new RuntimeException("Cannot read configuration file "+file, e);
}
}
else{
logger.warning("No configfile specified !");
}
// The defaults are set here
otfChannelPrefix = properties.getProperty(AcquisitionConfiguration.class.getPackage().getName()+".otf.channelPrefix", "");
otfScalerPrefix = properties.getProperty(AcquisitionConfiguration.class.getPackage().getName()+".otf.scalerPrefix", "");
otfNfsServer = properties.getProperty(AcquisitionConfiguration.class.getPackage().getName()+".otf.nfsServer", "");
otfNfsShare = properties.getProperty(AcquisitionConfiguration.class.getPackage().getName()+".otf.nfsShare", "");
otfSmbShare = properties.getProperty(AcquisitionConfiguration.class.getPackage().getName()+".otf.smbShare", "");
otfUseCrlogic = new Boolean(properties.getProperty(AcquisitionConfiguration.class.getPackage().getName()+".otf.useCrlogic", "false"));
otfCrlogicPrefix = properties.getProperty(AcquisitionConfiguration.class.getPackage().getName()+".otf.crlogicPrefix", "");
otfCrlogicKeepTmpFiles = new Boolean(properties.getProperty(AcquisitionConfiguration.class.getPackage().getName()+".otf.crlogicKeepTmpFiles", "false"));
dataBaseDirectory = properties.getProperty(AcquisitionConfiguration.class.getPackage().getName()+".data.dir",".");
if(cfile!=null && dataBaseDirectory.matches("^\\.\\.?/.*")){ // if basedir starts with . or .. we assume the data directory to be relative to the directory of the configuration file
dataBaseDirectory = cfile.getParentFile().getAbsolutePath()+"/"+dataBaseDirectory;
}
dataFilePrefix = properties.getProperty(AcquisitionConfiguration.class.getPackage().getName()+".data.filePrefix","");
actorMoveTimeout = new Long(properties.getProperty(AcquisitionConfiguration.class.getPackage().getName()+".actorMoveTimeout","600000"));
smptServer= properties.getProperty(AcquisitionConfiguration.class.getPackage().getName()+".notification.host","mail.psi.ch");
}
/**
* Replace ${name} and ${date} macro given string
* @param string
* @param date
* @param name
* @return
*/
public String replaceMacros(String string, Date date, String name){
String newString = string;
// Replace scan name macros
newString = newString.replaceAll("\\$\\{name\\}", name);
// Replace date macros
Pattern pattern = Pattern.compile("\\$\\{[a-z,A-Z,-,_,:]*\\}");
Matcher matcher = pattern.matcher(newString);
while(matcher.find()){
String datePattern = matcher.group();
datePattern = datePattern.replaceAll("\\$\\{", "");
datePattern = datePattern.replaceAll("\\}", "");
SimpleDateFormat datef = new SimpleDateFormat(datePattern);
newString = matcher.replaceFirst(datef.format(date));
matcher = pattern.matcher(newString);
}
return newString;
}
// Getter and setter functions
public String getOtfChannelPrefix() {
return otfChannelPrefix;
}
public void setOtfChannelPrefix(String otfChannelPrefix) {
this.otfChannelPrefix = otfChannelPrefix;
}
public String getOtfNfsServer() {
return otfNfsServer;
}
public void setOtfNfsServer(String otfNfsServer) {
this.otfNfsServer = otfNfsServer;
}
public String getOtfNfsShare() {
return otfNfsShare;
}
public void setOtfNfsShare(String otfNfsShare) {
this.otfNfsShare = otfNfsShare;
}
public String getOtfSmbShare() {
return otfSmbShare;
}
public void setOtfSmbShare(String otfSmbShare) {
this.otfSmbShare = otfSmbShare;
}
public String getOtfScalerPrefix() {
return otfScalerPrefix;
}
public void setOtfScalerPrefix(String otfScalerPrefix) {
this.otfScalerPrefix = otfScalerPrefix;
}
public boolean isOtfUseCrlogic() {
return otfUseCrlogic;
}
public void setOtfUseCrlogic(boolean otfUseCrlogic) {
this.otfUseCrlogic = otfUseCrlogic;
}
public String getOtfCrlogicPrefix() {
return otfCrlogicPrefix;
}
public void setOtfCrlogicPrefix(String otfCrlogicPrefix) {
this.otfCrlogicPrefix = otfCrlogicPrefix;
}
public boolean isOtfCrlogicKeepTmpFiles() {
return otfCrlogicKeepTmpFiles;
}
public void setOtfCrlogicKeepTmpFiles(boolean otfCrlogicKeepTmpFiles) {
this.otfCrlogicKeepTmpFiles = otfCrlogicKeepTmpFiles;
}
public String getDataBaseDirectory() {
return dataBaseDirectory;
}
public void setDataBaseDirectory(String dataBaseDirectory) {
this.dataBaseDirectory = dataBaseDirectory;
}
public String getDataFilePrefix() {
return dataFilePrefix;
}
public void setDataFilePrefix(String dataFilePrefix) {
this.dataFilePrefix = dataFilePrefix;
}
public Long getActorMoveTimeout() {
return actorMoveTimeout;
}
public void setActorMoveTimeout(Long actorMoveTimeout) {
this.actorMoveTimeout = actorMoveTimeout;
}
public String getSmptServer() {
return smptServer;
}
public void setSmptServer(String smptServer) {
this.smptServer = smptServer;
}
}

View File

@@ -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;
}
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

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

View File

@@ -1,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();
}

View File

@@ -1,66 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core;
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();
}

View File

@@ -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();
}

View File

@@ -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;
}
}

View File

@@ -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();
}

View File

@@ -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);
}

View File

@@ -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();
}

View File

@@ -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();
}
}
}

View File

@@ -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() {
}
}

View File

@@ -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() {
}
}

View File

@@ -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() {
}
}

View File

@@ -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;
}
}

View File

@@ -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&lt;end = 1, start&gt;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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}

View File

@@ -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);
}
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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();
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}
}

View 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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -1,80 +0,0 @@
/**
*
* Copyright 2014 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* This code is distributed in the hope that it will be useful, but without any
* warranty; without even the implied warranty of merchantability or fitness for
* a particular purpose. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.rest;
import java.util.logging.Logger;
import ch.psi.fda.aq.Acquisition;
import ch.psi.fda.aq.AcquisitionConfiguration;
import ch.psi.fda.model.v1.Configuration;
import ch.psi.jcae.ChannelService;
import com.google.common.eventbus.EventBus;
public class AcquisitionJob implements Runnable {
private static final Logger logger = Logger.getLogger(AcquisitionJob.class.getName());
private final AcquisitionConfiguration config;
private final ChannelService cService;
private final ZMQDataService zmqService;
private final String trackingId;
private final Configuration configuration;
public AcquisitionJob(ChannelService cService, ZMQDataService zmqService, AcquisitionConfiguration config, String trackingId, Configuration configuration) {
this.zmqService = zmqService;
this.cService = cService;
this.config = config;
this.trackingId = trackingId;
this.configuration = configuration;
}
@Override
public void run() {
Acquisition acquisition = null;
try {
logger.info("Execute - " + trackingId);
EventBus ebus = new EventBus();
zmqService.setTrackingId(trackingId);
ebus.register(zmqService);
// Post visualization configuration
ebus.post(configuration.getVisualization());
acquisition = new Acquisition(cService, config);
acquisition.initalize(ebus, configuration);
acquisition.execute();
logger.info("" + trackingId + " done");
// Cleanup
ebus.unregister(zmqService);
} catch (InterruptedException e) {
logger.info("Execution of "+trackingId+ " was interrupted");
} finally {
if(acquisition!=null){
acquisition.destroy();
}
}
}
}

View File

@@ -1,99 +0,0 @@
/**
*
* Copyright 2014 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* This code is distributed in the hope that it will be useful, but without any
* warranty; without even the implied warranty of merchantability or fitness for
* a particular purpose. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.rest;
import java.io.File;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.inject.Inject;
import ch.psi.fda.cdump.Cdump;
import ch.psi.fda.cdump.CdumpConfiguration;
import ch.psi.fda.rest.model.CdumpRequest;
import ch.psi.fda.serializer.SerializerTXT;
import ch.psi.jcae.ChannelService;
import com.google.common.eventbus.AsyncEventBus;
import com.google.common.eventbus.EventBus;
public class CdumpEngine {
private Cdump cdump;
private EventBus bus;
private ZMQDataService zmqService;
private ChannelService cservice;
private CdumpConfiguration configuration;
private boolean stream = false;
private ExecutorService eservice;
@Inject
public CdumpEngine(ChannelService cservice, ZMQDataService zmqService, CdumpConfiguration configuration){
this.cservice = cservice;
this.zmqService = zmqService;
this.configuration = configuration;
eservice = Executors.newSingleThreadExecutor();
}
public void acquire(String trackingId, final CdumpRequest request){
if(cdump!=null){
throw new IllegalStateException("Cdump is already running");
}
bus = new AsyncEventBus(Executors.newSingleThreadExecutor());
cdump = new Cdump(cservice,bus,configuration);
SerializerTXT serializer = new SerializerTXT(new File(request.getFilename()));
serializer.setShowDimensionHeader(false);
bus.register(serializer);
stream = (request.getStream()!=null && request.getStream().getIds().length>0) ;
if(stream){
// Stream data via ZMQ
zmqService.setTrackingId(trackingId);
// TODO set id filter !!!
bus.register(zmqService);
}
eservice.execute(new Runnable() {
@Override
public void run() {
cdump.acquire(request.getSamplingRate());
}
});
}
public void stop(){
cdump.stop();
cdump = null;
bus.unregister(zmqService);
}
public boolean isActive(){
return cdump!=null;
}
}

View 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;
}
}

View File

@@ -1,90 +0,0 @@
/**
*
* Copyright 2014 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* This code is distributed in the hope that it will be useful, but without any
* warranty; without even the implied warranty of merchantability or fitness for
* a particular purpose. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.rest;
import java.io.File;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.inject.Inject;
import ch.psi.fda.fdaq.FdaqConfiguration;
import ch.psi.fda.fdaq.FdaqService;
import ch.psi.fda.rest.model.FdaqRequest;
import ch.psi.fda.serializer.SerializerTXT;
import com.google.common.eventbus.AsyncEventBus;
import com.google.common.eventbus.EventBus;
/**
*
*/
public class FdaqEngine {
private FdaqService fdaq;
private EventBus bus;
private ZMQDataService zmqService;
private boolean stream = false;
private ExecutorService eservice;
@Inject
public FdaqEngine(ZMQDataService zmqService){
this.zmqService = zmqService;
eservice = Executors.newSingleThreadExecutor();
}
public void acquire(String trackingId, FdaqRequest request){
if(fdaq!=null && fdaq.isRunning()){
throw new IllegalStateException("FDAQ is already running");
}
bus = new AsyncEventBus(Executors.newSingleThreadExecutor());
fdaq = new FdaqService(bus, new FdaqConfiguration());
SerializerTXT serializer = new SerializerTXT(new File(request.getFilename()));
serializer.setShowDimensionHeader(false);
bus.register(serializer);
stream = (request.getStream()!=null && request.getStream().getIds().length>0) ;
if(stream){
// Stream data via ZMQ
zmqService.setTrackingId(trackingId);
// TODO Set id filter !!!!
bus.register(zmqService);
}
eservice.execute(new Runnable() {
@Override
public void run() {
fdaq.acquire();
}
});
}
public void stop(){
fdaq.stop();
bus.unregister(zmqService);
// TODO check whether serializer also needs to be unregistered ...
}
}

View File

@@ -1,30 +0,0 @@
package ch.psi.fda.rest;
import javax.inject.Singleton;
import org.glassfish.hk2.utilities.binding.AbstractBinder;
import ch.psi.fda.aq.AcquisitionConfiguration;
import ch.psi.fda.cdump.CdumpConfiguration;
import ch.psi.jcae.ChannelService;
import ch.psi.jcae.impl.DefaultChannelService;
public class ResourceBinder extends AbstractBinder {
@Override
protected void configure() {
bind(DefaultChannelService.class).to(ChannelService.class).in(Singleton.class);
bind(AcquisitionConfiguration.class).to(AcquisitionConfiguration.class).in(Singleton.class);
bind(AcquisitionEngine.class).to(AcquisitionEngine.class).in(Singleton.class);
bind(FdaqEngine.class).to(FdaqEngine.class).in(Singleton.class);
// ZMQ data service singleton
bind(new ZMQDataService(10000)).to(ZMQDataService.class);
bind(CdumpEngine.class).to(CdumpEngine.class).in(Singleton.class);
bind(CdumpConfiguration.class).to(CdumpConfiguration.class).in(Singleton.class);
}
}

View File

@@ -1,48 +0,0 @@
/**
*
* Copyright 2014 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.model;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class CdumpRequest {
private String filename;
private Stream stream;
private String samplingRate;
public String getFilename() {
return filename;
}
public void setFilename(String filename) {
this.filename = filename;
}
public Stream getStream() {
return stream;
}
public void setStream(Stream stream) {
this.stream = stream;
}
public String getSamplingRate() {
return samplingRate;
}
public void setSamplingRate(String samplingRate) {
this.samplingRate = samplingRate;
}
}

View File

@@ -1,74 +0,0 @@
/**
*
* Copyright 2014 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.model;
import javax.xml.bind.annotation.XmlRootElement;
import org.codehaus.jackson.map.annotate.JsonDeserialize;
/**
* Execution request
*/
@XmlRootElement
@JsonDeserialize(using = ERequestJsonDeserializer.class)
public class ERequest {
/**
* List of ids to stream
*/
private Stream stream;
/**
* Execution type: scan, fdaq, cdump
*/
private String etype;
/**
* Json string holding the executions' configuration. It will interpreted differently based on the specified etype
*
* Use adapter ???? https://www.google.ch/url?sa=t&rct=j&q=&esrc=s&source=web&cd=6&cad=rja&ved=0CFgQFjAF&url=http%3A%2F%2Fblog.bdoughan.com%2F2012%2F01%2Fjaxb-and-inhertiance-using-xmladapter.html&ei=GfrMUtzTNsGp7AbykYDQDw&usg=AFQjCNG3xDZKYLYV6Ez-EvvJe_AIYE5EHA&sig2=ND5Epp90O-FWrJI4T3zyCw&bvm=bv.58187178,d.ZGU
*/
private String configuration;
public Stream getStream() {
return stream;
}
public void setStream(Stream stream) {
this.stream = stream;
}
public String getEtype() {
return etype;
}
public void setEtype(String etype) {
this.etype = etype;
}
public String getConfiguration() {
return configuration;
}
public void setConfiguration(String configuration) {
this.configuration = configuration;
}
}

View File

@@ -1,30 +0,0 @@
package ch.psi.fda.rest.model;
import java.io.IOException;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.JsonProcessingException;
import org.codehaus.jackson.map.DeserializationContext;
import org.codehaus.jackson.map.JsonDeserializer;
class ERequestJsonDeserializer extends JsonDeserializer<ERequest> {
@Override
public ERequest deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
ERequest request = new ERequest();
JsonNode node = jp.readValueAsTree();
request.setEtype(node.get("etype").asText());
request.setStream(jp.getCodec().treeToValue(node.get("stream"), Stream.class));
request.setConfiguration(node.get("configuration").toString());
// Class<? extends ERe> concreteType = determineConcreteType(node); //Implement
// return jp.getCodec().treeToValue(node, concreteType);
//
// return jp.readValueAsTree().toString();
return request;
}
}

View File

@@ -1,40 +0,0 @@
/**
*
* Copyright 2014 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.model;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class FdaqRequest {
private String filename;
private Stream stream;
public String getFilename() {
return filename;
}
public void setFilename(String filename) {
this.filename = filename;
}
public Stream getStream() {
return stream;
}
public void setStream(Stream stream) {
this.stream = stream;
}
}

View File

@@ -1,31 +0,0 @@
/**
*
* Copyright 2014 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.model;
public class Stream {
private String[] ids;
public String[] getIds() {
return ids;
}
public void setIds(String[] ids) {
this.ids = ids;
}
}

View File

@@ -1,63 +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.services;
import javax.inject.Inject;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.core.MediaType;
import ch.psi.fda.rest.CdumpEngine;
import ch.psi.fda.rest.model.CdumpRequest;
@Path("cdump")
public class CDUMPService {
@Inject
private CdumpEngine cdumpE;
@PUT
@Path("{trackingId}")
@Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public void execute(@PathParam("trackingId") String trackingId, CdumpRequest request) throws InterruptedException{
cdumpE.acquire(trackingId, request);
}
@DELETE
@Path("{trackingId}")
public void stop(@PathParam("trackingId") String trackingId){
terminateAll();
}
@DELETE
public void terminateAll(){
cdumpE.stop();
}
@GET
public boolean isActive(){
return cdumpE.isActive();
}
}

View File

@@ -1,58 +0,0 @@
/**
*
* Copyright 2013 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* This code is distributed in the hope that it will be useful, but without any
* warranty; without even the implied warranty of merchantability or fitness for
* a particular purpose. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.rest.services;
import javax.inject.Inject;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.core.MediaType;
import ch.psi.fda.fdaq.FdaqService;
import ch.psi.fda.rest.model.FdaqRequest;
@Path("fdaq")
public class FDAQService {
@Inject
private FdaqService fdaq;
@PUT
@Path("{trackingId}")
@Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public void execute(@PathParam("trackingId") String trackingId, FdaqRequest request) throws InterruptedException {
fdaq.acquire();
}
@DELETE
@Path("{trackingId}")
public void stop(@PathParam("trackingId") String trackingId) {
terminateAll();
}
@DELETE
public void terminateAll(){
fdaq.stop();
}
}

View File

@@ -1,281 +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.visualizer;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import com.google.common.eventbus.Subscribe;
import ch.psi.fda.messages.DataMessage;
import ch.psi.fda.messages.EndOfStreamMessage;
import ch.psi.fda.messages.StreamDelimiterMessage;
import ch.psi.plot.Plot;
import ch.psi.plot.xy.LinePlot;
import ch.psi.plot.xy.XYSeriesCollectionP;
import ch.psi.plot.xy.XYSeriesP;
import ch.psi.plot.xyz.MatrixPlot;
import ch.psi.plot.xyz.MatrixPlotData;
/**
* Visualizer for visualizing data
*/
public class Visualizer {
private static Logger logger = Logger.getLogger(Visualizer.class.getName());
private boolean updateAtStreamElement = true;
private boolean updateAtStreamDelimiter = true;
private boolean updateAtEndOfStream = false;
private int ecount;
private boolean clearPlot;
private List<SeriesDataFilter> filters;
private boolean first = true;
public Visualizer(List<SeriesDataFilter> filters){
this.filters = filters;
}
@Subscribe
public void onDataMessage(final DataMessage message){
if(first){
first=false;
// filters = VisMapper.mapVisualizations(visualizations);
// TODO somehow handle dimension / clear
}
// Clear is here as the plot should not be cleared after the last point is plotted
// but just before the first point of the next plot (cycle)
if (clearPlot) {
for (SeriesDataFilter f: filters) {
Plot plot = f.getPlot();
if(plot instanceof MatrixPlot){
((MatrixPlotData) ((MatrixPlot)plot).getData()).clear();
}
}
clearPlot = false;
}
for(SeriesDataFilter filter: filters){
if(filter instanceof XYSeriesDataFilter){
XYSeriesDataFilter xyfilter = (XYSeriesDataFilter) filter;
if(xyfilter.getActualSeries()==null || xyfilter.isNewseries()){
// First series that is filled by this filter!
XYSeriesP s = new XYSeriesP(xyfilter.getSeriesName() + " " + ecount + "-" + xyfilter.getCount());
((LinePlot)xyfilter.getPlot()).getData().addSeries(s);
xyfilter.setActualSeries(s);
xyfilter.setNewseries(false);
}
XYSeriesP series = xyfilter.getActualSeries(); // TODO Does not work with multiple series filter per plot !!!!
// There might be other values than double in the data, therefore we have to check for it
Object dX = message.getData(xyfilter.getIdX());
Object dY = message.getData(xyfilter.getIdY());
Double dataX = Double.NaN;
Double dataY = Double.NaN;
if(dX instanceof Double){
dataX = (Double) dX;
}
if(dY instanceof Double){
dataY = (Double) dY;
}
// Add Data to the series
series.add(dataX , dataY, updateAtStreamElement);
}
if(filter instanceof XYSeriesArrayDataFilter){
final XYSeriesArrayDataFilter xyfilter = (XYSeriesArrayDataFilter) filter;
// Ensure that there is no concurrent modification exception or synchronization problems with the
// Swing update task
SwingUtilities.invokeLater(new Runnable(){
@Override
public void run() {
XYSeriesP series = new XYSeriesP(xyfilter.getSeriesName() + "-" + xyfilter.getCount()); // Series name must be unique
xyfilter.incrementCount();
// ((LinePlot)xyfilter.getPlot()).getData().removeAllSeries(); // Remove all series from the data
// If we can agree only to display one series at a time also a clear() on the actual series is better
XYSeriesCollectionP sc = ((LinePlot)xyfilter.getPlot()).getData();
sc.addSeries(series);
// Remove outdated series
if(sc.getSeriesCount()>xyfilter.getMaxSeries()){
// Remove oldest series
sc.removeSeries(0);
}
double[] data = message.getData(xyfilter.getIdY());
// Copy data starting from offset to size
int size = data.length;
int offset = xyfilter.getOffset();
if(xyfilter.getSize()>0 && offset+xyfilter.getSize()<data.length){
size = offset + xyfilter.getSize();
}
for(int i=offset;i<size;i++){
series.add(i,data[i], false); // Do not fire change event - this would degrade performance drastically
}
series.fireSeriesChanged();
}
});
}
else if(filter instanceof XYZSeriesDataFilter){
XYZSeriesDataFilter xyzfilter = (XYZSeriesDataFilter) filter;
try{
((MatrixPlot)xyzfilter.getPlot()).getData().addData((Double) message.getData(xyzfilter.getIdX()),(Double) message.getData(xyzfilter.getIdY()), (Double) message.getData(xyzfilter.getIdZ()));
}
catch (Exception e) {
// Ignore if something goes wrong while adding a datapoint
logger.log(Level.WARNING, "Unable to plot datapoint in matrix plot", e);
}
}
else if(filter instanceof XYZSeriesArrayDataFilter){
XYZSeriesArrayDataFilter xyzfilter = (XYZSeriesArrayDataFilter) filter;
try{
double[] data = (double[]) message.getData(xyzfilter.getIdZ());
double y = (Double) message.getData(xyzfilter.getIdY());
int offset = xyzfilter.getOffset();
int size = xyzfilter.getSize();
for(int i=offset;i<offset+size; i++){
((MatrixPlot)xyzfilter.getPlot()).getData().addData(i, y, data[i]);
}
// Update data if update by point is enabled
if(updateAtStreamElement){
xyzfilter.getPlot().update();
}
}
catch (Exception e) {
// Ignore if something goes wrong while adding a datapoint
logger.log(Level.WARNING, "Unable to plot datapoint in matrix plot", e);
}
}
}
}
@Subscribe
public void onStreamDelimiterMessage(StreamDelimiterMessage message){
for(SeriesDataFilter filter: filters){
if(filter instanceof XYSeriesDataFilter){
// Create new series
XYSeriesDataFilter xyfilter = (XYSeriesDataFilter) filter;
// if (message.getNumber() == xyfilter.getDimensionX()) {
if (message.getNumber() == 0) { // TODO need to check this - here we assume that always at the lowest level we create a new series
// Indicate to create new series at the next message
xyfilter.setCount(xyfilter.getCount()+1); // Increment count of the filter
xyfilter.setNewseries(true);
}
}
}
// Update matrix plot at the end of each line
if(updateAtStreamDelimiter){
for(SeriesDataFilter f: filters){
Plot plot = f.getPlot();
// for (Plot plot: plots) {
if(plot instanceof MatrixPlot){
((MatrixPlot)plot).update();
}
else if(plot instanceof LinePlot){
((LinePlot) plot).update();
}
}
}
// Clear matrix plot if iflag is encountered
// TODO: One need to check whether the iflag belongs to a delimiter
// of a higher dimension than the highest dimension (axis) that
// is involved in the plot
if (message.isIflag()) {
clearPlot = true;
}
}
@Subscribe
public void onEndOfStreamMessage(EndOfStreamMessage message){
ecount++;
// Update plots if updateAtEndOfStream flag is set
if(updateAtEndOfStream){
// Update matrix plots
for(SeriesDataFilter f: filters){
Plot plot = f.getPlot();
if(plot instanceof MatrixPlot){
((MatrixPlot)plot).update();
((MatrixPlot)plot).adaptColorMapScale(); // Update color scale at the end
}
else if(plot instanceof LinePlot){
((LinePlot) plot).update();
}
}
}
}
public void configure(){
ecount = 0;
clearPlot = false;
}
/**
* Get the plot panels for the visualizations
* @return List of configured JPanels
*/
public List<JPanel> getPlotPanels(){
List<JPanel> panels = new ArrayList<JPanel>();
for(SeriesDataFilter f: filters){
panels.add(f.getPlot().getChartPanel());
}
return panels;
}
public boolean isUpdateAtStreamElement() {
return updateAtStreamElement;
}
public void setUpdateAtStreamElement(boolean updateAtStreamElement) {
this.updateAtStreamElement = updateAtStreamElement;
}
public boolean isUpdateAtStreamDelimiter() {
return updateAtStreamDelimiter;
}
public void setUpdateAtStreamDelimiter(boolean updateAtStreamDelimiter) {
this.updateAtStreamDelimiter = updateAtStreamDelimiter;
}
public boolean isUpdateAtEndOfStream() {
return updateAtEndOfStream;
}
public void setUpdateAtEndOfStream(boolean updateAtEndOfStream) {
this.updateAtEndOfStream = updateAtEndOfStream;
}
}

View File

@@ -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>

View File

@@ -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>

View File

@@ -1,21 +0,0 @@
#!/bin/bash
BASEDIR=$(cd $(dirname $0);pwd)
EPICS_DISPLAY_PATH=/work/sls/config/medm:$EPICS_DISPLAY_PATH
export EPICS_DISPLAY_PATH
# OTFSCAN MEDM
medm -x -macro "P=MTEST-HW3-OTFX" G_OTFSCAN_user.adl &
# Motor MEDM
medm -x -macro "P=MTEST-HW3:, M=MOT1" motorx_more.adl &
#medm -x -macro "ENC=MTEST-HW3:EC1" G_ECM_514A_encoder.adl &
medm -x -macro "P=MTEST-HW3:, M=MOT2" motorx_more.adl &
#medm -x -macro "ENC=MTEST-HW3:EC2" G_ECM_514A_encoder.adl &
medm -x -macro "P=MTEST-PC-MOTOR:, M=MOT1" motorx_more.adl &
# Scaler MEDM
medm -x -macro "P=MTEST-HW3:, S=JS" scaler16.adl &

View File

@@ -1,2 +0,0 @@
# Load test template
dbLoadTemplate("MTEST-PC-FDA_test.subs")

View File

@@ -1,5 +0,0 @@
file test.template {
{
P = MTEST-PC-FDA:
}
}

View File

@@ -1,17 +0,0 @@
MODULE = MTEST-PC-FDA
export MODULE
build:
clean:
install: build
swit -V -ioc MTEST-PC-FDA
help:
@echo "The following targets are available with this Makefile:-"
@echo "make (calls default target)"
@echo "make build (default)"
@echo "make install"
@echo "make clean"
@echo "make help"

View File

@@ -1,42 +0,0 @@
# Binary Output
record(bo, "$(P)BO") {
field(DESC, "Binary Output")
}
# Binary Output
record(bo, "$(P)BO2") {
field(DESC, "Binary Output 2")
field(VAL, "0")
}
# Analog Output
record(ao, "$(P)AO") {
field(PREC, "6")
field(DESC, "Analog Output")
}
# String Output
record(stringout, "$(P)SOUT") {
}
# Double Waveform (100 Elements)
record(waveform, "$(P)DWAVE") {
field(DESC, "Double Waveform")
field(PREC, "6")
field(NELM, "100")
field(FTVL, "DOUBLE")
}
# Integer Waveform (100 Elements)
record(waveform, "$(P)LWAVE") {
field(DESC, "Long Waveform")
field(NELM, "100")
field(FTVL, "LONG")
}
# Character Waveform (100 Elements)
record(waveform, "$(P)CWAVE") {
field(DESC, "Character Waveform")
field(NELM, "100")
field(FTVL, "CHAR")
}

View File

@@ -1,35 +0,0 @@
/**
*
* Copyright 2011 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;
/**
* @author ebner
*
*/
public class TestChannels {
public static final String BINARY_OUT = "MTEST-PC-FDA:BO";
public static final String BINARY_OUT_TWO = "MTEST-PC-FDA:BO2";
public static final String ANALOG_OUT = "MTEST-PC-FDA:AO";
public static final String STRING_OUT = "MTEST-PC-FDA:SOUT";
public static final String DOUBLE_WAVEFORM = "MTEST-PC-FDA:DWAVE";
public static final String STRING_OUT_NOT_EXIST = "MTEST-PC-FDA:SOUT-NOT-EXIST";
public static final String MOTOR_ONE = "MTEST-HW3:MOT1";
}

View File

@@ -1,102 +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;
/**
* @author ebner
*
*/
public class TestConfiguration {
private static final TestConfiguration instance = new TestConfiguration();
private final String otfPrefix = "MTEST-HW3-OTFX";
private final String crlogicPrefix = "MTEST-HW3-CRL";
private final String prefixScaler = "MTEST-HW3:JS";
private final String server = "yoke.psi.ch";
private final String share = "/usr/nfs";
private final String smbShare = "smb://test:test@"+server+"/nfs/"; // It is important to have the last slash / !
private final String motor1 = "MTEST-HW3:MOT1";
private final String analogIn1 = "MTEST-HW3-AI1:AI_01";
private TestConfiguration(){
}
public static TestConfiguration getInstance(){
return instance;
}
/**
* @return the prefix
*/
public String getCrlogicPrefix() {
return crlogicPrefix;
}
/**
* @return the prefixScaler
*/
public String getPrefixScaler() {
return prefixScaler;
}
/**
* @return the server
*/
public String getServer() {
return server;
}
/**
* @return the share
*/
public String getShare() {
return share;
}
/**
* @return the smbShare
*/
public String getSmbShare() {
return smbShare;
}
/**
* @return the motor1
*/
public String getMotor1() {
return motor1;
}
/**
* @return the analogIn1
*/
public String getAnalogIn1() {
return analogIn1;
}
/**
* @return the otfPrefix
*/
public String getOtfPrefix() {
return otfPrefix;
}
}

View File

@@ -1,75 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.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);
}
}

View File

@@ -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());
}
}

View File

@@ -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");
}
}
}

View File

@@ -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);
}
}

View File

@@ -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
}
}

View File

@@ -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();
}
}
}

View File

@@ -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");
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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.
}
}

View File

@@ -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+" ]");
}
}
}
}

View File

@@ -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();
}
}
}

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