70 Commits

Author SHA1 Message Date
d1e8913dd4 new version 2016-03-21 15:55:40 +01:00
c5d845e7ff added simulated epics server for testing 2016-03-21 15:47:04 +01:00
5f836e7856 merged core into project 2016-03-17 08:52:34 +01:00
8c13c1c85d updated gradle build 2016-03-17 08:22:19 +01:00
e1ff42d464 merged xscan into project 2016-03-17 08:17:05 +01:00
b014dd6afd merged fdaq code 2016-03-16 15:09:26 +01:00
e412ae7092 merged cdump code which this project 2016-03-16 13:29:02 +01:00
e63d2e3052 Updated readme to remember that there are 2 more properties in the fda.properties file for CRLOGIC 2015-08-21 08:53:10 +02:00
09ead2eb64 updated version 2015-08-20 08:38:51 +02:00
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
340 changed files with 15499 additions and 13828 deletions

8
.gitignore vendored Normal file
View File

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

View File

@@ -35,7 +35,7 @@ usage: viewer
# Development
When checking out the project from the repository there is the `target/generated-sources/xjc` folder missing.
After checking out the project execute `mvn compile` to create the folder and the required classes.
After checking out the project execute `mvn compile` to create the folder and the required classes.
To build project use `mvn clean install`.
@@ -104,4 +104,62 @@ GET fda/{trackingId}/done
# Notes
## Upgrade FDA 1.x to 2.x
In existing fda.properties file the following property need to be added: `ch.psi.fda.aq.data.dir=../data`
In existing fda.properties file the following property need to be added: `ch.psi.fda.aq.data.dir=../data`
## Upgrade FDA 2.6.1
There are 2 new properties for crlogic:
```
ch.psi.fda.aq.crlogic.ioc=X05LA-VME-ES2
ch.psi.fda.aq.crlogic.prefix=X05LA-ES2-CRL
```
# FDAQ
## Overview
This software is used to readout the FDAQ box developed at X10SA.
On The FDAQ box there are 2 socket servers, one for retrieving the data and one for resetting the socket
server for data retrieval.
The fdaq code provides exactly 2 functionalities. It can query on the data socket for data (need to specifying how many data point to read),
and it can send a reset request on the reset channel.
## Usage
To acquire data into a file use:
```
java -jar ch.psi.fda.fdaq-<version>.jar <file>
```
You can terminate the acquisition with *CTRL+C*. If you submit 2 consequtive *CTRL+C* the program will terminate immediately (and data might be lost);
This will take the default connections settings:
* Hostname: mchip015.psi.ch
* Port: 2233
* Kill Port: 2234
* Number Of Elements: Integer.MAX_VALUE/2
If you need to specify different settings create a property files with following content:
```
ch.psi.fda.fdaq.hostname=myhost
ch.psi.fda.fdaq.port=1234
ch.psi.fda.fdaq.killPort=4321
```
Use `-Dch.psi.fda.fdaq.config.file=<file>` to use this property file as base configuration.
## Development
A standalone jar can be build via `mvn clean compile assembly:single`.
To upload the latest version to the artifact repository use ` mvn clean compile deploy`.
## Notes
Trigger port is `Trigger In 1`. For testing apply a 1kHz signal.

92
build.gradle Normal file
View File

@@ -0,0 +1,92 @@
apply plugin: 'java'
apply plugin: 'eclipse'
sourceCompatibility = 1.7
version = '3.0.0'
buildscript {
repositories {
maven {
url "https://plugins.gradle.org/m2/"
}
}
dependencies {
classpath "com.github.jacobono:gradle-jaxb-plugin:1.3.5"
}
}
apply plugin: "com.github.jacobono.jaxb"
repositories {
mavenCentral()
maven { url "http://artifacts.psi.ch/artifactory/libs-releases" }
maven { url "http://artifacts.psi.ch/artifactory/libs-snapshots" }
}
dependencies {
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.4'
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'
compile 'com.google.guava:guava:>15.0'
compile 'com.sun.mail:javax.mail:1.5.0'
compile 'javax.inject:javax.inject:1'
compile 'org.python:jython:2.5.3'
compile 'com.fasterxml.jackson.core:jackson-databind:2.5.2'
jaxb 'com.sun.xml.bind:jaxb-xjc:2.2.7-b41'
jaxb 'com.sun.xml.bind:jaxb-impl:2.2.7-b41'
jaxb 'javax.xml.bind:jaxb-api:2.2.7'
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
}
jaxb{
xsdDir = "src/main/resources"
xjc {
generatePackage = "ch.psi.fda.model.v1"
}
}
apply plugin: 'maven'
uploadArchives {
repositories {
mavenDeployer {
repository(url: "http://artifacts.psi.ch/artifactory/libs-snapshots-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

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,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,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,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,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,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,146 +0,0 @@
/**
*
* Copyright 2012 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* This code is distributed in the hope that it will be useful, but without any
* warranty; without even the implied warranty of merchantability or fitness for
* a particular purpose. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.loops;
import static org.junit.Assert.*;
import java.io.IOException;
import java.util.logging.Logger;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import ch.psi.fda.TestConfiguration;
import ch.psi.fda.core.loops.otf.DistributedFile;
/**
* @author ebner
*
*/
public class DistributedFileTest {
private static final Logger logger = Logger.getLogger(DistributedFileTest.class.getName());
DistributedFile file;
DistributedFile smbfile;
/**
* @throws java.lang.Exception
*/
@Before
public void setUp() throws Exception {
file = new DistributedFile("src/test/resources");
smbfile = new DistributedFile(TestConfiguration.getInstance().getSmbShare());
}
/**
* @throws java.lang.Exception
*/
@After
public void tearDown() throws Exception {
}
/**
* Test method for {@link ch.psi.fda.core.loops.otf.DistributedFile#getCanonicalPath()}.
* @throws IOException
*/
@Test
public void testGetCanonicalPath() throws IOException {
logger.info(file.getCanonicalPath());
logger.info(smbfile.getCanonicalPath());
}
/**
* Test method for {@link ch.psi.fda.core.loops.otf.DistributedFile#exists()}.
* @throws IOException
*/
@Test
public void testExists() throws IOException {
if(!file.exists()){
fail("Indicating wrong file status (file actually exists)");
}
if(!smbfile.exists()){
fail("Indicating wrong file status (file actually exists)");
}
}
/**
* Test method for {@link ch.psi.fda.core.loops.otf.DistributedFile#isDirectory()}.
* @throws IOException
*/
@Test
public void testIsDirectory() throws IOException {
if(!file.isDirectory()){
fail("Indicating wrong file type (file is directory)");
}
if(!smbfile.isDirectory()){
fail("Indicating wrong file type (file is directory)");
}
}
/**
* Test method for {@link ch.psi.fda.core.loops.otf.DistributedFile#listFiles()}.
*/
@Test
public void testListFiles() {
// fail("Not yet implemented");
}
/**
* Test method for {@link ch.psi.fda.core.loops.otf.DistributedFile#getName()}.
*/
@Test
public void testGetName() {
logger.info(file.getName());
logger.info(smbfile.getName());
}
/**
* Test method for {@link ch.psi.fda.core.loops.otf.DistributedFile#isFile()}.
* @throws IOException
*/
@Test
public void testIsFile() throws IOException {
if(file.isFile()){
fail("Indicating wrong file type (file is directory)");
}
if(smbfile.isFile()){
fail("Indicating wrong file type (file is directory)");
}
}
/**
* Test method for {@link ch.psi.fda.core.loops.otf.DistributedFile#delete()}.
*/
@Test
public void testDelete() {
// fail("Not yet implemented");
}
/**
* Test method for {@link ch.psi.fda.core.loops.otf.DistributedFile#getInputStream()}.
*/
@Test
public void testGetInputStream() {
// fail("Not yet implemented");
}
}

View File

@@ -1,229 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.loops;
import static org.junit.Assert.*;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.google.common.eventbus.Subscribe;
import ch.psi.fda.TestConfiguration;
import ch.psi.fda.core.loops.otf.OTFLoop;
import ch.psi.fda.core.loops.otf.OTFNamedChannelSensor;
import ch.psi.fda.core.loops.otf.OTFScalerChannelSensor;
import ch.psi.fda.core.loops.otf.TemplateOTF;
import ch.psi.fda.core.sensors.TimestampSensor;
import ch.psi.fda.messages.ControlMessage;
import ch.psi.fda.messages.DataMessage;
import ch.psi.fda.messages.Message;
import ch.psi.jcae.Channel;
import ch.psi.jcae.ChannelDescriptor;
import ch.psi.jcae.ChannelException;
import ch.psi.jcae.ChannelService;
import ch.psi.jcae.impl.DefaultChannelService;
public class OTFLoopTest {
private static Logger logger = Logger.getLogger(OTFLoopTest.class.getName());
private ChannelService cservice;
private static final TestConfiguration configuration = TestConfiguration.getInstance();
private OTFLoop loopZigZag;
private OTFLoop loop;
private Channel<Integer> statusChannel;
@Before
public void setUp() throws Exception {
cservice = new DefaultChannelService();
statusChannel = cservice.createChannel(new ChannelDescriptor<>(Integer.class, configuration.getOtfPrefix()+":USTAT"));
OTFScalerChannelSensor s2 = new OTFScalerChannelSensor("id1", 0);
OTFScalerChannelSensor s3 = new OTFScalerChannelSensor("id2", 1);
TimestampSensor s4 = new TimestampSensor("id3");
OTFNamedChannelSensor s5 = new OTFNamedChannelSensor("id4", configuration.getAnalogIn1());
Map<String, String> macros = new HashMap<>();
macros.put("PREFIX", configuration.getOtfPrefix());
TemplateOTF template = new TemplateOTF();
cservice.createAnnotatedChannels(template, macros);
// ZigZag loop
loopZigZag = new OTFLoop(template, configuration.getServer(), configuration.getShare(), configuration.getSmbShare(), true);
loopZigZag.setActuator("id0", configuration.getMotor1(), null, 0, 8, 0.5, 0.5, 0);
loopZigZag.getSensors().add(s2);
loopZigZag.getSensors().add(s3);
loopZigZag.getSensors().add(s4);
loopZigZag.getSensors().add(s5);
// Normal loop
loop = new OTFLoop(template, configuration.getServer(), configuration.getShare(), configuration.getSmbShare(), false);
loop.setActuator("id0", configuration.getMotor1(), null, 0, 8, 0.5, 0.5, 0);
loop.getSensors().add(s2);
loop.getSensors().add(s3);
loop.getSensors().add(s4);
loop.getSensors().add(s5);
}
@After
public void tearDown() throws Exception {
cservice.destroy();
}
/**
* Test method for {@link ch.psi.fda.core.loops.otf.OTFLoop#execute()}.
* Test ordinary 1D OTF scan
* @throws ExecutionException
* @throws ChannelException
* @throws TimeoutException
* @throws CAException
*/
@Test
public void testExecute() throws InterruptedException, TimeoutException, ChannelException, ExecutionException {
Object l = new Object(){
boolean first = true;
@Subscribe
public void onMessage(DataMessage m) {
if(first){
first = false;
int numberOfSensors = 5;
if(m.getMetadata().size() != numberOfSensors){
fail("Loop returned wrong number of components inside the data message metadata");
}
boolean fail = false;
for(int x=0;x<numberOfSensors; x++){
if(! m.getMetadata().get(x).getId().equals("id"+x)){
fail = true;
}
}
if(fail){
fail("Ids of the component metadata elements inside the data message metadata is not correct");
}
}
logger.info(m.toString());
}
};
loop.getEventBus().register(l);
loop.prepare();
loop.execute();
loop.cleanup();
if(statusChannel.getValue()!=1){
fail("OTF C Logic status is not on INACTIVE");
}
}
/**
* Test method for {@link ch.psi.fda.core.loops.otf.OTFLoop#execute()}.
* Test OTF ZigZag mode
* @throws ExecutionException
* @throws ChannelException
* @throws TimeoutException
* @throws CAException
*/
@Test
public void testExecuteZigZag() throws InterruptedException, TimeoutException, ChannelException, ExecutionException {
loopZigZag.getEventBus().register(new TestCollector());
loopZigZag.prepare();
loopZigZag.execute();
loopZigZag.execute();
loopZigZag.cleanup();
if(statusChannel.getValue()!=1){
fail("OTF C Logic status is not on INACTIVE");
}
}
/**
* Test method for {@link ch.psi.fda.core.loops.otf.OTFLoop#execute()}.
* Test abort functionality while executing an OTF scan
* @throws ExecutionException
* @throws ChannelException
* @throws TimeoutException
* @throws CAException
*/
@Test
public void testExecuteAbort() throws InterruptedException, TimeoutException, ChannelException, ExecutionException {
loop.getEventBus().register(new TestCollector());
// Thread to simulate asynchronous abort operation
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(6000); // Wait some seconds before aborting the loop
loop.abort();
} catch (InterruptedException e) {
logger.log(Level.SEVERE, "An Exception occured while testing the abort functionality", e);
}
}
});
t1.start();
loop.prepare();
loop.execute();
loop.cleanup();
if(statusChannel.getValue()!=1){
fail("OTF C Logic status is not on INACTIVE");
}
}
class TestCollector {
@Subscribe
public void onMessage(Message m) {
if (m instanceof DataMessage) {
DataMessage x = (DataMessage) m;
logger.info(x.toString());
} else if (m instanceof ControlMessage) {
logger.info("---- " + m.toString() + " ----");
}
}
}
}

View File

@@ -1,121 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.loops.cr;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.logging.Logger;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import ch.psi.fda.messages.DataMessage;
import ch.psi.fda.messages.EndOfStreamMessage;
import ch.psi.fda.messages.Message;
import ch.psi.fda.messages.Metadata;
public class ParallelCrlogicStreamMergeTest {
private static final Logger logger = Logger.getLogger(ParallelCrlogicStreamMergeTest.class.getName());
@Before
public void setUp() throws Exception {
}
@After
public void tearDown() throws Exception {
}
@Test
public void testMerge() throws InterruptedException {
List<Metadata> dmm = new ArrayList<>();
dmm.add(new Metadata("cractuator"));
dmm.add(new Metadata("tstamp"));
BlockingQueue<Message> dataQueue = new LinkedBlockingQueue<Message>();
DataMessage dm = new DataMessage(dmm);
dm.getData().add(0.0035d);
dm.getData().add(10.000000123);
dataQueue.add(dm);
dm = new DataMessage(dmm);
dm.getData().add(0.015);
dm.getData().add(10.000000143);
dataQueue.add(dm);
dm = new DataMessage(dmm);
dm.getData().add(0.026);
dm.getData().add(10.000000163);
dataQueue.add(dm);
dataQueue.add(new EndOfStreamMessage());
List<Metadata> dmm2 = new ArrayList<>();
dmm2.add(new Metadata("milli"));
dmm2.add(new Metadata("nano"));
dmm2.add(new Metadata("sensor1"));
BlockingQueue<Message> dataQueue2 = new LinkedBlockingQueue<Message>();
DataMessage dm2 = new DataMessage(dmm2);
dm2.getData().add(9000d);
dm2.getData().add(122d);
dm2.getData().add(0.1d);
dataQueue2.add(dm2);
dm2 = new DataMessage(dmm2);
dm2.getData().add(10000d);
dm2.getData().add(122d);
dm2.getData().add(1d);
dataQueue2.add(dm2);
dm2 = new DataMessage(dmm2);
dm2.getData().add(10000d);
dm2.getData().add(153d);
dm2.getData().add(2d);
dataQueue2.add(dm2);
dm2 = new DataMessage(dmm2);
dm2.getData().add(10000d);
dm2.getData().add(162d);
dm2.getData().add(3d);
dataQueue2.add(dm2);
dataQueue2.add(new EndOfStreamMessage());
EventBus b = new EventBus();
b.register(new Object(){
@Subscribe
public void onMessage(Message m){
logger.info(m.toString());
}
});
ParallelCrlogicStreamMerge streamMerge = new ParallelCrlogicStreamMerge(dataQueue, dataQueue2, b);
streamMerge.merge();
}
}

BIN
gradle/wrapper/gradle-wrapper.jar vendored Normal file

Binary file not shown.

View File

@@ -0,0 +1,6 @@
#Thu Mar 17 08:20:35 CET 2016
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-bin.zip

164
gradlew vendored Executable file
View File

@@ -0,0 +1,164 @@
#!/usr/bin/env bash
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# For Cygwin, ensure paths are in UNIX format before anything is touched.
if $cygwin ; then
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
fi
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >&-
APP_HOME="`pwd -P`"
cd "$SAVED" >&-
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"

90
gradlew.bat vendored Normal file
View File

@@ -0,0 +1,90 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windowz variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View File

Before

Width:  |  Height:  |  Size: 9.7 KiB

After

Width:  |  Height:  |  Size: 9.7 KiB

View File

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 45 KiB

View File

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 51 KiB

View File

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

View File

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -37,4 +37,4 @@ do
done
# Execute java
java -Xmx1024m -XX:MaxPermSize=128m -cp $CLASSPATH -Dch.psi.fda.home=${APPLICATION_HOME} -Djava.util.logging.config.file=${APPLICATION_HOME}/config/logging.properties $VM_ARGUMENTS ch.psi.fda.ConversionMain $ARGUMENTS
java -Xmx1024m -XX:MaxPermSize=128m -cp $CLASSPATH -Djava.util.logging.config.file=${APPLICATION_HOME}/config/logging.properties $VM_ARGUMENTS ch.psi.fda.ui.ConversionMain $ARGUMENTS

View File

@@ -37,4 +37,4 @@ do
done
# Execute java
java -Xmx1024m -XX:MaxPermSize=128m -Dch.psi.fda.home=${APPLICATION_HOME} -Djava.util.logging.config.file=${APPLICATION_HOME}/config/logging.properties $VM_ARGUMENTS -cp $CLASSPATH ch.psi.fda.AcquisitionMain $ARGUMENTS
java -Xmx1024m -XX:MaxPermSize=128m -Dch.psi.fda.home=${APPLICATION_HOME} -Djava.util.logging.config.file=${APPLICATION_HOME}/config/logging.properties $VM_ARGUMENTS -cp $CLASSPATH ch.psi.fda.ui.RemoteAcquisitionMain $ARGUMENTS

View File

@@ -0,0 +1,40 @@
#!/bin/bash
CURRENTDIR=`pwd`
# Resolve symlinks
BASEDIR=$0
while [ -h "$BASEDIR" ]; do
ls=`ls -ld "$BASEDIR"`
link=`expr "$ls" : '^.*-> \(.*\)$' 2>/dev/null`
if expr "$link" : '^/' 2> /dev/null >/dev/null; then
BASEDIR="$link"
else
BASEDIR="`dirname "$BASEDIR"`/$link"
fi
done
BASEDIR=`dirname "$BASEDIR"`
SCRIPTNAME=`basename ${0}`
APPLICATION_HOME=$BASEDIR/../..
LIB_DIR=`find $BASEDIR/../lib -name "*.jar"`
LIB_DIR=`echo $LIB_DIR | sed -e 's/ /:/g'`
CLASSPATH=${APPLICATION_HOME}/config/:$LIB_DIR
ARGUMENTS=
VM_ARGUMENTS=
for i in $@
do
if [ `expr $i : '-D.*'` != '0' ] ;then
# Extract VM options
VM_ARGUMENTS="$VM_ARGUMENTS $i"
else
ARGUMENTS="$ARGUMENTS $i"
fi
done
# Execute java
java -Xmx1024m -XX:MaxPermSize=128m -Dch.psi.fda.home=${APPLICATION_HOME} -Djava.util.logging.config.file=${APPLICATION_HOME}/config/logging.properties $VM_ARGUMENTS -cp $CLASSPATH ch.psi.fda.ui.AcquisitionMain $ARGUMENTS

View File

@@ -37,4 +37,4 @@ do
done
# Execute java
java -Xmx1024m -XX:MaxPermSize=128m -cp $CLASSPATH -Dch.psi.fda.home=${APPLICATION_HOME} -Djava.util.logging.config.file=${APPLICATION_HOME}/config/logging.properties $VM_ARGUMENTS ch.psi.fda.ViewerMain $ARGUMENTS
java -Xmx1024m -XX:MaxPermSize=128m -cp $CLASSPATH -Djava.util.logging.config.file=${APPLICATION_HOME}/config/logging.properties $VM_ARGUMENTS ch.psi.fda.ui.VisualizationZMQMain $ARGUMENTS

View File

@@ -37,4 +37,4 @@ do
done
# Execute java
java -Xmx1024m -XX:MaxPermSize=128m -cp $CLASSPATH -Dch.psi.fda.home=${APPLICATION_HOME} -Djava.util.logging.config.file=${APPLICATION_HOME}/config/logging.properties $VM_ARGUMENTS ch.psi.fda.VisualizationMain $ARGUMENTS
java -Xmx1024m -XX:MaxPermSize=128m -cp $CLASSPATH -Djava.util.logging.config.file=${APPLICATION_HOME}/config/logging.properties $VM_ARGUMENTS ch.psi.fda.ui.VisualizationMain $ARGUMENTS

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 730 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 854 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 730 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 730 B

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

6158
src/main/assembly/www/css/bootstrap.css vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,22 @@
/* ==========================================================================
Author's custom styles
========================================================================== */

Binary file not shown.

After

Width:  |  Height:  |  Size: 766 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -0,0 +1,222 @@
<!DOCTYPE html>
<!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
<!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]> <html class="no-js lt-ie9"> <![endif]-->
<!--[if gt IE 8]><!-->
<html class="no-js">
<!--<![endif]-->
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title></title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width">
<link rel="stylesheet" href="css/bootstrap.min.css">
<style>
body {
padding-top: 60px;
padding-bottom: 40px;
}
</style>
<link rel="stylesheet" href="css/bootstrap-responsive.min.css">
<link rel="stylesheet" href="css/main.css">
<script src="js/vendor/modernizr-2.6.2-respond-1.1.0.min.js"></script>
<script src="js/jquery-2.0.0.min.js"></script>
<script type='text/javascript'>
var base = '../hub';
var stream;
function getVersion() {
$.get(base+'/version', function(data) {
$('#version').empty();
$('#version').append(data)
});
}
function getBeamlines() {
$.get(base, function(data) {
/* update beamlines selection */
$('#selectionBeamline').empty();
for (var i in data){
beamline = data[i];
$('#selectionBeamline').append('<option value="'+beamline+'">'+beamline+'</option>')
}
/* $('#selectionBeamline')[0].selectedIndex=0; */
connectStream(data[0]);
});
}
function updateKeys(beamline, keys){
keytag = $('#beamlineKeys');
keytag.empty();
table='<table class="table table-hover"><thead><tr><td>Key</td><td>Value</td></tr></thead><tbody>';
for(k in keys){
table=table+'<tr><td>'+k+'</td><td>'+
'<div class="input-append">'+
'<input type="text" value="'+keys[k]+'" onchange="setKey(\''+beamline+'\',\''+k+'\',$(this).val())">'+
//'<button class="btn" type="button" onclick="setKey(\''+beamline+'\',\''+k+'\',$(this).prev().val())">Update</button>'+
'<button class="btn" type="button" onclick="deleteKey(\''+beamline+'\',\''+k+'\')">Delete</button>'+
'</div>'+
'</td></tr>';
}
table = table+'<tr>'+
'<td><input id="keyToAdd" type="text" placeholder="Key"></td>'+
'<td><div class="input-append">'+
'<input id="valueToAdd"type="text" placeholder="Value">'+
'<button class="btn" type="button" onclick="setKey(\''+beamline+'\',$(\'#keyToAdd\').val(),$(\'#valueToAdd\').val())">Add</button>'+
'</div></td>'+
'</tr>';
table = table+'</table></tbody>';
keytag.append(table);
}
function connectStream(beamline) {
closeStream();
stream = new EventSource(base + '/' + beamline + '/stream');
stream.onmessage = function(event) {
keys=JSON.parse(event.data)
updateKeys(beamline, keys);
};
getKeys(beamline);
}
function closeStream() {
try {
stream.close();
} catch (e) {
}
}
function getKeys(beamline){
$.get(base+'/'+beamline+'/keys', function(data) {
updateKeys(beamline, data );
});
}
function setKey(beamline, key, value){
$.ajax({
url: base+'/'+beamline+'/keys/'+key,
type: 'PUT',
data: value,
success: function(result) {
}
});
}
function deleteKey(beamline, key){
$.ajax({
url: base+'/'+beamline+'/keys/'+key,
type: 'DELETE',
success: function(result) {
}
});
}
function addBeamline(beamline){
getKeys(beamline); /*create beamline*/
getBeamlines();
}
function deleteBeamline(beamline){
$.ajax({
url: base+'/'+beamline,
type: 'DELETE',
success: function(result) {
getBeamlines(); /* Update beamline list */
}
});
}
</script>
</head>
<body>
<!-- <script>
var source = new EventSource('../server-sent-events/');
source.onmessage = function(e) {
$('#messagefield') = e.data;
};
</script> -->
<!--[if lt IE 7]>
<p class="chromeframe">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> or <a href="http://www.google.com/chromeframe/?redirect=true">activate Google Chrome Frame</a> to improve your experience.</p>
<![endif]-->
<!-- This code is taken from http://twitter.github.com/bootstrap/examples/hero.html -->
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="navbar-inner">
<div class="container">
<a class="btn btn-navbar" data-toggle="collapse"
data-target=".nav-collapse"> <span class="icon-bar"></span> <span
class="icon-bar"></span> <span class="icon-bar"></span>
</a> <a class="brand" href="#">hub</a>
</div>
</div>
</div>
<div class="container">
<!-- Main hero unit for a primary marketing message or call to action -->
<!-- <div class="hero-unit">
<p>This is the central Hub administration page ...</p>
</div> -->
<!-- Example row of columns -->
<div class="row">
<div class="span5">
<h2>Key Group</h2>
<div>
<select id="selectionBeamline">
<!-- <option value="sydney">Sydney</option> -->
</select>
</div>
<div id="beamlineKeys"></div>
</div>
</div>
<div class="row">
<div class="span5">
<h2>Key Group Management</h2>
<div class="input-append">
<input class="span2" id="appendedInputButton" placeholder="Key Group" type="text">
<button id="addBeamlineBtn" class="btn" type="button" onclick="addBeamline($(this).prev().val());$(this).prev().val('')">Add</button>
<button id="addBeamlineBtn" class="btn" type="button" onclick="deleteBeamline($(this).prev().prev().val());$(this).prev().prev().val('')">Delete</button>
</div>
</div>
</div>
<hr>
<footer>
<p>Hub - Version <span id='version'></span> - &copy; Paul Scherrer Institute 2013</p>
</footer>
</div>
<!-- /container -->
<script>
/* update beamlines */
getVersion();
getBeamlines();
$('#selectionBeamline').change(function(){connectStream($('#selectionBeamline').val())});
</script>
<script>
window.jQuery
|| document
.write('<script src="js/vendor/jquery-1.9.1.min.js"><\/script>')
</script>
<script src="js/vendor/bootstrap.min.js"></script>
<script src="js/main.js"></script>
</body>
</html>

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,17 @@
package ch.psi.fda;
import java.io.File;
import ch.psi.fda.edescriptor.EDescriptor;
import ch.psi.fda.vdescriptor.VDescriptor;
public interface DescriptorProvider {
public void load(File ... files );
public EDescriptor getEDescriptor();
public VDescriptor getVDescriptor();
public Class<?> getEDescriptorClass();
}

View File

@@ -0,0 +1,28 @@
package ch.psi.fda;
public interface EContainer {
/**
* Initialize execution container like required resources, etc.
*/
public void initialize();
/**
* Executes the logic implemented by the ExecutionContainer
* Execute is a blocking function and must not return before the actual logic is executed
*/
public void execute();
/**
* Try to abort the execution of the logic
*/
public void abort();
public boolean isActive();
/**
* Destroy execution container and free all allocated resources
*/
public void destroy();
}

View File

@@ -0,0 +1,22 @@
package ch.psi.fda;
import ch.psi.fda.edescriptor.EDescriptor;
import com.google.common.eventbus.EventBus;
public interface EContainerFactory {
/**
* Check whether the factory supports
* @param descriptor
* @return
*/
public boolean supportsEDescriptor(EDescriptor descriptor);
/**
* Create the execution container based on the passed descriptor
* @param descriptor
* @return
*/
public EContainer getEContainer(EDescriptor descriptor, EventBus bus);
}

View File

@@ -55,14 +55,10 @@ import ch.psi.fda.core.actors.PseudoActuatorSensor;
import ch.psi.fda.core.guard.ChannelAccessGuard;
import ch.psi.fda.core.guard.ChannelAccessGuardCondition;
import ch.psi.fda.core.loops.ActorSensorLoop;
import ch.psi.fda.core.loops.cr.CrlogicLoop;
import ch.psi.fda.core.loops.cr.CrlogicLoopStream;
import ch.psi.fda.core.loops.cr.CrlogicResource;
import ch.psi.fda.core.loops.cr.ParallelCrlogic;
import ch.psi.fda.core.loops.cr.ScrlogicLoop;
import ch.psi.fda.core.loops.otf.OTFLoop;
import ch.psi.fda.core.loops.otf.OTFNamedChannelSensor;
import ch.psi.fda.core.loops.otf.OTFScalerChannelSensor;
import ch.psi.fda.core.loops.otf.TemplateOTF;
import ch.psi.fda.core.manipulator.JythonManipulation;
import ch.psi.fda.core.scripting.JythonGlobalVariable;
import ch.psi.fda.core.scripting.JythonParameterMapping;
@@ -231,9 +227,13 @@ public class Acquisition {
logger.fine("Map Model to internal logic");
if(smodel.getScan().getManipulation()!= null && smodel.getScan().getManipulation().size()>0){
if(smodel.getScan().getManipulation()!= null && smodel.getScan().getManipulation().size()>0){
// Setup optimized with manipulations
EventBus b = new AsyncEventBus(Executors.newCachedThreadPool());
//EventBus b = new AsyncEventBus(Executors.newCachedThreadPool());
EventBus b = new AsyncEventBus(Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()));
//EventBus b = new AsyncEventBus(Executors.newSingleThreadExecutor());
// Map scan to base model
// After this call actionLoop and collector will be initialized
Collector collector = new Collector(b);
@@ -370,6 +370,14 @@ public class Acquisition {
this.configModel = configuration;
Scan scan = configuration.getScan();
for(Variable v: configuration.getVariable()){
JythonGlobalVariable var = new JythonGlobalVariable();
var.setName(v.getName());
var.setValue(v.getValue());
jVariableDictionary.put(v.getName(), var);
v.getValue();
}
// Map continuous dimension
if(scan.getCdimension() != null){
ActionLoop aLoop = mapContinuousDimension(scan.getCdimension());
@@ -950,140 +958,93 @@ public class Acquisition {
* @param dimension
* @return
*/
private ActionLoop mapContinuousDimension(ContinuousDimension dimension){
ActionLoop aLoop = null;
if(!configuration.isOtfUseCrlogic()){
// USE OTFLOGIC FOR CONTINUOUS "SCANS"
// Create loop
boolean zigZag = dimension.isZigzag(); // default value is false
Map<String,String> macros = new HashMap<>();
macros.put("PREFIX", configuration.getOtfChannelPrefix());
TemplateOTF template = new TemplateOTF();
createTemplateChannels(template, macros);
OTFLoop actionLoop = new OTFLoop(template, configuration.getOtfNfsServer(), configuration.getOtfNfsShare(), configuration.getOtfSmbShare(), zigZag);
actionLoop.getPreActions().addAll(mapActions(dimension.getPreAction()));
// Map positioner
ContinuousPositioner p = dimension.getPositioner();
double backlash = 0;
if(p.getAdditionalBacklash()!=null){
backlash = p.getAdditionalBacklash();
}
actionLoop.setActuator(p.getId(), p.getName(), p.getReadback(), p.getStart(), p.getEnd(), p.getStepSize(), p.getIntegrationTime(), backlash);
// Map sensors
// ATTENTION: the sequence of the mapping depends on the sequence in the schema file !
int cnt = 0;
for(SimpleScalarDetector detector: dimension.getDetector()){
if(cnt<8){ // Only up to 8 additional channels supported
actionLoop.getSensors().add(new OTFNamedChannelSensor(detector.getId(), detector.getName()));
}
cnt++;
}
cnt = 0;
for(ScalerChannel detector: dimension.getScaler()){
if(cnt<16){ // Only up to 16 scaler channels supported
actionLoop.getSensors().add(new OTFScalerChannelSensor(detector.getId(), detector.getChannel()));
}
cnt++;
}
Timestamp detector = dimension.getTimestamp();
if(detector != null){
actionLoop.getSensors().add(new TimestampSensor(detector.getId()));
}
actionLoop.getPostActions().addAll(mapActions(dimension.getPostAction()));
aLoop = actionLoop;
}
else{
// USE CRLOGIC FOR CONTINUOUS "SCANS"
boolean hcrOnly = true;
for(SimpleScalarDetector detector: dimension.getDetector()){
if(detector.isScr()){
hcrOnly=false;
break;
}
}
// BEGIN configure HCRLOGIC
// Create loop
boolean zigZag = dimension.isZigzag(); // default value is false
CrlogicLoop actionLoop = new CrlogicLoop(cservice, configuration.getOtfCrlogicPrefix(), configuration.getOtfNfsServer(), configuration.getOtfNfsShare(), configuration.getOtfSmbShare(), zigZag);
actionLoop.setKeepTmpFiles(configuration.isOtfCrlogicKeepTmpFiles());
actionLoop.getPreActions().addAll(mapActions(dimension.getPreAction()));
// Map positioner
ContinuousPositioner p = dimension.getPositioner();
double backlash = 0;
if(p.getAdditionalBacklash()!=null){
backlash = p.getAdditionalBacklash();
}
actionLoop.setActuator(p.getId(), p.getName(), p.getReadback(), p.getStart(), p.getEnd(), p.getStepSize(), p.getIntegrationTime(), backlash);
// Map sensors
// ATTENTION: the sequence of the mapping depends on the sequence in the schema file !
for(SimpleScalarDetector detector: dimension.getDetector()){
if(!detector.isScr()){
actionLoop.getSensors().add(new CrlogicResource(detector.getId(), detector.getName()));
}
}
for(ScalerChannel detector: dimension.getScaler()){
actionLoop.getSensors().add(new CrlogicResource(detector.getId(), "SCALER"+detector.getChannel(), true));
}
Timestamp tdetector = dimension.getTimestamp();
if(tdetector != null){
actionLoop.getSensors().add(new CrlogicResource(tdetector.getId(), "TIMESTAMP"));
}
actionLoop.getPostActions().addAll(mapActions(dimension.getPostAction()));
// END Configure HCRLOGIC
if(hcrOnly){
// There are no additional channels to be read out while taking data via hcrlogic
// Therefor we just register the hcr loop as action loop
private ActionLoop mapContinuousDimension(ContinuousDimension dimension) {
aLoop = actionLoop;
ActionLoop aLoop = null;
boolean hcrOnly = true;
for (SimpleScalarDetector detector : dimension.getDetector()) {
if (detector.isScr()) {
hcrOnly = false;
break;
}
else{
List<Channel<DoubleTimestamp>> sensors = new ArrayList<>();
List<String> ids = new ArrayList<>();
for(SimpleScalarDetector detector: dimension.getDetector()){
if(detector.isScr()){
ids.add(detector.getId());
sensors.add(createChannel(DoubleTimestamp.class, detector.getName()));
}
}
// Create loop
boolean zigZag = dimension.isZigzag(); // default value is false
CrlogicLoopStream actionLoop = new CrlogicLoopStream(cservice, configuration.getCrlogicPrefix(), configuration.getCrlogicIoc(), zigZag);
actionLoop.getPreActions().addAll(mapActions(dimension.getPreAction()));
// Map positioner
ContinuousPositioner p = dimension.getPositioner();
double backlash = 0;
if (p.getAdditionalBacklash() != null) {
backlash = p.getAdditionalBacklash();
}
actionLoop.setActuator(p.getId(), p.getName(), p.getReadback(), p.getStart(), p.getEnd(), p.getStepSize(), p.getIntegrationTime(), backlash);
// Map sensors
// ATTENTION: the sequence of the mapping depends on the sequence in the
// schema file !
for (SimpleScalarDetector detector : dimension.getDetector()) {
if (!detector.isScr()) {
actionLoop.getSensors().add(new CrlogicResource(detector.getId(), detector.getName()));
}
}
for (ScalerChannel detector : dimension.getScaler()) {
actionLoop.getSensors().add(new CrlogicResource(detector.getId(), "SCALER" + detector.getChannel(), true));
}
Timestamp tdetector = dimension.getTimestamp();
if (tdetector != null) {
actionLoop.getSensors().add(new CrlogicResource(tdetector.getId(), "TIMESTAMP"));
}
actionLoop.getPostActions().addAll(mapActions(dimension.getPostAction()));
if (hcrOnly) {
// There are no additional channels to be read out while taking data
// via hcrlogic
// Therefore we just register the hcr loop as action loop
aLoop = actionLoop;
} else {
List<Channel<DoubleTimestamp>> sensors = new ArrayList<>();
List<String> ids = new ArrayList<>();
for (SimpleScalarDetector detector : dimension.getDetector()) {
if (detector.isScr()) {
ids.add(detector.getId());
sensors.add(createChannel(DoubleTimestamp.class, detector.getName(), true));
}
// Create soft(ware) based crlogic
ScrlogicLoop scrlogic = new ScrlogicLoop(ids, sensors);
// Create parallel logic
ParallelCrlogic pcrlogic = new ParallelCrlogic(actionLoop, scrlogic);
aLoop = pcrlogic;
}
// Create soft(ware) based crlogic
ScrlogicLoop scrlogic = new ScrlogicLoop(ids, sensors);
// Create parallel logic
ParallelCrlogic pcrlogic = new ParallelCrlogic(actionLoop, scrlogic);
aLoop = pcrlogic;
}
return aLoop;
}
private <T> Channel<T> createChannel(Class<T> type, String name, boolean monitor){
try {
if(name== null){
return null;
}
Channel<T> c = cservice.createChannel(new ChannelDescriptor<T>(type, name, monitor) );
channels.add(c);
return c;
} catch (ChannelException | InterruptedException | TimeoutException e) {
throw new RuntimeException("Unable to create channel: "+name,e);
}
return aLoop;
}
/**
@@ -1120,17 +1081,5 @@ public class Acquisition {
throw new RuntimeException("Unable to create channel: "+name,e);
}
}
private void createTemplateChannels(Object o, Map<String,String> macro){
try {
cservice.createAnnotatedChannels(o, macro);
templates.add(o);
} catch (ChannelException | InterruptedException | TimeoutException e) {
throw new RuntimeException("Unable to initialize template: "+o.getClass().getName(),e);
}
}
}
}

View File

@@ -35,16 +35,10 @@ 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";
public final static String FDA_CONFIG_FILE = "ch.psi.fda.xscan.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;
private String crlogicPrefix;
private String crlogicIoc;
/**
* Base directory for data. The directory may contain date macros. The string may contain any @see java.text.SimpleDateFormat
@@ -98,16 +92,8 @@ public class AcquisitionConfiguration {
}
// 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"));
crlogicPrefix = properties.getProperty(AcquisitionConfiguration.class.getPackage().getName()+".crlogic.prefix", "");
crlogicIoc= properties.getProperty(AcquisitionConfiguration.class.getPackage().getName()+".crlogic.ioc", "");
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
@@ -150,71 +136,22 @@ public class AcquisitionConfiguration {
return newString;
}
// Getter and setter functions
public String getCrlogicPrefix() {
return crlogicPrefix;
}
public void setCrlogicPrefix(String crlogicPrefix) {
this.crlogicPrefix = crlogicPrefix;
}
public String getOtfChannelPrefix() {
return otfChannelPrefix;
public void setCrlogicIoc(String crlogicIoc) {
this.crlogicIoc = crlogicIoc;
}
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 getCrlogicIoc() {
return crlogicIoc;
}
public String getDataBaseDirectory() {
return dataBaseDirectory;
@@ -247,5 +184,4 @@ public class AcquisitionConfiguration {
public void setSmptServer(String smptServer) {
this.smptServer = smptServer;
}
}

View File

@@ -66,12 +66,14 @@ public class Manipulator {
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));
// ((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);
}
// Need to update the metadata of the message
dm.setMetadata(this.metadata);
}
}
bus.post(message);
//System.out.println(Thread.currentThread());
}
}

View File

@@ -0,0 +1,50 @@
package ch.psi.fda.aq;
import com.google.common.eventbus.EventBus;
import ch.psi.fda.EContainer;
import ch.psi.fda.model.v1.Configuration;
import ch.psi.jcae.ChannelService;
public class XScanContainer implements EContainer {
private final Acquisition acquisition;
private EventBus bus;
private Configuration xscanConfiguration;
public XScanContainer(ChannelService cservice, AcquisitionConfiguration config, EventBus bus, Configuration xscanConfiguration){
acquisition = new Acquisition(cservice, config);
this.bus = bus;
this.xscanConfiguration = xscanConfiguration;
}
@Override
public void initialize() {
acquisition.initalize(bus, xscanConfiguration);
}
@Override
public void execute() {
try {
acquisition.execute();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
@Override
public void abort() {
acquisition.abort();
}
@Override
public void destroy() {
acquisition.destroy();
}
@Override
public boolean isActive() {
return acquisition.isActive();
}
}

View File

@@ -0,0 +1,29 @@
package ch.psi.fda.aq;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import ch.psi.fda.edescriptor.EDescriptor;
import ch.psi.fda.model.v1.Configuration;
@XmlRootElement(name="edescriptor")
@XmlType(name="edescriptor")
public class XScanDescriptor implements EDescriptor {
private Configuration configuration;
public XScanDescriptor(){
}
public XScanDescriptor(Configuration configuration){
this.configuration = configuration;
}
public Configuration getConfiguration() {
return configuration;
}
public void setConfiguration(Configuration configuration) {
this.configuration = configuration;
}
}

View File

@@ -1,116 +1,128 @@
/**
*
* 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.io.File;
import java.util.List;
import java.util.logging.Logger;
import ch.psi.fda.DescriptorProvider;
import ch.psi.fda.edescriptor.EDescriptor;
import ch.psi.fda.model.ModelManager;
import ch.psi.fda.model.v1.ArrayDetector;
import ch.psi.fda.model.v1.Configuration;
import ch.psi.fda.model.v1.ContinuousPositioner;
import ch.psi.fda.model.v1.Data;
import ch.psi.fda.model.v1.Detector;
import ch.psi.fda.model.v1.LinearPositioner;
import ch.psi.fda.model.v1.Positioner;
import ch.psi.fda.model.v1.PseudoPositioner;
import ch.psi.fda.model.v1.Visualization;
import ch.psi.fda.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;
import ch.psi.fda.vdescriptor.LinePlot;
import ch.psi.fda.vdescriptor.VDescriptor;
import ch.psi.fda.vdescriptor.XYSeries;
import ch.psi.fda.vdescriptor.XYZSeries;
import ch.psi.fda.vdescriptor.YSeries;
import ch.psi.fda.vdescriptor.YZSeries;
public class VisualizationMapper {
public class XScanDescriptorProvider implements DescriptorProvider {
private static final Logger logger = Logger.getLogger(XScanDescriptorProvider.class.getName());
private EDescriptor edescriptor;
private VDescriptor vdescriptor;
/**
* 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();
@Override
public void load(File... files) {
if(files.length<1 || files[0]==null){
throw new IllegalArgumentException("There need to be at lease one file specified");
}
else if (object instanceof Detector){
id = ((Detector)object).getId();
File file = files[0];
if(!file.exists()){
throw new IllegalArgumentException("File "+file.getAbsolutePath()+" does not exist");
}
else if (object instanceof ch.psi.fda.model.v1.Manipulation){
id = ((ch.psi.fda.model.v1.Manipulation)object).getId();
Configuration c;
try {
c = ModelManager.unmarshall(file);
} catch (Exception e) {
throw new UnsupportedOperationException("Unable to deserialize configuration: "+e.getMessage(), e);
}
// For testing purposes
else if(object instanceof String){
id = (String) object;
// Set data file name
// Determine name used for the data file
String name = file.getName();
name = name.replaceAll("\\.xml$", "");
if(c.getData()!=null){
Data data = c.getData();
// Only update filename if no name is specified in xml file
if(data.getFileName()==null){
data.setFileName(name);
}
}
else{
throw new RuntimeException("Unable to identify id of object reference "+object);
Data data = new Data();
data.setFileName(name);
c.setData(data);
}
return id;
// // Override number of executions
// if(iterations != null){
// c.setNumberOfExecution(iterations);
// }
// Fix configuration if iterations is specified with 0 and no iterations option is specified
if(c.getNumberOfExecution()==0){
c.setNumberOfExecution(1);
}
this.edescriptor = new XScanDescriptor(c);
this.vdescriptor = mapVisualizations(c.getVisualization());
}
/**
* Converts a list of visualizations into a list of data filters which can be applied to the data stream
*
* Create a vdescriptor out of the scan description
* @param vl
* @return
*/
public static List<SeriesDataFilter> mapVisualizations(List<Visualization> vl){
List<SeriesDataFilter> filters = new ArrayList<SeriesDataFilter>();
public static VDescriptor mapVisualizations(List<Visualization> vl){
VDescriptor vd = new VDescriptor();
for(Visualization v: vl){
if(v instanceof ch.psi.fda.model.v1.LinePlot){
ch.psi.fda.model.v1.LinePlot lp = (ch.psi.fda.model.v1.LinePlot) v;
// 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());
String x = getId(lp.getX());
LinePlot lineplot = new LinePlot(lp.getTitle());
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);
String y = getId(o);
lineplot.getData().add(new XYSeries(x, y));
}
vd.getPlots().add(lineplot);
}
else if(v instanceof ch.psi.fda.model.v1.LinePlotArray){
// Array visualization
ch.psi.fda.model.v1.LinePlotArray lp = (ch.psi.fda.model.v1.LinePlotArray) v;
// Create plot for visualization
ch.psi.plot.xy.LinePlot plot = new ch.psi.plot.xy.LinePlot(lp.getTitle());
LinePlot lineplot = new 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);
// TODO Need to actually check if minX of
lineplot.setMinX(new Double(lp.getOffset()));
lineplot.setMaxX(new Double(lp.getOffset()+lp.getSize()));
lineplot.setMaxSeries(lp.getMaxSeries());
lineplot.getData().add(new YSeries(idY));
}
vd.getPlots().add(lineplot);
}
else if(v instanceof ch.psi.fda.model.v1.MatrixPlot){
@@ -180,12 +192,18 @@ public class VisualizationMapper {
// 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);
ch.psi.fda.vdescriptor.MatrixPlot matrixplot = new ch.psi.fda.vdescriptor.MatrixPlot(mp.getTitle());
matrixplot.setMinX(minX);
matrixplot.setMaxX(maxX);
matrixplot.setnX(nX);
matrixplot.setMinY(minY);
matrixplot.setMaxY(maxY);
matrixplot.setnY(nY);
matrixplot.setType(mp.getType());
matrixplot.getData().add(new XYZSeries(idX, idY, idZ));
vd.getPlots().add(matrixplot);
}
else if(v instanceof ch.psi.fda.model.v1.MatrixPlotArray){
// Support for 2D waveform plots
@@ -256,18 +274,66 @@ public class VisualizationMapper {
// 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);
ch.psi.fda.vdescriptor.MatrixPlot matrixplot = new ch.psi.fda.vdescriptor.MatrixPlot(mp.getTitle());
matrixplot.setMinX(minX);
matrixplot.setMaxX(maxX);
matrixplot.setnX(nX);
matrixplot.setMinY(minY);
matrixplot.setMaxY(maxY);
matrixplot.setnY(nY);
matrixplot.setType(mp.getType());
matrixplot.getData().add(new YZSeries(idY, idZ));
vd.getPlots().add(matrixplot);
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");
logger.warning(v.getClass().getName()+" is not supported as visualization type");
}
}
return filters;
return vd;
}
/**
* 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;
}
@Override
public EDescriptor getEDescriptor() {
return edescriptor;
}
@Override
public VDescriptor getVDescriptor() {
return vdescriptor;
}
@Override
public Class<?> getEDescriptorClass() {
return XScanDescriptor.class;
}
}

View File

@@ -0,0 +1,36 @@
package ch.psi.fda.aq;
import javax.inject.Inject;
import com.google.common.eventbus.EventBus;
import ch.psi.fda.EContainer;
import ch.psi.fda.EContainerFactory;
import ch.psi.fda.edescriptor.EDescriptor;
import ch.psi.jcae.ChannelService;
public class XScanFactory implements EContainerFactory {
@Inject
private ChannelService cservice;
private AcquisitionConfiguration config = new AcquisitionConfiguration();
@Override
public boolean supportsEDescriptor(EDescriptor descriptor) {
return (descriptor instanceof XScanDescriptor);
}
@Override
public EContainer getEContainer(EDescriptor descriptor, EventBus bus) {
if(! (descriptor instanceof XScanDescriptor)){
throw new IllegalArgumentException("Descriptor of type "+descriptor.getClass().getName()+" is not supported - descriptor need to be of type "+XScanDescriptor.class);
}
XScanDescriptor xdescriptor = (XScanDescriptor) descriptor;
return new XScanContainer(cservice, config, bus, xdescriptor.getConfiguration());
}
}

View File

@@ -0,0 +1,151 @@
/**
*
* 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.cdump;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import java.util.logging.Logger;
import com.google.common.eventbus.EventBus;
import ch.psi.jcae.Channel;
import ch.psi.jcae.ChannelDescriptor;
import ch.psi.jcae.ChannelException;
import ch.psi.jcae.ChannelService;
/**
* Cdump readout logic - i.e. put monitor on a data waveform channel of the fast
* ADC and send data to the eventbus
*/
public class Cdump {
private static final Logger logger = Logger.getLogger(Cdump.class.getName());
public final static String[] SAMPLING_RATES = new String[] {"1Hz","2Hz", "5Hz", "10Hz", "20Hz", "50Hz", "100Hz", "200Hz", "500Hz",
"1kHz", "2kHz", "5kHz", "10kHz", "20kHz", "50kHz", "100kHz"};
private Channel<int[]> adcData;
private enum AdcCmd {
READY, GO
};
private Channel<Integer> adcCmd;
private CdumpListener listener;
private ChannelService cservice;
private CdumpConfiguration configuration;
public Cdump(ChannelService cservice, EventBus ebus, CdumpConfiguration configuration) {
this.cservice = cservice;
this.configuration = configuration;
this.listener = new CdumpListener(ebus, configuration.getNelements());
}
/**
* Acquire data with the given sampling rate
* @param samplingRate
*/
public void acquire(String samplingRate) {
logger.info("Start acquisition with sampling rate "+ samplingRate);
try {
// Set ADC sampling rate
Channel<Integer> smplRate = cservice.createChannel(new ChannelDescriptor<>(Integer.class, configuration.getSamplingRateChannel(), false));
smplRate.setValue(getIntSamplingRate(samplingRate));
smplRate.destroy();
adcData = cservice.createChannel(new ChannelDescriptor<>(int[].class, configuration.getDataChannel(), true));
adcCmd = cservice.createChannel(new ChannelDescriptor<>(Integer.class, configuration.getControlChannel(), false));
adcCmd.setValue(AdcCmd.GO.ordinal());
adcData.addPropertyChangeListener(listener);
} catch (ChannelException | TimeoutException | InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
}
/**
* Wait until acquire is done
*/
public void waitAcquireDone(){
try {
adcCmd.waitForValue(AdcCmd.READY.ordinal());
} catch (InterruptedException | ExecutionException | ChannelException e) {
throw new RuntimeException(e);
}
}
public void stop() {
logger.info("Stop acquisition");
try {
// Detach listener from channel - i.e. stop data acquisition
adcData.removePropertyChangeListener(listener);
adcCmd.setValue(AdcCmd.READY.ordinal());
listener.terminate();
adcCmd.destroy();
adcData.destroy();
} catch (ChannelException | InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
}
/**
* Get sampling rate int value based on the passed rate string.
* If the string does not match any of the strings specified in the rates variable
* this function will set the rate to 1Hz
*
* 0 = 1Hz
* 1 = 2Hz
* 2 = 5Hz
* 3 = 10Hz
* 4 = 20Hz
* 5 = 50Hz
* 6 = 100Hz
* 7 = 200Hz
* 8 = 500Hz
* 9 = 1000Hz
* 10 = 2000Hz
* 11 = 5000Hz
* 12 = 10000Hz
* 13 = 20000Hz
* 14 = 50000Hz
* 15 = 100000Hz
*
* @param rate
*/
private int getIntSamplingRate(String rate){
for(int i=0;i<SAMPLING_RATES.length; i++){
if(rate.equals(SAMPLING_RATES[i])){
return i;
}
}
// Default sampling rate 10kHz
logger.info("Using default sampling rate 12");
return 12;
}
}

View File

@@ -0,0 +1,87 @@
/**
*
* 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.cdump;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.Properties;
public class CdumpConfiguration {
public final static String CDUMP_CONFIG = "ch.psi.fda.cdump.config.file";
private String dataChannel;
private int nelements = 65536;
private String controlChannel;
private String samplingRateChannel;
public CdumpConfiguration(){
String config = System.getProperty(CDUMP_CONFIG);
if(config != null){
loadFile(new File(config));
}
else{
throw new RuntimeException("No configuration file specified via -D"+CDUMP_CONFIG+"=...");
}
}
public void loadFile(File file) {
Properties properties = new Properties();
if(file!=null){
try {
properties.load(new FileReader(file));
} catch (IOException e) {
throw new RuntimeException("Cannot read file "+file, e);
}
}
dataChannel = properties.getProperty(CdumpConfiguration.class.getPackage().getName()+".dataChannel", "");
controlChannel = properties.getProperty(CdumpConfiguration.class.getPackage().getName()+".controlChannel", "");
samplingRateChannel = properties.getProperty(CdumpConfiguration.class.getPackage().getName()+".samplingRateChannel", "");
nelements = Integer.parseInt(properties.getProperty(CdumpConfiguration.class.getPackage().getName()+".nelements", "65536"));
}
public String getDataChannel() {
return dataChannel;
}
public void setDataChannel(String dataChannel) {
this.dataChannel = dataChannel;
}
public String getControlChannel() {
return controlChannel;
}
public void setControlChannel(String controlChannel) {
this.controlChannel = controlChannel;
}
public String getSamplingRateChannel() {
return samplingRateChannel;
}
public void setSamplingRateChannel(String samplingRateChannel) {
this.samplingRateChannel = samplingRateChannel;
}
public int getNelements() {
return nelements;
}
}

View File

@@ -0,0 +1,73 @@
package ch.psi.fda.cdump;
import java.io.File;
import com.google.common.eventbus.EventBus;
import ch.psi.fda.EContainer;
import ch.psi.fda.messages.EndOfStreamMessage;
import ch.psi.fda.serializer.SerializerTXT;
import ch.psi.jcae.ChannelService;
public class CdumpEContainer implements EContainer {
private final ChannelService cservice;
private final CdumpEDescriptor edescriptor;
private final EventBus eventbus;
private Cdump cdump;
private SerializerTXT serializer;
private volatile boolean running = false;
public CdumpEContainer(ChannelService cservice, EventBus eventbus, CdumpEDescriptor edescriptor) {
this.cservice = cservice;
this.eventbus = eventbus;
this.edescriptor = edescriptor;
}
@Override
public void initialize() {
cdump = new Cdump(cservice, eventbus, new CdumpConfiguration());
File file = new File(edescriptor.getFileName());
file.getParentFile().mkdirs(); // Create data base directory
serializer = new SerializerTXT(file);
serializer.setShowDimensionHeader(false);
eventbus.register(serializer);
}
@Override
public void execute() {
running = true;
try{
cdump.acquire(edescriptor.getSamplingRate());
cdump.waitAcquireDone();
}
finally{
running=false;
}
}
@Override
public void abort() {
eventbus.post(new EndOfStreamMessage());
cdump.stop();
running = false;
eventbus.unregister(serializer);
}
@Override
public boolean isActive() {
return running;
}
@Override
public void destroy() {
abort();
}
}

View File

@@ -0,0 +1,26 @@
package ch.psi.fda.cdump;
import javax.inject.Inject;
import com.google.common.eventbus.EventBus;
import ch.psi.fda.EContainer;
import ch.psi.fda.EContainerFactory;
import ch.psi.fda.edescriptor.EDescriptor;
import ch.psi.jcae.ChannelService;
public class CdumpEContainerFactory implements EContainerFactory {
@Inject
private ChannelService cservice;
@Override
public boolean supportsEDescriptor(EDescriptor descriptor) {
return descriptor instanceof CdumpEDescriptor;
}
@Override
public EContainer getEContainer(EDescriptor descriptor, EventBus bus) {
return new CdumpEContainer(cservice, bus, (CdumpEDescriptor) descriptor);
}
}

View File

@@ -0,0 +1,25 @@
package ch.psi.fda.cdump;
import javax.xml.bind.annotation.XmlRootElement;
import ch.psi.fda.edescriptor.EDescriptor;
@XmlRootElement(name="cdump")
public class CdumpEDescriptor implements EDescriptor {
private String samplingRate;
private String fileName;
public String getSamplingRate() {
return samplingRate;
}
public void setSamplingRate(String samplingRate) {
this.samplingRate = samplingRate;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
}

View File

@@ -0,0 +1,44 @@
package ch.psi.fda.cdump;
import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import ch.psi.fda.DescriptorProvider;
import ch.psi.fda.edescriptor.EDescriptor;
import ch.psi.fda.vdescriptor.VDescriptor;
public class CdumpEDescriptorProvider implements DescriptorProvider {
private EDescriptor edescriptor;
@Override
public void load(File... files) {
try {
JAXBContext context = JAXBContext.newInstance(CdumpEDescriptor.class);
Unmarshaller u = context.createUnmarshaller();
edescriptor = (EDescriptor) u.unmarshal(files[0]);
} catch (JAXBException e) {
throw new RuntimeException(e);
}
}
@Override
public EDescriptor getEDescriptor() {
return edescriptor;
}
@Override
public VDescriptor getVDescriptor() {
return null;
}
@Override
public Class<?> getEDescriptorClass() {
return CdumpEDescriptor.class;
}
}

View File

@@ -0,0 +1,102 @@
/**
*
* 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.cdump;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.List;
import ch.psi.fda.messages.DataMessage;
import ch.psi.fda.messages.EndOfStreamMessage;
import ch.psi.fda.messages.Metadata;
import com.google.common.eventbus.EventBus;
/**
* Listener that monitors the adc data channel and splitting up the data
*/
public class CdumpListener implements PropertyChangeListener {
private final EventBus bus;
private final int numberOfElements;
private boolean first = true;
private int numberOfWaveforms = 0;
private final List<Metadata> metadata = new ArrayList<>();
public CdumpListener(EventBus bus, int numberOfElements){
this.bus = bus;
this.numberOfElements = numberOfElements;
}
@Override
public void propertyChange(PropertyChangeEvent evt) {
if(evt.getPropertyName().equals("value")){
transform((int[]) evt.getNewValue());
}
}
/**
* Transform received waveform
* 1. Take channel waveform
* [wavefrom .......................................................]
* 2. Split up waveform
* [1-number of elements][2-number of elements][3-number of elements]
* 3. Rotate splitted waveforms
* [1-0,2-0,3-0] thats one message
* [1-1,2-1,3-1]
* ...
* [1-noe, 2-noe, 3-noe]
*
*/
public void transform(int[] value){
// The first time check whether received waveform is a multiple of the specified number of elements number
// Calculate how many waveforms are within the received waveform
if(first){
first=false;
int nelements = value.length;
int n = nelements % numberOfElements;
if (n != 0) {
throw new RuntimeException("Array size is not a multiple of "+numberOfElements);
}
numberOfWaveforms = nelements / numberOfElements;
for(int i=0;i<numberOfWaveforms;i++){
metadata.add(new Metadata("waveform-"+i));
}
}
// Split and rotate waveform
for (int x = 0; x < numberOfElements; x++) {
DataMessage m = new DataMessage(metadata);
for (int t = 0; t < numberOfWaveforms; t++) {
m.getData().add(value[x + t * numberOfElements]);
}
bus.post(m);
}
}
public void terminate(){
bus.post(new EndOfStreamMessage());
}
}

View File

@@ -0,0 +1,107 @@
/**
*
* 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.cdump.ui;
import java.io.File;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import com.google.common.eventbus.AsyncEventBus;
import com.google.common.eventbus.EventBus;
import ch.psi.fda.cdump.Cdump;
import ch.psi.fda.cdump.CdumpConfiguration;
import ch.psi.fda.serializer.SerializerTXT;
import ch.psi.jcae.ChannelService;
import ch.psi.jcae.impl.DefaultChannelService;
import sun.misc.Signal;
import sun.misc.SignalHandler;
@SuppressWarnings("restriction")
public class CdumpMain {
public static void main(String[] args){
final ChannelService cservice = new DefaultChannelService();
if(args.length != 2){
System.err.println("Usage: cdump <samplingRate> <datafilename>");
StringBuilder b = new StringBuilder();
for(String s: Cdump.SAMPLING_RATES){
b.append(s);
b.append(" ");
}
System.err.println("Supported rates: "+b.toString());
System.exit(1);
}
String samplingRate = args[0];
// Calculate data file location/name
String fname = args[1];
File f = new File(fname);
f.getParentFile().mkdirs(); // Create data base directory
// Create execution service
EventBus eventbus = new AsyncEventBus(Executors.newSingleThreadExecutor());
final Cdump service = new Cdump(cservice, eventbus, new CdumpConfiguration());
SerializerTXT serializer = new SerializerTXT(f);
serializer.setShowDimensionHeader(false);
eventbus.register(serializer);
// Stop/abort handling of acquisition
Signal.handle(new Signal("INT"), new SignalHandler() {
/**
* Thread save signal counter
*/
private AtomicInteger signalCount= new AtomicInteger(0);
/**
* Testing signal handler (in Eclipse) use this after starting scan:
*
* SL5: A=`ps -ef | tail -10 | grep jav[a] | awk '{printf $2}'`;kill -2 $A
* MacOS X: A=`ps -ef | grep AcquisitionMai[n] | awk '{printf $2}'`;kill -2 $A
*
* on the command line use CTRL-C
*/
@Override
public void handle(Signal signal) {
int count = signalCount.incrementAndGet();
// If signal is received more than 1 time forcefully abort application
if(count>1){
System.exit(2);
}
service.stop();
cservice.destroy();
}
});
service.acquire(samplingRate);
}
}

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