Compare commits
115 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d1e8913dd4 | |||
| c5d845e7ff | |||
| 5f836e7856 | |||
| 8c13c1c85d | |||
| e1ff42d464 | |||
| b014dd6afd | |||
| e412ae7092 | |||
| e63d2e3052 | |||
| 09ead2eb64 | |||
| 166e8d325a | |||
| 03ac83adf6 | |||
| edf3672317 | |||
| 10f0fcdde2 | |||
| 19d2b28f25 | |||
| ac04a730a3 | |||
| 87ed988dfe | |||
| fb21986493 | |||
| 1601fbcbfd | |||
| c25a80ddfb | |||
| ba630a44e1 | |||
| 5316773104 | |||
| 38b60f3f5e | |||
| 31d37c7c45 | |||
| 366a7f2a74 | |||
| e5cc3126ab | |||
| 45505b511d | |||
| e21b3d64ee | |||
| 1a294a1a75 | |||
| fb5b2ff257 | |||
| 8d9fba4be6 | |||
| 065ed130a6 | |||
| 074ac2caff | |||
| f2e3bf23e8 | |||
| f39822ec74 | |||
| 5038912472 | |||
| 8ab87b8332 | |||
| 8f698e82ba | |||
| 58e92684ad | |||
| 5a6396cfb7 | |||
| 57ecb121b2 | |||
| 3ce7282214 | |||
| 16d18288b6 | |||
| 76ce595f87 | |||
| 486d11db2b | |||
| fa2416492e | |||
| db097eba8f | |||
| 838f6fd385 | |||
| 1c9eca2a1c | |||
| f30aa6495f | |||
| a15356190d | |||
| 88f4dd2b19 | |||
| 9f4c6c0356 | |||
| 84fb119932 | |||
| 311eae3cbc | |||
| 9529d7f088 | |||
| e597b5cd12 | |||
| 8ab6f7965b | |||
| 4bb984cc1c | |||
| b64f31e778 | |||
| 43a8347924 | |||
| f520ff4337 | |||
| 5995b2ed5c | |||
| e20cab4874 | |||
| 576d7eb048 | |||
| 21f86d7d69 | |||
| aa1681aaf3 | |||
| da182adcd2 | |||
| 8d1bd4e816 | |||
| 07d6b47885 | |||
| 87781b8f06 | |||
| 28bd7c40d8 | |||
| dcd394b586 | |||
| 76c40ccf28 | |||
| 8522d46813 | |||
| 1077ec8ab3 | |||
| da0e0eab79 | |||
| ac54407e34 | |||
| b0d4ef9d8b | |||
| f8ee1bd666 | |||
| 8d37cdbeca | |||
| fbe03b7ade | |||
| d866fa0eda | |||
| 2b0877c65d | |||
| d7f1b15927 | |||
| 35a4949907 | |||
| 30355deacc | |||
| eb0aa9a1b6 | |||
| b447ec12d7 | |||
| ae78b8c7a7 | |||
| c9ff7ccf2c | |||
| c01995675e | |||
| e4885d11e1 | |||
| 407aff2e24 | |||
| 9d6ae89f13 | |||
| fafea6dc69 | |||
| 3e841c7596 | |||
| 542379545b | |||
| 4d0f329e72 | |||
| 488fa5c908 | |||
| d550e59254 | |||
| 685ac0cd2d | |||
| 9476f9b57c | |||
| 8888172ede | |||
| e324987c8e | |||
| 76e9ea1bed | |||
| 244001fd99 | |||
| 55faaa2aa3 | |||
| ab0d1654c1 | |||
| 726cf9c0ff | |||
| 03c7d84b05 | |||
| 54fb16a0e9 | |||
| f96b85f6d0 | |||
| 696893ba16 | |||
| d84ce43676 | |||
| e625185b6d |
8
.gitignore
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
/bin
|
||||
/target
|
||||
/build
|
||||
.gradle
|
||||
.settings
|
||||
.project
|
||||
.classpath
|
||||
/schema/
|
||||
165
Readme.md
Normal file
@@ -0,0 +1,165 @@
|
||||
# Overview
|
||||
This package holds the core functionality of FDA.
|
||||
|
||||
# Usage
|
||||
use -Djava.util.logging.config.file=logging.properties` to configure logging
|
||||
|
||||
## Server
|
||||
|
||||
The FDA server is started as follows:
|
||||
|
||||
```
|
||||
./bin/server -h
|
||||
usage: fda
|
||||
-h Help
|
||||
-p <arg> Server port (default: 8080)
|
||||
-s <arg> Server address (default: localhost)
|
||||
```
|
||||
|
||||
Start new scan:
|
||||
|
||||
```
|
||||
curl -X PUT -d @scan1d.xml -H 'Content-Type:application/xml' http://localhost:8080/fda/scan
|
||||
```
|
||||
|
||||
## Viewer
|
||||
|
||||
```
|
||||
./bin/viewer -h
|
||||
usage: viewer
|
||||
-h Help
|
||||
-p <arg> Server port (default: 10000)
|
||||
-s <arg> Server address (default: localhost)
|
||||
```
|
||||
|
||||
|
||||
# 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.
|
||||
|
||||
To build project use `mvn clean install`.
|
||||
|
||||
To upload the latest version to the central artifact repository use `mvn clean deploy`.
|
||||
Create Zip file via `mvn clean compile assembly:assembly`
|
||||
|
||||
To use the FDA libary in an other project (like the GUI project) use:
|
||||
|
||||
```
|
||||
<dependency>
|
||||
<groupId>ch.psi</groupId>
|
||||
<artifactId>fda</artifactId>
|
||||
<version>x.x.x</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
## REST
|
||||
FDA offers a rest service to execute scans. There are 3 distinct service for fda scan, fdaq and cdump.
|
||||
|
||||
### FDA Service
|
||||
|
||||
Submit scan
|
||||
|
||||
```
|
||||
PUT fda/{trackingId}
|
||||
Content-Type: application/xml
|
||||
<configuration>
|
||||
...
|
||||
</configuration>
|
||||
|
||||
204 - Success
|
||||
|
||||
```
|
||||
|
||||
Stop/cancel scan
|
||||
|
||||
```
|
||||
DELETE fda/{trackingId}
|
||||
|
||||
204 - Success
|
||||
```
|
||||
|
||||
Stop all scans
|
||||
|
||||
```
|
||||
DELETE fda
|
||||
|
||||
204 - Success
|
||||
```
|
||||
|
||||
Check if scan is running
|
||||
|
||||
```
|
||||
GET fda/{trackingId}/running
|
||||
|
||||
200 - true/false
|
||||
```
|
||||
|
||||
Wait for scan done (blocks until scan is done)
|
||||
|
||||
```
|
||||
GET fda/{trackingId}/done
|
||||
|
||||
204 - Success
|
||||
```
|
||||
|
||||
# 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`
|
||||
|
||||
## 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
@@ -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'
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
1
ch.psi.fda/.gitignore
vendored
@@ -1 +0,0 @@
|
||||
/target
|
||||
@@ -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>
|
||||
@@ -1,3 +0,0 @@
|
||||
eclipse.preferences.version=1
|
||||
encoding//src/main/java=UTF-8
|
||||
encoding//src/test/java=UTF-8
|
||||
@@ -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
|
||||
@@ -1,5 +0,0 @@
|
||||
#Tue Oct 18 15:52:42 CEST 2011
|
||||
activeProfiles=
|
||||
eclipse.preferences.version=1
|
||||
resolveWorkspaceProjects=true
|
||||
version=1
|
||||
@@ -1,255 +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>1.1.41</version>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.glassfish.jersey.containers</groupId>
|
||||
<artifactId>jersey-container-grizzly2-http</artifactId>
|
||||
<version>2.3.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.glassfish.jersey.media</groupId>
|
||||
<artifactId>jersey-media-sse</artifactId>
|
||||
<version>2.3.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.glassfish.jersey.media</groupId>
|
||||
<artifactId>jersey-media-json-jackson</artifactId>
|
||||
<version>2.3.1</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>org.jeromq</groupId>
|
||||
<artifactId>jeromq</artifactId>
|
||||
<version>0.2.0</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>15.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.psi</groupId>
|
||||
<artifactId>jcae</artifactId>
|
||||
<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>
|
||||
<!-- Generate Javadoc Jar -->
|
||||
<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>
|
||||
<!-- Generate Source Jar -->
|
||||
<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>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<configuration>
|
||||
<finalName>${project.name}-${project.version}</finalName>
|
||||
<appendAssemblyId>false</appendAssemblyId>
|
||||
<archive>
|
||||
<!-- <manifest>
|
||||
<mainClass>ch.psi.fda.AcquisitionMain</mainClass>
|
||||
</manifest> -->
|
||||
</archive>
|
||||
<descriptorRefs>
|
||||
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||
</descriptorRefs>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</build>
|
||||
|
||||
<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>
|
||||
@@ -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.core.messages.DataMessage;
|
||||
import ch.psi.fda.core.messages.EndOfStreamMessage;
|
||||
import ch.psi.fda.core.messages.Message;
|
||||
import ch.psi.fda.core.messages.Metadata;
|
||||
|
||||
/**
|
||||
* Class to merge two data streams into one. The secondary queues data is added to the primary queues data.
|
||||
* The resulting queue therefor will hold the same amount of elements as the primary queue does.
|
||||
* The datagroup flag set in the end of stream message will be set according to the flag set in the primary queue.
|
||||
*/
|
||||
public class ParallelCrlogicStreamMerge {
|
||||
|
||||
|
||||
private BlockingQueue<Message> primaryQueue;
|
||||
private BlockingQueue<Message> secondaryQueue;
|
||||
|
||||
private final EventBus eventbus;
|
||||
|
||||
private List<Metadata> metadata;
|
||||
|
||||
/**
|
||||
* @param pqueue Primary/master queue
|
||||
* @param squeue Secondary queue
|
||||
*/
|
||||
public ParallelCrlogicStreamMerge(BlockingQueue<Message> pqueue, BlockingQueue<Message> squeue, EventBus ebus){
|
||||
this.primaryQueue = pqueue;
|
||||
this.secondaryQueue = squeue;
|
||||
|
||||
this.eventbus = ebus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge the streams based on the timestamp
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public void merge() throws InterruptedException{
|
||||
|
||||
metadata = new ArrayList<>();
|
||||
|
||||
boolean firstPrimary = true;
|
||||
boolean firstSecondary = true;
|
||||
|
||||
// Actual data of the secondary queue
|
||||
List<Object> currData = null;
|
||||
|
||||
// Take first element of the primary queue (wait until message is available)
|
||||
Message m = primaryQueue.take();
|
||||
|
||||
while(! (m instanceof EndOfStreamMessage)){
|
||||
|
||||
if(m instanceof DataMessage){
|
||||
|
||||
DataMessage dm = (DataMessage) m;
|
||||
|
||||
if(firstPrimary){
|
||||
firstPrimary = false;
|
||||
List<Metadata> pqm = dm.getMetadata();
|
||||
metadata.add(pqm.get(0)); // add first component (this is the actuator)
|
||||
// Skip the next component as this is the timestamp used to merge the data
|
||||
for(int i=2;i<pqm.size();i++){
|
||||
metadata.add(pqm.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Get and remove merge timestamp from the data of the message
|
||||
Double timestamp = (Double) dm.getData().remove(1);
|
||||
long milliseconds = (long) (timestamp*1000);
|
||||
long nanoOffset = (long)((timestamp*1000-milliseconds)*1000000);
|
||||
|
||||
while(true){
|
||||
// Assumption: the secondary Queue holds at least the data up to the
|
||||
// timestamp of the primary queue
|
||||
Message mess = secondaryQueue.peek();
|
||||
|
||||
if(mess instanceof EndOfStreamMessage){
|
||||
break;
|
||||
}
|
||||
|
||||
if(mess == null){
|
||||
break;
|
||||
}
|
||||
|
||||
if(mess instanceof DataMessage){
|
||||
|
||||
// Check whether timestamp of the next message is bigger than the timestamp of the
|
||||
// message from the primary queue - if the timestamp is bigger do not take message out of the queue
|
||||
DataMessage msCheck = (DataMessage) mess;
|
||||
|
||||
if(firstSecondary){
|
||||
firstSecondary = false;
|
||||
|
||||
List<Metadata> sqm = msCheck.getMetadata();
|
||||
// Skip first two components of the message as this is the timestamp
|
||||
for(int i=2;i<sqm.size();i++){
|
||||
metadata.add(sqm.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
long currMilliCheck = ((Double) msCheck.getData().get(0)).longValue();
|
||||
long currNanoCheck = ((Double) msCheck.getData().get(1)).longValue();
|
||||
|
||||
if(currMilliCheck>milliseconds || (currMilliCheck==milliseconds && currNanoCheck>nanoOffset)){
|
||||
break;
|
||||
}
|
||||
|
||||
DataMessage ms = (DataMessage) secondaryQueue.take();
|
||||
|
||||
currData = ms.getData();
|
||||
// Remove timestamps
|
||||
currData.remove(0);
|
||||
currData.remove(0);
|
||||
}
|
||||
else{
|
||||
// No DataMessage
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Add data to primary data queue message and put it into the out queue
|
||||
dm.getData().addAll(currData);
|
||||
dm.setMetadata(metadata);
|
||||
eventbus.post(dm);
|
||||
}
|
||||
|
||||
|
||||
m = primaryQueue.take();
|
||||
}
|
||||
|
||||
// Add the end of stream message of the primary queue
|
||||
eventbus.post(m);
|
||||
|
||||
// Clear all remaining messages in secondary queue
|
||||
secondaryQueue.clear();
|
||||
}
|
||||
}
|
||||
@@ -1,305 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Foundation, either version 3 of the License, or (at your option) any
|
||||
* later version.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but without any
|
||||
* warranty; without even the implied warranty of merchantability or fitness for
|
||||
* a particular purpose. See the GNU Lesser General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this code. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.psi.fda.core.loops.cr;
|
||||
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.google.common.eventbus.EventBus;
|
||||
|
||||
import ch.psi.fda.core.Action;
|
||||
import ch.psi.fda.core.ActionLoop;
|
||||
import ch.psi.fda.core.messages.DataMessage;
|
||||
import ch.psi.fda.core.messages.EndOfStreamMessage;
|
||||
import ch.psi.fda.core.messages.Metadata;
|
||||
import ch.psi.jcae.Channel;
|
||||
import ch.psi.jcae.impl.type.DoubleTimestamp;
|
||||
|
||||
/**
|
||||
* Assumptions: - The delay between the monitor writing the value to the
|
||||
* monitor queue and the readout of all the queues is sufficient to
|
||||
* prevent the situation that some monitors of events close to each
|
||||
* other on different IOC's have not arrived yet. - The sequence of
|
||||
* monitors fired for one channel is according to the sequence of the
|
||||
* causes. No monitor package is overtaking an other package on the
|
||||
* network.
|
||||
*
|
||||
* - No monitor events are lost on the network (while using monitors you
|
||||
* cannot guarantee this)
|
||||
*
|
||||
* The data queue returned by this logic includes two items for the
|
||||
* timestamp and nanoseconds offset. These two items are the first two
|
||||
* items of a message The id's are: crTimestampMilliseconds
|
||||
* crTimestampOffsetNanoseconds
|
||||
*/
|
||||
public class ScrlogicLoop implements ActionLoop {
|
||||
|
||||
private static String ID_TIMESTAMP_MILLISECONDS = "crTimestampMilliseconds";
|
||||
private static String ID_TIMESTAMP_OFFSET_NANOSECONDS = "crTimestampOffsetNanoseconds";
|
||||
|
||||
// Get Logger
|
||||
private static final Logger logger = Logger.getLogger(ScrlogicLoop.class.getName());
|
||||
|
||||
|
||||
/**
|
||||
* Data queue sensor data is posted to. A message consists of a list of data
|
||||
* objects that are read out of the sensors of this loop.
|
||||
*/
|
||||
// private final BlockingQueue<Message> dataQueue = new LinkedBlockingQueue<Message>();
|
||||
|
||||
private boolean dataGroup = false;
|
||||
private final List<Action> preActions = new ArrayList<Action>();
|
||||
private final List<Action> postActions = new ArrayList<Action>();
|
||||
|
||||
private List<String> sensorIds;
|
||||
private List<Channel<DoubleTimestamp>> sensors;
|
||||
|
||||
/**
|
||||
* List of monitors that were attached to the sensor channels (i.e
|
||||
* workaround)
|
||||
*/
|
||||
private final List<PropertyChangeListener> monitors = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* List of blocking queues that hold the data for one sensor (channel)
|
||||
*/
|
||||
private final List<BlockingQueue<TimestampedValue>> queues = new ArrayList<BlockingQueue<TimestampedValue>>();
|
||||
|
||||
private CountDownLatch latch;
|
||||
|
||||
private final EventBus eventbus;
|
||||
private List<Metadata> metadata;
|
||||
|
||||
public ScrlogicLoop(List<String> sensorIds, List<Channel<DoubleTimestamp>> sensors) {
|
||||
this.eventbus = new EventBus();
|
||||
this.sensorIds = sensorIds;
|
||||
this.sensors = sensors;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() throws InterruptedException {
|
||||
|
||||
// Clear all queues
|
||||
queues.clear();
|
||||
latch = new CountDownLatch(1);
|
||||
|
||||
// Attach monitors to the channels (this is actually a workaround)
|
||||
for (Channel<DoubleTimestamp> sensor : sensors) {
|
||||
final BlockingQueue<TimestampedValue> q = new LinkedBlockingQueue<TimestampedValue>();
|
||||
queues.add(q);
|
||||
PropertyChangeListener listener = new PropertyChangeListener() {
|
||||
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
if(evt.getPropertyName().equals("value")){
|
||||
DoubleTimestamp v = (DoubleTimestamp) evt.getNewValue();
|
||||
q.add(new TimestampedValue(v.getValue(), v.getTimestamp().getTime(), v.getNanosecondOffset()));
|
||||
}
|
||||
}
|
||||
};
|
||||
sensor.addPropertyChangeListener(listener);
|
||||
monitors.add(listener);
|
||||
|
||||
}
|
||||
|
||||
logger.info("Start data acquisition");
|
||||
|
||||
latch.await();
|
||||
|
||||
// Remove monitors
|
||||
|
||||
for (int i = 0; i < sensors.size(); i++) {
|
||||
Channel<DoubleTimestamp> sensor = sensors.get(i);
|
||||
sensor.removePropertyChangeListener(monitors.get(i));
|
||||
}
|
||||
|
||||
// Merge data
|
||||
merge();
|
||||
|
||||
// Clear data queues
|
||||
for (BlockingQueue<TimestampedValue> q : queues) {
|
||||
q.clear();
|
||||
}
|
||||
queues.clear();
|
||||
|
||||
|
||||
// Put end of stream to the queue
|
||||
eventbus.post(new EndOfStreamMessage(dataGroup));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void abort() {
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepare() {
|
||||
|
||||
metadata = new ArrayList<>();
|
||||
|
||||
// Build up data message metadata based on the channels registered.
|
||||
metadata.add(new Metadata(ID_TIMESTAMP_MILLISECONDS));
|
||||
metadata.add(new Metadata(ID_TIMESTAMP_OFFSET_NANOSECONDS));
|
||||
for (String id : sensorIds) {
|
||||
metadata.add(new Metadata(id));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanup() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Action> getPreActions() {
|
||||
return preActions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Action> getPostActions() {
|
||||
return postActions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDataGroup() {
|
||||
return dataGroup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDataGroup(boolean dataGroup) {
|
||||
this.dataGroup = dataGroup;
|
||||
}
|
||||
|
||||
private boolean hasNext(){
|
||||
for (BlockingQueue<TimestampedValue> q: queues) {
|
||||
if(!q.isEmpty()){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge data collected by different monitor
|
||||
*
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
private void merge() throws InterruptedException {
|
||||
// Array to hold temporary channel values
|
||||
TimestampedValue[] cvalues = new TimestampedValue[queues.size()];
|
||||
TimestampedValueComparator comparator = new TimestampedValueComparator();
|
||||
|
||||
// Oldest value written
|
||||
TimestampedValue globalOldest = null;
|
||||
List<Integer> indexes = new ArrayList<Integer>();
|
||||
|
||||
while (hasNext()) {
|
||||
Thread.sleep(10); // Ensure that close by monitors have time to
|
||||
// catch up / also ensure context switch
|
||||
|
||||
// Oldest value of this run
|
||||
TimestampedValue oldest = null;
|
||||
// Queue index of the oldest value of this run
|
||||
indexes.clear();
|
||||
|
||||
// Find oldest element in any of the queues
|
||||
for (int i = 0; i < queues.size(); i++) {
|
||||
|
||||
BlockingQueue<TimestampedValue> q = queues.get(i);
|
||||
TimestampedValue ttcheck = q.peek();
|
||||
|
||||
if (ttcheck != null) {
|
||||
if (oldest == null) {
|
||||
// Update the oldest variable with current element
|
||||
oldest = ttcheck;
|
||||
indexes.clear();
|
||||
indexes.add(i);
|
||||
} else if (comparator.compare(ttcheck, oldest) < 0) {
|
||||
// Check whether timestamp is less (older) than the current oldest timestamp.
|
||||
oldest = ttcheck;
|
||||
indexes.clear();
|
||||
indexes.add(i);
|
||||
} else if (comparator.compare(ttcheck, oldest) == 0) {
|
||||
// SAME TIMESTAMP
|
||||
indexes.add(i);
|
||||
} else {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// logger.info("Index: "+index+" Permits: "+semaphore.availablePermits());
|
||||
// System.out.println("indexes: "+indexes.size());
|
||||
|
||||
if (indexes.size() > 0) {
|
||||
long timestamp = 0l;
|
||||
long nanoOffset = 0l;
|
||||
|
||||
for (Integer index : indexes) {
|
||||
// Get next older value
|
||||
cvalues[index] = queues.get(index).poll();
|
||||
|
||||
if (globalOldest != null) {
|
||||
if (comparator.compare(cvalues[index], globalOldest) >= 0) {
|
||||
// Update the global oldest variable
|
||||
globalOldest = cvalues[index];
|
||||
timestamp = cvalues[index].getTimestamp();
|
||||
nanoOffset = cvalues[index].getNanosecondsOffset();
|
||||
} else {
|
||||
// Monitors did not fire in sequence (an newer
|
||||
// monitor overtook an older (from an other IOC))
|
||||
logger.warning("Timestamped value out of sequence - discard value !!!!");
|
||||
// Continue with next value ...
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
globalOldest = cvalues[index];
|
||||
}
|
||||
}
|
||||
|
||||
// Assemble data message ...
|
||||
DataMessage message = new DataMessage(metadata);
|
||||
|
||||
message.getData().add(new Double(timestamp));
|
||||
message.getData().add(new Double(nanoOffset));
|
||||
|
||||
for (int y = 0; y < cvalues.length; y++) {
|
||||
if (cvalues[y] != null) {
|
||||
message.getData().add(new Double(cvalues[y].getValue()));
|
||||
} else {
|
||||
message.getData().add(Double.NaN);
|
||||
}
|
||||
}
|
||||
// System.out.println(message);
|
||||
eventbus.post(message);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public EventBus getEventBus(){
|
||||
return eventbus;
|
||||
}
|
||||
}
|
||||
@@ -1,158 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* Copyright 2012 Paul Scherrer Institute. All rights reserved.
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Foundation, either version 3 of the License, or (at your option) any
|
||||
* later version.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but without any
|
||||
* warranty; without even the implied warranty of merchantability or fitness for
|
||||
* a particular purpose. See the GNU Lesser General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this code. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package ch.psi.fda.core.loops.otf;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.MalformedURLException;
|
||||
|
||||
import jcifs.smb.SmbFile;
|
||||
|
||||
public class DistributedFile {
|
||||
|
||||
private SmbFile smbfile = null;
|
||||
private File file = null;
|
||||
|
||||
public DistributedFile(SmbFile file){
|
||||
this.smbfile = file;
|
||||
}
|
||||
|
||||
public DistributedFile(File file){
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
public DistributedFile(String url) throws MalformedURLException{
|
||||
if(url.startsWith("smb://")){
|
||||
smbfile = new SmbFile(url);
|
||||
}
|
||||
else {
|
||||
file = new File(url);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public String getCanonicalPath() throws IOException{
|
||||
if(smbfile!=null){
|
||||
return(smbfile.getCanonicalPath());
|
||||
}
|
||||
else{
|
||||
return file.getCanonicalPath();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
public boolean exists() throws IOException {
|
||||
if(smbfile!=null){
|
||||
return(smbfile.exists());
|
||||
}
|
||||
else{
|
||||
return file.exists();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public boolean isDirectory() throws IOException {
|
||||
if(smbfile!=null){
|
||||
return(smbfile.isDirectory());
|
||||
}
|
||||
else{
|
||||
return file.isDirectory();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public DistributedFile[] listFiles() throws IOException {
|
||||
if(smbfile!=null){
|
||||
SmbFile[] files = smbfile.listFiles();
|
||||
DistributedFile[] dfiles = new DistributedFile[files.length];
|
||||
for(int i=0;i<files.length;i++){
|
||||
dfiles[i] = new DistributedFile(files[i]);
|
||||
}
|
||||
return(dfiles);
|
||||
}
|
||||
else{
|
||||
File[] files = file.listFiles();
|
||||
DistributedFile[] dfiles = new DistributedFile[files.length];
|
||||
for(int i=0;i<files.length;i++){
|
||||
dfiles[i] = new DistributedFile(files[i]);
|
||||
}
|
||||
return(dfiles);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public String getName() {
|
||||
if(smbfile!=null){
|
||||
return(smbfile.getName());
|
||||
}
|
||||
else{
|
||||
return file.getName();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public boolean isFile() throws IOException {
|
||||
if(smbfile!=null){
|
||||
return(smbfile.isFile());
|
||||
}
|
||||
else{
|
||||
return file.isFile();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public void delete() throws IOException {
|
||||
if(smbfile!=null){
|
||||
smbfile.delete();
|
||||
}
|
||||
else{
|
||||
file.delete();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public InputStreamReader getInputStream() throws IOException {
|
||||
if(smbfile!=null){
|
||||
return(new InputStreamReader(smbfile.getInputStream()));
|
||||
}
|
||||
else{
|
||||
return new FileReader(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,439 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful,
|
||||
* but without any warranty; without even the implied warranty of
|
||||
* merchantability or fitness for a particular purpose. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this code. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.psi.fda.core.loops.otf;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.MalformedURLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.google.common.eventbus.EventBus;
|
||||
|
||||
import ch.psi.fda.core.Action;
|
||||
import ch.psi.fda.core.ActionLoop;
|
||||
import ch.psi.fda.core.Sensor;
|
||||
import ch.psi.fda.core.messages.DataMessage;
|
||||
import ch.psi.fda.core.messages.EndOfStreamMessage;
|
||||
import ch.psi.fda.core.messages.Metadata;
|
||||
import ch.psi.fda.core.sensors.TimestampSensor;
|
||||
|
||||
/**
|
||||
* ActionLoop that is implementing the OTF Scan logic.
|
||||
* While executing the loop a full OTF scan procedure is executed.
|
||||
*/
|
||||
public class OTFLoop implements ActionLoop {
|
||||
|
||||
private static Logger logger = Logger.getLogger(OTFLoop.class.getName());
|
||||
|
||||
/**
|
||||
* Flag to indicate whether the data of this loop will be grouped
|
||||
* According to this flag the dataGroup flag in EndOfStream will be set.
|
||||
*/
|
||||
private boolean dataGroup = false;
|
||||
|
||||
/**
|
||||
* Maximum number of monitored channels
|
||||
*/
|
||||
private static final int numberOfMonitoredChannels = 8;
|
||||
/**
|
||||
* Maximum number of Scaler channels
|
||||
*/
|
||||
private static final int numberOfScalerChannels = 16;
|
||||
|
||||
/**
|
||||
* Default timeout (in milliseconds) for wait operations
|
||||
*/
|
||||
private long timeout = 8000;
|
||||
|
||||
/**
|
||||
* Name of the NFS server to place the data of the OTF logic
|
||||
*/
|
||||
private final String server;
|
||||
/**
|
||||
* Share on the NFS server to put the OTF data on to
|
||||
*/
|
||||
private final String share;
|
||||
/**
|
||||
* SMB share to access the data written by the OTF C logic
|
||||
*/
|
||||
private final String smbShare;
|
||||
|
||||
/**
|
||||
* Flag whether the actor of this loop should move in zig zag mode
|
||||
*/
|
||||
private final boolean zigZag;
|
||||
|
||||
/**
|
||||
* Bean holding all OTF channels and functionality.
|
||||
*/
|
||||
private TemplateOTF obean;
|
||||
|
||||
/**
|
||||
* List of actions that are executed at the beginning of the loop.
|
||||
*/
|
||||
private List<Action> preActions;
|
||||
/**
|
||||
* List of actions that are executed at the end of the loop.
|
||||
*/
|
||||
private List<Action> postActions;
|
||||
|
||||
/**
|
||||
* List of sensors of this loop
|
||||
*/
|
||||
private List<Sensor> sensors;
|
||||
|
||||
|
||||
private List<Integer> dataIndexes;
|
||||
|
||||
/**
|
||||
* Execution count of this loop. This count is used to determine the
|
||||
* file name of the OTF file.
|
||||
*/
|
||||
private int executionCount;
|
||||
|
||||
/**
|
||||
* Flag that indicates that the loop was requested to abort.
|
||||
*/
|
||||
private volatile boolean abort = false;
|
||||
|
||||
|
||||
private String id;
|
||||
private String name; // name of the motor channel
|
||||
private String readback; // name of the encoder channel
|
||||
private double start;
|
||||
private double end;
|
||||
private double stepSize;
|
||||
private double integrationTime;
|
||||
private double additionalBacklash;
|
||||
|
||||
private final EventBus eventbus;
|
||||
private List<Metadata> metadata;
|
||||
|
||||
/**
|
||||
* @param channelPrefix Prefix of the OTF related records, e.g. MTEST-HW3-OTF
|
||||
* @param server NFS server the OTF C Logic should put its data to
|
||||
* @param share Share on NFS server to put the OTF C Logic data
|
||||
* @param smbShare SMB share to get the data written by the OTF C Logic
|
||||
* @param zigZag Operate loop in zig zag mode
|
||||
*/
|
||||
public OTFLoop(TemplateOTF obean, String server, String share, String smbShare, boolean zigZag){
|
||||
|
||||
this.eventbus = new EventBus();
|
||||
|
||||
this.obean = obean;
|
||||
|
||||
// Store loop configuration
|
||||
this.server = server;
|
||||
this.share = share;
|
||||
this.smbShare = smbShare;
|
||||
this.zigZag = zigZag;
|
||||
|
||||
// Initialize lists used by the loop
|
||||
this.preActions = new ArrayList<Action>();
|
||||
this.postActions = new ArrayList<Action>();
|
||||
this.sensors = new ArrayList<Sensor>();
|
||||
}
|
||||
|
||||
public void setActuator(String id, String name, String readback, double start, double end, double stepSize, double integrationTime, double additionalBacklash){
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.readback = readback;
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
this.stepSize = stepSize;
|
||||
this.integrationTime = integrationTime;
|
||||
this.additionalBacklash = additionalBacklash;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void execute() throws InterruptedException {
|
||||
|
||||
// Execute pre actions
|
||||
for(Action action: preActions){
|
||||
action.execute();
|
||||
}
|
||||
|
||||
// Start scan
|
||||
obean.start();
|
||||
|
||||
// Wait for end of scan
|
||||
obean.waitUntilStopped();
|
||||
|
||||
// Read data from file
|
||||
collectData();
|
||||
|
||||
// Execute post actions
|
||||
for(Action action: postActions){
|
||||
action.execute();
|
||||
}
|
||||
|
||||
|
||||
// Issue end of loop control message
|
||||
eventbus.post(new EndOfStreamMessage(dataGroup));
|
||||
|
||||
// Increase execution count
|
||||
executionCount++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void abort() {
|
||||
// Abort otf scan logic
|
||||
obean.abort();
|
||||
|
||||
abort=true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepare() {
|
||||
executionCount = 0;
|
||||
|
||||
// Set abort flag to false
|
||||
abort=false;
|
||||
|
||||
// list with all monitored channels
|
||||
List<String> monitoredChannels = new ArrayList<String>();
|
||||
dataIndexes = new ArrayList<Integer>();
|
||||
dataIndexes.add(1); // The first one is always the readback of the motor
|
||||
int channelCount =0;
|
||||
for(Sensor s: sensors){
|
||||
if(s instanceof OTFNamedChannelSensor){
|
||||
// Monitored channel
|
||||
OTFNamedChannelSensor so = (OTFNamedChannelSensor) s;
|
||||
if(channelCount>=numberOfMonitoredChannels){
|
||||
throw new IllegalArgumentException("Only up to "+numberOfMonitoredChannels+" channels can be monitored by OTF");
|
||||
}
|
||||
|
||||
monitoredChannels.add(so.getName());
|
||||
dataIndexes.add(2+numberOfScalerChannels+channelCount);
|
||||
|
||||
|
||||
channelCount++;
|
||||
}
|
||||
else if (s instanceof OTFScalerChannelSensor){
|
||||
OTFScalerChannelSensor so = (OTFScalerChannelSensor) s;
|
||||
if(so.getIndex()>=numberOfScalerChannels){
|
||||
throw new IllegalArgumentException("Scaler index must be between 0<=index<"+numberOfScalerChannels);
|
||||
}
|
||||
dataIndexes.add(2+so.getIndex()); // scalers follow directly after the readback
|
||||
}
|
||||
else if (s instanceof TimestampSensor){
|
||||
dataIndexes.add(2+numberOfScalerChannels+numberOfMonitoredChannels);
|
||||
}
|
||||
// else if (s instanceof OTFReadbackSensor){
|
||||
// dataIndexes.add(1);
|
||||
// }
|
||||
else{
|
||||
throw new IllegalArgumentException("Sensor type "+s.getClass()+" is not supported by this loop");
|
||||
}
|
||||
}
|
||||
|
||||
// Set OTF parameters
|
||||
try{
|
||||
obean.resetToDefaults();
|
||||
|
||||
// Set actor properties
|
||||
obean.setMotor(this.name);
|
||||
obean.waitUntilMotorOk(timeout);
|
||||
|
||||
obean.setBegin(this.start);
|
||||
obean.setEnd(this.end);
|
||||
obean.setStepSize(this.stepSize);
|
||||
obean.setIntegrationTime(this.integrationTime);
|
||||
|
||||
// Override encoder if specified
|
||||
if(this.readback!=null){
|
||||
obean.setUseEncoder(true);
|
||||
obean.setEncoder(this.readback);
|
||||
obean.waitUntilEncoderOk(timeout);
|
||||
}
|
||||
|
||||
// Set user backlash
|
||||
obean.setUserBacklash(this.additionalBacklash);
|
||||
|
||||
|
||||
// NFS settings
|
||||
obean.setNfsServer(server);
|
||||
obean.setNfsShare(share);
|
||||
|
||||
obean.setFileNameGeneration(true);
|
||||
obean.setAppendFile(false);
|
||||
obean.setZigZag(zigZag); // Set ZigZag because there might be iterations
|
||||
obean.setFileNameFormat("%06d"); // Force an update of the filename/counter by setting file format twice with different values
|
||||
obean.setFileNameFormat("%06d.txt");
|
||||
|
||||
|
||||
|
||||
// Set monitored channels
|
||||
obean.setMonitoredChannels(monitoredChannels.toArray(new String[monitoredChannels.size()]));
|
||||
}
|
||||
catch(Exception e){
|
||||
throw new RuntimeException("Unable to set OTF configuration parameters",e);
|
||||
}
|
||||
|
||||
|
||||
// Cleanup temporary directory
|
||||
try{
|
||||
DistributedFile tmpDir = new DistributedFile(smbShare);
|
||||
if( !tmpDir.exists() || !tmpDir.isDirectory() ){
|
||||
throw new RuntimeException("Cannot access OTF temporary directory "+tmpDir.getCanonicalPath());
|
||||
}
|
||||
DistributedFile[] files = tmpDir.listFiles();
|
||||
|
||||
for(int i=0;i<files.length;i++){
|
||||
// Only delete item if it is not a directory and if it matches the given pattern.
|
||||
if(files[i].isFile() && files[i].getName().matches("[0-9]+.txt")){
|
||||
files[i].delete();
|
||||
logger.fine("Delete file: "+files[i].getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(MalformedURLException e){
|
||||
throw new RuntimeException(e);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Unable to access share (temporary files)",e);
|
||||
}
|
||||
|
||||
metadata = new ArrayList<>();
|
||||
metadata.add(new Metadata(id)); // Id of the readback of the motor
|
||||
|
||||
// Build up data message metadata based on the sensors currently registered.
|
||||
for(Sensor s: sensors){
|
||||
metadata.add(new Metadata(s.getId()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanup() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Action> getPreActions() {
|
||||
return preActions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Action> getPostActions() {
|
||||
return postActions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect data written by the OTFScan logic
|
||||
* @param dataSet
|
||||
* @param tmpFile
|
||||
*/
|
||||
private void collectData() {
|
||||
try{
|
||||
final int timestampIndex = 2+numberOfScalerChannels+numberOfMonitoredChannels;
|
||||
|
||||
DistributedFile tmpFile = new DistributedFile(smbShare +"/"+ String.format("%06d.txt", executionCount));
|
||||
logger.fine("Collect data from "+tmpFile.getCanonicalPath());
|
||||
|
||||
DistributedFile lockfile = new DistributedFile(tmpFile.getCanonicalPath() + ".lock");
|
||||
|
||||
logger.fine("Wait until file is written [lock file: "+lockfile.getCanonicalPath()+"]");
|
||||
// Wait until file is created
|
||||
while ((!tmpFile.exists()) || lockfile.exists()) {
|
||||
Thread.sleep(500);
|
||||
if(abort){
|
||||
// If abort is issued while waiting for data immediately return without
|
||||
// trying to read the data
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
logger.fine("Read file " + tmpFile.getCanonicalPath());
|
||||
InputStreamReader inreader = tmpFile.getInputStream();
|
||||
BufferedReader in = new BufferedReader(inreader);
|
||||
String line;
|
||||
boolean firstline = true;
|
||||
while (true) {
|
||||
line = in.readLine();
|
||||
if (line == null) {
|
||||
break;
|
||||
} else {
|
||||
if(line.matches("^\\[.*")){
|
||||
// Skip header lines
|
||||
}
|
||||
else{
|
||||
if(firstline){
|
||||
firstline=false;
|
||||
continue;
|
||||
}
|
||||
|
||||
DataMessage message = new DataMessage(metadata);
|
||||
// Add data to dataset
|
||||
String[] tokens = line.split("\t");
|
||||
|
||||
for(Integer i: dataIndexes){
|
||||
try{
|
||||
if(i == timestampIndex) {
|
||||
// Calculate time in milliseconds
|
||||
Double seconds = new Double(tokens[i]);
|
||||
Double nanoseconds = new Double(tokens[i+1]);
|
||||
|
||||
Double v = seconds*1000+Math.floor(nanoseconds*0.000001);
|
||||
message.getData().add(v);
|
||||
}
|
||||
else {
|
||||
|
||||
message.getData().add(new Double(tokens[i]));
|
||||
}
|
||||
}
|
||||
catch(NumberFormatException e){
|
||||
logger.warning("Cannot parse component ["+tokens[i]+"] from source file - will add 0 for this component");
|
||||
message.getData().add(new Double(0));
|
||||
}
|
||||
}
|
||||
eventbus.post(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
in.close();
|
||||
inreader.close();
|
||||
} catch(InterruptedException e){
|
||||
throw new RuntimeException("An interrupt occured while waiting for the file to show up",e);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("An IO Exception occured while reading the OTF data file",e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public List<Sensor> getSensors() {
|
||||
return sensors;
|
||||
}
|
||||
public boolean isDataGroup() {
|
||||
return dataGroup;
|
||||
}
|
||||
public void setDataGroup(boolean dataGroup) {
|
||||
this.dataGroup = dataGroup;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ch.psi.fda.core.ActionLoop#getEventBus()
|
||||
*/
|
||||
@Override
|
||||
public EventBus getEventBus() {
|
||||
return eventbus;
|
||||
}
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful,
|
||||
* but without any warranty; without even the implied warranty of
|
||||
* merchantability or fitness for a particular purpose. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this code. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.psi.fda.core.loops.otf;
|
||||
|
||||
import ch.psi.fda.core.Sensor;
|
||||
|
||||
/**
|
||||
* Sensor to read out a named (Epics) channel. This sensor can only be used within the
|
||||
* OTFLoop. If it is used in other loops, the read value will always be 0.
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
public class OTFNamedChannelSensor implements Sensor {
|
||||
|
||||
/**
|
||||
* Name of the channel
|
||||
*/
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* Global id of the sensor
|
||||
*/
|
||||
private final String id;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param id Global id of the sensor
|
||||
* @param name Name of the (Epics) channel
|
||||
*/
|
||||
public OTFNamedChannelSensor(String id, String name){
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object read() {
|
||||
// Always return 0 if read() method is called.
|
||||
return 0d;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the name of the channel
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful,
|
||||
* but without any warranty; without even the implied warranty of
|
||||
* merchantability or fitness for a particular purpose. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this code. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.psi.fda.core.loops.otf;
|
||||
|
||||
import ch.psi.fda.core.Sensor;
|
||||
|
||||
/**
|
||||
* Sensor to read out a scaler channel. This sensor can only be used within the
|
||||
* OTFLoop. If it is used in other loops, the read value will always be 0.
|
||||
*
|
||||
*/
|
||||
public class OTFScalerChannelSensor implements Sensor {
|
||||
|
||||
/**
|
||||
* Index of the scaler channel. The index starts at 0;
|
||||
*/
|
||||
private final int index;
|
||||
|
||||
/**
|
||||
* Global id of the sensor
|
||||
*/
|
||||
private final String id;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param id Global id of the sensor
|
||||
* @param index Index of the scaler channel. Index starts at 0.
|
||||
*/
|
||||
public OTFScalerChannelSensor(String id, int index){
|
||||
this.id = id;
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object read() {
|
||||
return 0d;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the index of the scaler channel
|
||||
*/
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
@@ -1,964 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful,
|
||||
* but without any warranty; without even the implied warranty of
|
||||
* merchantability or fitness for a particular purpose. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this code. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.psi.fda.core.loops.otf;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import ch.psi.jcae.annotation.CaChannel;
|
||||
import ch.psi.jcae.Channel;
|
||||
import ch.psi.jcae.ChannelException;
|
||||
|
||||
/**
|
||||
* Bean holding all OTF channels and functionality
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
public class TemplateOTF {
|
||||
|
||||
public enum Status { SETUP, INACTIVE, INITIALIZE, ACTIVE, STOP, FAULT, ERROR };
|
||||
public enum Command { NONE, START, STOP };
|
||||
|
||||
private long timeoutMotorOk = 8000;
|
||||
private long commandTimeout = 20000; // Maximum time until a command should take effect
|
||||
|
||||
@CaChannel(type=String.class, name ="${PREFIX}:UMOT")
|
||||
private Channel<String> motor;
|
||||
|
||||
@CaChannel(type=String.class, name="${PREFIX}:MENC")
|
||||
private Channel<String> encoder;
|
||||
|
||||
@CaChannel(type=Double.class, name="${PREFIX}:UBEG")
|
||||
private Channel<Double> begin;
|
||||
|
||||
@CaChannel(type=Double.class, name="${PREFIX}:UBEG.DRVL")
|
||||
private Channel<Double> beginMin;
|
||||
|
||||
@CaChannel(type=Double.class, name="${PREFIX}:UBEG.DRVH")
|
||||
private Channel<Double> beginMax;
|
||||
|
||||
@CaChannel(type=Double.class, name="${PREFIX}:UEND")
|
||||
private Channel<Double> end;
|
||||
|
||||
@CaChannel(type=Double.class, name="${PREFIX}:UEND.DRVL")
|
||||
private Channel<Double> endMin;
|
||||
|
||||
@CaChannel(type=Double.class, name="${PREFIX}:UEND.DRVH")
|
||||
private Channel<Double> endMax;
|
||||
|
||||
@CaChannel(type=Double.class, name="${PREFIX}:USSIZ")
|
||||
private Channel<Double> stepSize;
|
||||
|
||||
@CaChannel(type=Double.class, name="${PREFIX}:USSIZ.DRVL")
|
||||
private Channel<Double> stepSizeMin;
|
||||
|
||||
@CaChannel(type=Double.class, name="${PREFIX}:UITIM")
|
||||
private Channel<Double> integrationTime;
|
||||
|
||||
@CaChannel(type=Double.class, name="${PREFIX}:UITIM.DRVL")
|
||||
private Channel<Double> integrationTimeMin;
|
||||
|
||||
@CaChannel(type=Double.class, name="${PREFIX}:UITIM.DRVH")
|
||||
private Channel<Double> integrationTimeMax;
|
||||
|
||||
@CaChannel(type=Double.class, name="${PREFIX}:UBCL")
|
||||
private Channel<Double> userBacklash;
|
||||
|
||||
@CaChannel(type=String.class, name="${PREFIX}:NFSSE")
|
||||
private Channel<String> nfsServer;
|
||||
|
||||
@CaChannel(type=String.class, name="${PREFIX}:NFSSH")
|
||||
private Channel<String> nfsShare;
|
||||
|
||||
@CaChannel(type=String.class, name="${PREFIX}:DFNAM")
|
||||
private Channel<String> fileName;
|
||||
|
||||
@CaChannel(type=String.class, name="${PREFIX}:FFORM")
|
||||
private Channel<String> fileNameFormat;
|
||||
|
||||
@CaChannel(type=Integer.class, name="${PREFIX}:FCNT")
|
||||
private Channel<Integer> fileCount;
|
||||
|
||||
@CaChannel(type=Integer.class, name="${PREFIX}:FCNT.B")
|
||||
private Channel<Integer> resetFileCounter;
|
||||
|
||||
@CaChannel(type=Boolean.class, name="${PREFIX}:FAPPE")
|
||||
private Channel<Boolean> appendFile;
|
||||
|
||||
@CaChannel(type=Boolean.class, name="${PREFIX}:FUSE")
|
||||
private Channel<Boolean> fileNameGeneration;
|
||||
|
||||
@CaChannel(type=Boolean.class, name="${PREFIX}:UZIGZ")
|
||||
private Channel<Boolean> zigZag;
|
||||
|
||||
@CaChannel(type=Integer.class, name="${PREFIX}:UCOM")
|
||||
private Channel<Integer> command;
|
||||
|
||||
@CaChannel(type=Boolean.class, name="${PREFIX}:SCRU", monitor=true)
|
||||
private Channel<Boolean> scanRunning;
|
||||
|
||||
@CaChannel(type=Boolean.class, name="${PREFIX}:MUENC")
|
||||
private Channel<Boolean> useEncoder;
|
||||
|
||||
@CaChannel(type=String.class, name={"${PREFIX}:CTM0","${PREFIX}:CTM1","${PREFIX}:CTM2","${PREFIX}:CTM3","${PREFIX}:CTM4","${PREFIX}:CTM5","${PREFIX}:CTM6","${PREFIX}:CTM7"})
|
||||
private List<Channel<String>> monitoredChannels;
|
||||
|
||||
@CaChannel(type=Boolean.class, name="${PREFIX}:OTF", monitor=true)
|
||||
private Channel<Boolean> running;
|
||||
|
||||
@CaChannel(type=Integer.class, name="${PREFIX}:USTAT", monitor=true)
|
||||
private Channel<Integer> status;
|
||||
|
||||
@CaChannel(type=Boolean.class, name="${PREFIX}:MOK", monitor=true)
|
||||
private Channel<Boolean> motorOk;
|
||||
|
||||
@CaChannel(type=Boolean.class, name="${PREFIX}:EOK", monitor=true)
|
||||
private Channel<Boolean> encoderOk;
|
||||
|
||||
@CaChannel(type=String.class, name="${PREFIX}:MSG")
|
||||
private Channel<String> message;
|
||||
|
||||
/**
|
||||
* Get the trigger name that can be used by the sscan record to trigger an OTFScan
|
||||
* @return Name of the trigger that can be used by sscan record
|
||||
*/
|
||||
public String getSScanTriggerName(){
|
||||
return(running.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Start OTF scan
|
||||
*/
|
||||
public void start() {
|
||||
try{
|
||||
if(getStatus().equals(Status.INACTIVE)){
|
||||
|
||||
// Send START command
|
||||
this.command.setValue(Command.START.ordinal());
|
||||
|
||||
// Wait until OtF logic is active
|
||||
this.scanRunning.waitForValue(true, commandTimeout);
|
||||
}
|
||||
else{
|
||||
throw new RuntimeException("Cannot start scan, status is not INACTIVE.\nThe current status is: "+getStatus()+" . The OTF logic need to be recovered manually [Message: "+getMessage()+"]");
|
||||
}
|
||||
}
|
||||
catch(Exception e){
|
||||
throw new RuntimeException("Unable to start OTF scan.",e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Abort scan
|
||||
*/
|
||||
public void abort() {
|
||||
try{
|
||||
// Send STOP command
|
||||
this.command.setValue(Command.STOP.ordinal());
|
||||
|
||||
// Do not wait for put to return
|
||||
this.running.setValueNoWait(false);
|
||||
}
|
||||
catch(Exception e){
|
||||
throw new RuntimeException("Unable to abort OTF logic" ,e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop OTF scan
|
||||
* @throws Exception
|
||||
*/
|
||||
public void stop() throws Exception{
|
||||
if(!getStatus().equals(Status.INACTIVE) || !getStatus().equals(Status.FAULT)){
|
||||
|
||||
// Send STOP command
|
||||
this.command.setValue(Command.STOP.ordinal());
|
||||
|
||||
// Wait until logic is stopped
|
||||
status.waitForValue(Status.INACTIVE.ordinal(), commandTimeout);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait until scan has stopped
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public void waitUntilStopped() throws InterruptedException {
|
||||
try {
|
||||
scanRunning.waitForValue(false); // Use of default wait timeout
|
||||
|
||||
// Check whether the status is INACTIVE otherwise get messge from OTF and throw an exception
|
||||
if(status.getValue() != Status.INACTIVE.ordinal()){
|
||||
throw new RuntimeException("OTFSCAN failed with message: "+message.getValue());
|
||||
}
|
||||
|
||||
} catch (ExecutionException | ChannelException | TimeoutException e) {
|
||||
throw new RuntimeException("An error occurred while waiting for the OTF logic to finish.", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait until scan has stopped
|
||||
* @param waitTimeout
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public void waitUntilStopped(Long waitTimeout) throws InterruptedException {
|
||||
try {
|
||||
scanRunning.waitForValue(false, waitTimeout);
|
||||
|
||||
// Check whether the status is INACTIVE otherwise get messge from OTF and throw an exception
|
||||
if(status.getValue() != Status.INACTIVE.ordinal()){
|
||||
throw new RuntimeException("OTFSCAN failed with message: "+message.getValue());
|
||||
}
|
||||
|
||||
} catch (ExecutionException | ChannelException | TimeoutException e) {
|
||||
throw new RuntimeException("An error occurred while waiting for the OTF logic to finish.", e);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset OTFScan records to defaults
|
||||
* @throws CAException
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public void resetToDefaults() throws InterruptedException{
|
||||
try{
|
||||
setMonitoredChannels(new String[]{});
|
||||
setMotor("");
|
||||
begin.setValue(0d);
|
||||
end.setValue(0d);
|
||||
stepSize.setValue(0d);
|
||||
integrationTime.setValue(0d);
|
||||
zigZag.setValue(false);
|
||||
setAppendFile(false);
|
||||
setFileNameGeneration(true);
|
||||
setFileName("");
|
||||
setFileNameFormat("%06d.txt");
|
||||
resetFileCounter();
|
||||
|
||||
setUserBacklash(0d);
|
||||
|
||||
// setNfsServer("");
|
||||
// setNfsShare("");
|
||||
|
||||
waitUntilMotorNotOk(timeoutMotorOk);
|
||||
}
|
||||
catch(ExecutionException | ChannelException e){
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get motor of the OTFScan axis
|
||||
* @return Name of the OTF motor
|
||||
* @throws CAException
|
||||
*/
|
||||
public String getMotor() throws InterruptedException {
|
||||
try {
|
||||
return(this.motor.getValue());
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set motor of the OTFScan axis
|
||||
* @param motor
|
||||
* @throws CAException
|
||||
*/
|
||||
public void setMotor(String motor) throws InterruptedException {
|
||||
try{
|
||||
this.motor.setValue(motor);
|
||||
} catch (ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get encoder of the OTFScan axis
|
||||
* @return Name of the used encoder
|
||||
* @throws CAException
|
||||
*/
|
||||
public String getEncoder() throws InterruptedException {
|
||||
try{
|
||||
return(this.encoder.getValue());
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set encoder to use of the OTFScan axis
|
||||
* @param encoder
|
||||
* @throws CAException
|
||||
*/
|
||||
public void setEncoder(String encoder) throws InterruptedException {
|
||||
try{
|
||||
this.encoder.setValue(encoder);
|
||||
} catch (ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get begin position of the scan
|
||||
* @return Begin position scan
|
||||
* @throws CAException
|
||||
*/
|
||||
public Double getBegin() throws InterruptedException {
|
||||
try{
|
||||
return(this.begin.getValue());
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set begin position of scan
|
||||
* @param begin
|
||||
* @throws Exception
|
||||
*/
|
||||
public void setBegin(Double begin) throws InterruptedException {
|
||||
try{
|
||||
if(begin==null){
|
||||
throw new IllegalArgumentException("Begin position must not be null");
|
||||
}
|
||||
|
||||
if(begin < beginMin.getValue() || begin > beginMax.getValue()){
|
||||
throw new IllegalArgumentException("Cannot set begin value to "+begin+ ". Value is outside range [min: "+beginMin.getValue()+" max: "+beginMax.getValue()+"]");
|
||||
}
|
||||
|
||||
this.begin.setValue(begin);
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get minimum value of the begin position
|
||||
* @return Min value for begin
|
||||
* @throws CAException
|
||||
*/
|
||||
public Double getMinBegin() throws InterruptedException {
|
||||
try{
|
||||
return(this.beginMin.getValue());
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get maximum value of the begin position
|
||||
* @return Max value for begin
|
||||
* @throws CAException
|
||||
*/
|
||||
public Double getMaxBegin() throws InterruptedException {
|
||||
try{
|
||||
return(this.beginMax.getValue());
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get end position of the scan
|
||||
* @return End position scan
|
||||
* @throws CAException
|
||||
*/
|
||||
public Double getEnd() throws InterruptedException {
|
||||
try{
|
||||
return(this.end.getValue());
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set end positon of scan
|
||||
* @param end
|
||||
* @throws CAException
|
||||
*/
|
||||
public void setEnd(Double end) throws InterruptedException {
|
||||
try{
|
||||
if(end==null){
|
||||
throw new IllegalArgumentException("End position must not be null");
|
||||
}
|
||||
|
||||
if(end < endMin.getValue() || end > endMax.getValue()){
|
||||
throw new IllegalArgumentException("Cannot set end value to "+end+ ". Value is outside range [min: "+endMin.getValue()+" max: "+endMax.getValue()+"]");
|
||||
}
|
||||
|
||||
this.end.setValue(end);
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get minimum value of end position
|
||||
* @return Min value for end
|
||||
* @throws CAException
|
||||
*/
|
||||
public Double getMinEnd() throws InterruptedException {
|
||||
try{
|
||||
return(this.endMin.getValue());
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Get maximum value of end position
|
||||
* @return Max value for end
|
||||
* @throws CAException
|
||||
*/
|
||||
public Double getMaxEnd() throws InterruptedException {
|
||||
try{
|
||||
return(this.endMax.getValue());
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get scan step size
|
||||
* @return Step size
|
||||
* @throws CAException
|
||||
*/
|
||||
public Double getStepSize() throws InterruptedException {
|
||||
try{
|
||||
return(this.stepSize.getValue());
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set step size of scan
|
||||
* @param stepSize
|
||||
* @throws CAException
|
||||
*/
|
||||
public void setStepSize(Double stepSize) throws InterruptedException {
|
||||
try{
|
||||
if(integrationTime==null){
|
||||
throw new IllegalArgumentException("Step size must not be null");
|
||||
}
|
||||
|
||||
// Check if step size is greater than min step size
|
||||
if(stepSizeMin.getValue() != 0 && stepSize < stepSizeMin.getValue()){
|
||||
throw new IllegalArgumentException("Step size value ["+stepSize+"] is less than minimum step size ["+stepSizeMin.getValue()+"]!");
|
||||
}
|
||||
|
||||
this.stepSize.setValue(stepSize);
|
||||
|
||||
// TODO WORKAROUND - Wait to "ensure" that step size related fields are updated (i.e. min/max integration time)
|
||||
Thread.sleep(1);
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get minimum integration time
|
||||
* @return Min value for step size
|
||||
* @throws CAException
|
||||
*/
|
||||
public double getMinStepSize() throws InterruptedException {
|
||||
try{
|
||||
return(this.stepSizeMin.getValue());
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get scan integration time (time that is spend in one step)
|
||||
* @return Integration time
|
||||
* @throws CAException
|
||||
*/
|
||||
public Double getIntegrationTime() throws InterruptedException {
|
||||
try{
|
||||
return(this.integrationTime.getValue());
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set integration time of scan
|
||||
* @param integrationTime
|
||||
* @throws CAException
|
||||
*/
|
||||
public void setIntegrationTime(Double integrationTime) throws InterruptedException {
|
||||
try{
|
||||
if(integrationTime==null){
|
||||
throw new IllegalArgumentException("Integration time must not be null");
|
||||
}
|
||||
|
||||
// Check range (if limit is set to 0 then limit is not set)
|
||||
double min = integrationTimeMin.getValue();
|
||||
double max = integrationTimeMax.getValue();
|
||||
if(min!= 0 && max!= 0){
|
||||
if(integrationTime < min || integrationTime > max){
|
||||
throw new IllegalArgumentException("Integration time ["+integrationTime+"] is outside range [min: "+min+" max: "+max+"]");
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(min!= 0 && integrationTime<min){
|
||||
throw new IllegalArgumentException("Integration time ["+integrationTime+"] is outside range [min: "+min+" max: - ]");
|
||||
}
|
||||
else if(max!= 0 && integrationTime>max){
|
||||
throw new IllegalArgumentException("Integration time ["+integrationTime+"] is outside range [min: - max: "+max+"]");
|
||||
}
|
||||
}
|
||||
|
||||
this.integrationTime.setValue(integrationTime);
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get minimum integration time
|
||||
* @return Min value for integration time
|
||||
* @throws CAException
|
||||
*/
|
||||
public Double getMinIntegrationTime() throws InterruptedException {
|
||||
try{
|
||||
return(this.integrationTimeMin.getValue());
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Get maximum integration time
|
||||
* @return Max value for integration time
|
||||
* @throws CAException
|
||||
*/
|
||||
public Double getMaxIntegrationTime() throws InterruptedException {
|
||||
try{
|
||||
return(this.integrationTimeMax.getValue());
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get additional user defined backlash
|
||||
* @return User backlash
|
||||
* @throws CAException
|
||||
*/
|
||||
public Double getUserBacklash() throws InterruptedException {
|
||||
try{
|
||||
return(this.userBacklash.getValue());
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set additional user defined backlash
|
||||
* @param userBacklash
|
||||
* @throws CAException
|
||||
*/
|
||||
public void setUserBacklash(Double userBacklash) throws InterruptedException {
|
||||
try{
|
||||
if(userBacklash==null){
|
||||
throw new IllegalArgumentException("User backlash must not be null");
|
||||
}
|
||||
|
||||
this.userBacklash.setValue(userBacklash);
|
||||
} catch (ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current NFS server the data is written to
|
||||
* @return Name of NFS server
|
||||
* @throws CAException
|
||||
*/
|
||||
public String getNfsServer() throws InterruptedException {
|
||||
try{
|
||||
return(this.nfsServer.getValue());
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set name of the NFS server the data is written to
|
||||
* @param nfsServer
|
||||
* @throws CAException
|
||||
*/
|
||||
public void setNfsServer(String nfsServer) throws InterruptedException {
|
||||
try{
|
||||
this.nfsServer.setValue(nfsServer);
|
||||
} catch (ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the NFS share the data is written to
|
||||
* @return Name of NFS share
|
||||
* @throws CAException
|
||||
*/
|
||||
public String getNfsShare() throws InterruptedException {
|
||||
try{
|
||||
return(this.nfsShare.getValue());
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set name of the NFS share the data is written to
|
||||
* @param nfsShare
|
||||
* @throws CAException
|
||||
*/
|
||||
public void setNfsShare(String nfsShare) throws InterruptedException {
|
||||
try{
|
||||
this.nfsShare.setValue(nfsShare);
|
||||
} catch (ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the data file
|
||||
* @return Name of data file name
|
||||
* @throws CAException
|
||||
*/
|
||||
public String getFileName() throws InterruptedException {
|
||||
try{
|
||||
return(this.fileName.getValue());
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set name of the data file
|
||||
* @param filename
|
||||
* @throws CAException
|
||||
*/
|
||||
public void setFileName(String filename) throws InterruptedException {
|
||||
try{
|
||||
this.fileName.setValue(filename);
|
||||
} catch (ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get File name formate
|
||||
* @return Get format for file name
|
||||
* @throws CAException
|
||||
*/
|
||||
public String getFileNameFormat() throws InterruptedException {
|
||||
try{
|
||||
return(this.fileNameFormat.getValue());
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set file name formate of the data file
|
||||
* @param fileNameFormat
|
||||
* @throws Exception
|
||||
*/
|
||||
public void setFileNameFormat(String fileNameFormat) throws InterruptedException {
|
||||
try{
|
||||
this.fileNameFormat.setValue(fileNameFormat);
|
||||
} catch (ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get value of the IOC based file name counter
|
||||
* @return File counter
|
||||
* @throws CAException
|
||||
*/
|
||||
public int getFileCounter() throws InterruptedException {
|
||||
try{
|
||||
return(this.fileCount.getValue());
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the IOC based file counter
|
||||
* @throws CAException
|
||||
*/
|
||||
public void resetFileCounter() throws InterruptedException {
|
||||
try{
|
||||
this.resetFileCounter.setValue(1);
|
||||
} catch (ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get if append file option is activated
|
||||
* @return Append file flag
|
||||
* @throws CAException
|
||||
*/
|
||||
public boolean isAppendFile() throws InterruptedException {
|
||||
try{
|
||||
return(this.appendFile.getValue());
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to append the specified file if the file exists
|
||||
* @param append
|
||||
* @throws CAException
|
||||
*/
|
||||
public void setAppendFile(boolean append) throws InterruptedException {
|
||||
try{
|
||||
this.appendFile.setValue(append);
|
||||
} catch (ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get if file name generation is on or off
|
||||
* @return File name generation flag
|
||||
* @throws CAException
|
||||
*/
|
||||
public boolean isFileNameGeneration() throws InterruptedException {
|
||||
try{
|
||||
return(this.fileNameGeneration.getValue());
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Whether the file name should be generated out of the file name format and the file counter
|
||||
* @param generation
|
||||
* @throws CAException
|
||||
*/
|
||||
public void setFileNameGeneration(boolean generation) throws InterruptedException {
|
||||
try{
|
||||
this.fileNameGeneration.setValue(generation);
|
||||
} catch (ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get if ZigZag scan option is on or off
|
||||
* @return ZigZag flag
|
||||
* @throws CAException
|
||||
*/
|
||||
public boolean isZigZag() throws InterruptedException {
|
||||
try{
|
||||
return(this.zigZag.getValue());
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set ZigZag scan mode on/off
|
||||
* @param zigZag ZigZag mode on = true, ZigZag mode off = false
|
||||
* @throws CAException
|
||||
*/
|
||||
public void setZigZag(boolean zigZag) throws InterruptedException {
|
||||
try{
|
||||
this.zigZag.setValue(zigZag);
|
||||
} catch (ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether encoder is used
|
||||
*/
|
||||
public boolean isUseEncoder() throws InterruptedException {
|
||||
try{
|
||||
return(this.useEncoder.getValue());
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set flag to use encoder
|
||||
* @throws CAException
|
||||
*/
|
||||
public void setUseEncoder(boolean flag) throws InterruptedException {
|
||||
try{
|
||||
this.useEncoder.setValue(flag);
|
||||
} catch (ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the channels that are currently monitored by the OTFScan logic
|
||||
* @return Names of the monitored channels
|
||||
* @throws CAException
|
||||
*/
|
||||
public String[] getMonitoredChannels() throws InterruptedException {
|
||||
try{
|
||||
String[] values = new String[this.monitoredChannels.size()];
|
||||
|
||||
for(int i=0; i<this.monitoredChannels.size();i++){
|
||||
values[i] = monitoredChannels.get(i).getValue();
|
||||
}
|
||||
|
||||
return(values);
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the channels that need to be monitored.
|
||||
* Note: As OTF only supports 8 channels to be monitored, only the first 8
|
||||
* values of the passed channelNames are considered.
|
||||
* @param values Array of channel names to be monitored
|
||||
* @throws CAException
|
||||
*/
|
||||
public void setMonitoredChannels(String[] values) throws InterruptedException {
|
||||
|
||||
try{
|
||||
if(values.length>monitoredChannels.size()){
|
||||
throw new IllegalArgumentException("Only up to "+monitoredChannels.size()+" monitored channels are supported by OTF");
|
||||
}
|
||||
|
||||
for(int i=0; i<this.monitoredChannels.size(); i++){
|
||||
if(values != null && i<values.length){
|
||||
this.monitoredChannels.get(i).setValue(values[i]);
|
||||
}
|
||||
else{
|
||||
this.monitoredChannels.get(i).setValue("");
|
||||
}
|
||||
}
|
||||
} catch (ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether an scan is running
|
||||
* @return Running flag
|
||||
* @throws CAException
|
||||
*/
|
||||
public boolean isRunning() throws InterruptedException {
|
||||
try{
|
||||
return(running.getValue());
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get status of the scan
|
||||
* @return Status of the scan
|
||||
* @throws CAException
|
||||
*/
|
||||
public Status getStatus() throws InterruptedException {
|
||||
try{
|
||||
return(Status.values()[this.status.getValue()]);
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the (error) message from the OTF records
|
||||
* @return Message from OTF C logic
|
||||
* @throws CAException
|
||||
*/
|
||||
public String getMessage() throws InterruptedException {
|
||||
try{
|
||||
return(message.getValue());
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the specified motor is recognized as ok (i.e. it is registered as OTFScan motor)
|
||||
* @return Flag whether motor is ok
|
||||
* @throws CAException
|
||||
*/
|
||||
public boolean isMotorOk() throws InterruptedException {
|
||||
try{
|
||||
return(motorOk.getValue());
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait until the motor flag goes to ok
|
||||
* @param timeout Timout in milliseconds
|
||||
*
|
||||
* @throws CAException If motor ok flag does not switch to ok within the specified timeout
|
||||
*/
|
||||
public void waitUntilMotorOk(long timeout) throws InterruptedException {
|
||||
try{
|
||||
motorOk.waitForValue(true, timeout);
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait until the motor flag goes to not ok
|
||||
* @param timeout Timout in milliseconds
|
||||
*
|
||||
* @throws CAException If motor ok flag does not switch to ok within the specified timeout
|
||||
*/
|
||||
public void waitUntilMotorNotOk(long timeout) throws InterruptedException {
|
||||
try{
|
||||
motorOk.waitForValue(false, timeout);
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void waitUntilEncoderOk(long timeout) throws InterruptedException {
|
||||
try{
|
||||
if(!useEncoder.getValue()){
|
||||
return;
|
||||
}
|
||||
encoderOk.waitForValue(true, timeout);
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,170 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* Copyright 2013 Paul Scherrer Institute. All rights reserved.
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Foundation, either version 3 of the License, or (at your option) any
|
||||
* later version.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but without any
|
||||
* warranty; without even the implied warranty of merchantability or fitness for
|
||||
* a particular purpose. See the GNU Lesser General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this code. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package ch.psi.fda.rest;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import com.google.common.eventbus.EventBus;
|
||||
|
||||
import ch.psi.fda.aq.Acquisition;
|
||||
import ch.psi.fda.aq.AcquisitionConfiguration;
|
||||
import ch.psi.fda.model.v1.Configuration;
|
||||
import ch.psi.jcae.ChannelService;
|
||||
|
||||
/**
|
||||
* Main engine for data acquisition.
|
||||
*/
|
||||
public class AcquisitionEngine {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(AcquisitionEngine.class.getName());
|
||||
|
||||
private AcquisitionConfiguration config;
|
||||
private ChannelService cservice;
|
||||
private final ZMQDataService dservice;
|
||||
|
||||
/**
|
||||
* Variable holding the current acquisition
|
||||
*/
|
||||
private volatile Acquisition acquisition;
|
||||
private volatile ExecutionRequest currentRequest;
|
||||
|
||||
private ExecutorService eservice;
|
||||
|
||||
|
||||
private BlockingQueue<ExecutionRequest> requests = new LinkedBlockingQueue<>();
|
||||
|
||||
@Inject
|
||||
public AcquisitionEngine(ChannelService cservice, ZMQDataService dservice, AcquisitionConfiguration config) {
|
||||
this.dservice = dservice;
|
||||
this.cservice = cservice;
|
||||
this.config = config;
|
||||
|
||||
// Start main execution loop
|
||||
eservice = Executors.newSingleThreadExecutor();
|
||||
eservice.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
while (!Thread.currentThread().isInterrupted()) {
|
||||
try {
|
||||
ExecutionRequest r = requests.take();
|
||||
|
||||
logger.info("Execute - " + r.getTrackingId());
|
||||
|
||||
EventBus ebus = new EventBus();
|
||||
// Provide tracking id to data service and register the service to the event bus
|
||||
AcquisitionEngine.this.dservice.setTrackingId(r.getTrackingId());
|
||||
ebus.register(AcquisitionEngine.this.dservice);
|
||||
|
||||
synchronized (AcquisitionEngine.this) { // synchronize access to acquisition object via the AcquisitionEngine object
|
||||
acquisition = new Acquisition(AcquisitionEngine.this.cservice, AcquisitionEngine.this.config);
|
||||
currentRequest = r;
|
||||
}
|
||||
acquisition.initalize(ebus, r.getConfiguration());
|
||||
acquisition.execute();
|
||||
logger.info("" + r.getTrackingId() + " done");
|
||||
|
||||
// Cleanup
|
||||
ebus.unregister(AcquisitionEngine.this.dservice);
|
||||
} finally {
|
||||
acquisition.destroy();
|
||||
|
||||
synchronized (AcquisitionEngine.this) {
|
||||
acquisition = null;
|
||||
currentRequest = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit a scan to be executed. This will generate an execution request which is
|
||||
* enqueued in the execution queue.
|
||||
*
|
||||
* @param configuration
|
||||
* @return
|
||||
*/
|
||||
public String submit(Configuration configuration){
|
||||
ExecutionRequest r = new ExecutionRequest(UUID.randomUUID().toString(), configuration);
|
||||
try{
|
||||
requests.put(r);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
return r.getTrackingId();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Terminate the currently executed request
|
||||
*/
|
||||
public void terminate(){
|
||||
synchronized(this){
|
||||
if(acquisition==null){
|
||||
return;
|
||||
}
|
||||
|
||||
logger.info("Stop current acquisition");
|
||||
acquisition.abort();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Terminate the request which is identified by its tracking id. If the request
|
||||
* is still in the execution queue it gets removed there.
|
||||
* @param trackingId
|
||||
*/
|
||||
public void terminate(String trackingId){
|
||||
|
||||
// If request is currently executed terminate it
|
||||
if(currentRequest.getTrackingId().equals(trackingId)){
|
||||
terminate();
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove request from request queue
|
||||
ExecutionRequest rremove = null;
|
||||
for(ExecutionRequest r:requests){
|
||||
if(r.getTrackingId().equals(trackingId)){
|
||||
rremove = r; // We have to split the filtering and termination as we otherwise get a concurrent access exception.
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(rremove!=null){
|
||||
boolean b = requests.remove(rremove);
|
||||
// There is a chance that between the upper loop and here the request
|
||||
// already got dequeued. This check ensures that the requests got removed
|
||||
// if not it got dequeued and therefore we have to terminate the current
|
||||
// execution.
|
||||
if(!b){
|
||||
terminate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,22 +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.jcae.ChannelService;
|
||||
import ch.psi.jcae.impl.DefaultChannelService;
|
||||
|
||||
public class ResourceBinder extends AbstractBinder {
|
||||
|
||||
@Override
|
||||
protected void configure() {
|
||||
bind(DefaultChannelService.class).to(ChannelService.class).in(Singleton.class);
|
||||
bind(AcquisitionConfiguration.class).to(AcquisitionConfiguration.class).in(Singleton.class);
|
||||
bind(AcquisitionEngine.class).to(AcquisitionEngine.class).in(Singleton.class);
|
||||
bind(ZMQDataService.class).to(ZMQDataService.class).in(Singleton.class);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,49 +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.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
import ch.psi.fda.model.v1.Configuration;
|
||||
import ch.psi.fda.rest.AcquisitionEngine;
|
||||
|
||||
@Path("fda")
|
||||
public class ScanService {
|
||||
|
||||
@Inject
|
||||
private AcquisitionEngine aengine;
|
||||
|
||||
@POST
|
||||
@Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
|
||||
// @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
|
||||
public String execute(Configuration configuration) throws InterruptedException{
|
||||
return aengine.submit(configuration);
|
||||
}
|
||||
|
||||
@DELETE
|
||||
public void stop(){
|
||||
aengine.terminate();
|
||||
}
|
||||
}
|
||||
@@ -1,23 +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.serializer;
|
||||
|
||||
public interface DataSerializer {
|
||||
}
|
||||
@@ -1,197 +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.serializer;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
|
||||
import ch.psi.fda.core.messages.DataMessage;
|
||||
import ch.psi.fda.core.messages.EndOfStreamMessage;
|
||||
import ch.psi.fda.core.messages.Message;
|
||||
import ch.psi.fda.core.messages.Metadata;
|
||||
import ch.psi.fda.core.messages.StreamDelimiterMessage;
|
||||
|
||||
/**
|
||||
* Serialize data received by a DataQueue
|
||||
*/
|
||||
public class DataSerializerTXT implements DataSerializer{
|
||||
|
||||
private static final Logger logger = Logger.getLogger(DataSerializerTXT.class.getName());
|
||||
|
||||
private File file;
|
||||
|
||||
private boolean appendSuffix = true;
|
||||
|
||||
|
||||
private boolean first = true;
|
||||
private File outfile;
|
||||
|
||||
private int icount;
|
||||
private String basename;
|
||||
private String extension;
|
||||
private boolean newfile;
|
||||
private boolean dataInBetween;
|
||||
private BufferedWriter writer;
|
||||
private StringBuffer b;
|
||||
private StringBuffer b1;
|
||||
|
||||
|
||||
/**
|
||||
* @param metadata
|
||||
* @param file
|
||||
* @param appendSuffix Flag whether to append a _0000 suffix after the original file name
|
||||
*/
|
||||
public DataSerializerTXT(File file, boolean appendSuffix){
|
||||
this.file = file;
|
||||
this.appendSuffix = appendSuffix;
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onMessage(Message message){
|
||||
try{
|
||||
if(first){
|
||||
first=false;
|
||||
// Write header
|
||||
|
||||
|
||||
|
||||
icount = 0;
|
||||
newfile = true;
|
||||
dataInBetween = false;
|
||||
writer = null;
|
||||
|
||||
// Get basename of the file
|
||||
basename = this.file.getAbsolutePath(); // Determine file name
|
||||
extension = basename.replaceAll("^.*\\.", ""); // Determine extension
|
||||
basename = basename.replaceAll("\\."+extension+"$", "");
|
||||
}
|
||||
|
||||
if(message instanceof DataMessage){
|
||||
dataInBetween = true;
|
||||
if(newfile){
|
||||
|
||||
b = new StringBuffer();
|
||||
b1 = new StringBuffer();
|
||||
b.append("#");
|
||||
b1.append("#");
|
||||
for(Metadata c: ((DataMessage) message).getMetadata()){
|
||||
|
||||
b.append(c.getId());
|
||||
b.append("\t");
|
||||
|
||||
b1.append(c.getDimension());
|
||||
b1.append("\t");
|
||||
}
|
||||
b.setCharAt(b.length()-1, '\n');
|
||||
b1.setCharAt(b1.length()-1, '\n');
|
||||
|
||||
// Open new file and write header
|
||||
// Construct file name
|
||||
if(appendSuffix){
|
||||
outfile = new File(String.format("%s_%04d.%s", basename, icount, extension));
|
||||
}
|
||||
else{
|
||||
outfile = new File(String.format("%s.%s", basename, extension));
|
||||
}
|
||||
|
||||
// Open file
|
||||
logger.fine("Open new data file: "+outfile.getAbsolutePath());
|
||||
writer = new BufferedWriter(new FileWriter(outfile));
|
||||
|
||||
// Write header
|
||||
writer.write(b.toString());
|
||||
writer.write(b1.toString());
|
||||
|
||||
newfile=false;
|
||||
}
|
||||
|
||||
// Write message to file - each message will result in one line
|
||||
DataMessage m = (DataMessage) message;
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
for(Object o: m.getData()){
|
||||
if(o.getClass().isArray()){
|
||||
// If the array object is of type double[] display its content
|
||||
if(o instanceof double[]){
|
||||
double[] oa = (double[]) o;
|
||||
for(double o1 : oa){
|
||||
buffer.append(o1);
|
||||
buffer.append(" "); // Use space instead of tab
|
||||
}
|
||||
buffer.replace(buffer.length()-1,buffer.length()-1 , "\t"); // Replace last space with tab
|
||||
}
|
||||
else if(o instanceof Object[]){
|
||||
// TODO need to be recursive ...
|
||||
Object[] oa = (Object[])o;
|
||||
for(Object o1 : oa){
|
||||
buffer.append(o1);
|
||||
buffer.append(" "); // Use space instead of tab
|
||||
}
|
||||
buffer.replace(buffer.length()-1,buffer.length()-1 , "\t"); // Replace last space with tab
|
||||
}
|
||||
else{
|
||||
buffer.append("-"); // Not supported
|
||||
}
|
||||
}
|
||||
else{
|
||||
buffer.append(o);
|
||||
buffer.append("\t");
|
||||
}
|
||||
}
|
||||
|
||||
if(buffer.length()>0){
|
||||
buffer.deleteCharAt(buffer.length()-1); // Remove last character (i.e. \t)
|
||||
buffer.append("\n"); // Append newline
|
||||
}
|
||||
writer.write(buffer.toString());
|
||||
}
|
||||
else if(message instanceof StreamDelimiterMessage){
|
||||
StreamDelimiterMessage m = (StreamDelimiterMessage) message;
|
||||
logger.info("Delimiter - number: "+m.getNumber()+" iflag: "+m.isIflag());
|
||||
if(m.isIflag() && appendSuffix){
|
||||
// Only increase iflag counter if there was data in between
|
||||
// subsequent StreamDelimiterMessages.
|
||||
if(dataInBetween){
|
||||
icount++;
|
||||
}
|
||||
dataInBetween = false;
|
||||
|
||||
// Set flag to open new file
|
||||
newfile = true;
|
||||
|
||||
// Close file
|
||||
writer.close();
|
||||
}
|
||||
}
|
||||
else if (message instanceof EndOfStreamMessage){
|
||||
if(writer!=null){
|
||||
// Close file
|
||||
writer.close(); //If the stream was closed previously this has no effect
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Data serializer had a problem writing to the specified file",e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.core.messages.DataMessage;
|
||||
import ch.psi.fda.core.messages.StreamDelimiterMessage;
|
||||
import ch.psi.fda.core.messages.EndOfStreamMessage;
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 &
|
||||
@@ -1,2 +0,0 @@
|
||||
# Load test template
|
||||
dbLoadTemplate("MTEST-PC-FDA_test.subs")
|
||||
@@ -1,5 +0,0 @@
|
||||
file test.template {
|
||||
{
|
||||
P = MTEST-PC-FDA:
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
@@ -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")
|
||||
}
|
||||
@@ -1,146 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* Copyright 2012 Paul Scherrer Institute. All rights reserved.
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Foundation, either version 3 of the License, or (at your option) any
|
||||
* later version.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but without any
|
||||
* warranty; without even the implied warranty of merchantability or fitness for
|
||||
* a particular purpose. See the GNU Lesser General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this code. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package ch.psi.fda.core.loops;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import ch.psi.fda.TestConfiguration;
|
||||
import ch.psi.fda.core.loops.otf.DistributedFile;
|
||||
|
||||
/**
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
public class DistributedFileTest {
|
||||
|
||||
|
||||
private static final Logger logger = Logger.getLogger(DistributedFileTest.class.getName());
|
||||
|
||||
DistributedFile file;
|
||||
DistributedFile smbfile;
|
||||
|
||||
/**
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
file = new DistributedFile("src/test/resources");
|
||||
smbfile = new DistributedFile(TestConfiguration.getInstance().getSmbShare());
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.loops.otf.DistributedFile#getCanonicalPath()}.
|
||||
* @throws IOException
|
||||
*/
|
||||
@Test
|
||||
public void testGetCanonicalPath() throws IOException {
|
||||
logger.info(file.getCanonicalPath());
|
||||
logger.info(smbfile.getCanonicalPath());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.loops.otf.DistributedFile#exists()}.
|
||||
* @throws IOException
|
||||
*/
|
||||
@Test
|
||||
public void testExists() throws IOException {
|
||||
if(!file.exists()){
|
||||
fail("Indicating wrong file status (file actually exists)");
|
||||
}
|
||||
if(!smbfile.exists()){
|
||||
fail("Indicating wrong file status (file actually exists)");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.loops.otf.DistributedFile#isDirectory()}.
|
||||
* @throws IOException
|
||||
*/
|
||||
@Test
|
||||
public void testIsDirectory() throws IOException {
|
||||
if(!file.isDirectory()){
|
||||
fail("Indicating wrong file type (file is directory)");
|
||||
}
|
||||
if(!smbfile.isDirectory()){
|
||||
fail("Indicating wrong file type (file is directory)");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.loops.otf.DistributedFile#listFiles()}.
|
||||
*/
|
||||
@Test
|
||||
public void testListFiles() {
|
||||
// fail("Not yet implemented");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.loops.otf.DistributedFile#getName()}.
|
||||
*/
|
||||
@Test
|
||||
public void testGetName() {
|
||||
logger.info(file.getName());
|
||||
logger.info(smbfile.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.loops.otf.DistributedFile#isFile()}.
|
||||
* @throws IOException
|
||||
*/
|
||||
@Test
|
||||
public void testIsFile() throws IOException {
|
||||
if(file.isFile()){
|
||||
fail("Indicating wrong file type (file is directory)");
|
||||
}
|
||||
if(smbfile.isFile()){
|
||||
fail("Indicating wrong file type (file is directory)");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.loops.otf.DistributedFile#delete()}.
|
||||
*/
|
||||
@Test
|
||||
public void testDelete() {
|
||||
// fail("Not yet implemented");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.loops.otf.DistributedFile#getInputStream()}.
|
||||
*/
|
||||
@Test
|
||||
public void testGetInputStream() {
|
||||
// fail("Not yet implemented");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,229 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful,
|
||||
* but without any warranty; without even the implied warranty of
|
||||
* merchantability or fitness for a particular purpose. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this code. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.psi.fda.core.loops;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
|
||||
import ch.psi.fda.TestConfiguration;
|
||||
import ch.psi.fda.core.loops.otf.OTFLoop;
|
||||
import ch.psi.fda.core.loops.otf.OTFNamedChannelSensor;
|
||||
import ch.psi.fda.core.loops.otf.OTFScalerChannelSensor;
|
||||
import ch.psi.fda.core.loops.otf.TemplateOTF;
|
||||
import ch.psi.fda.core.messages.ControlMessage;
|
||||
import ch.psi.fda.core.messages.DataMessage;
|
||||
import ch.psi.fda.core.messages.Message;
|
||||
import ch.psi.fda.core.sensors.TimestampSensor;
|
||||
import ch.psi.jcae.Channel;
|
||||
import ch.psi.jcae.ChannelDescriptor;
|
||||
import ch.psi.jcae.ChannelException;
|
||||
import ch.psi.jcae.ChannelService;
|
||||
import ch.psi.jcae.impl.DefaultChannelService;
|
||||
|
||||
public class OTFLoopTest {
|
||||
|
||||
private static Logger logger = Logger.getLogger(OTFLoopTest.class.getName());
|
||||
|
||||
private ChannelService cservice;
|
||||
|
||||
|
||||
|
||||
private static final TestConfiguration configuration = TestConfiguration.getInstance();
|
||||
|
||||
|
||||
private OTFLoop loopZigZag;
|
||||
private OTFLoop loop;
|
||||
private Channel<Integer> statusChannel;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
cservice = new DefaultChannelService();
|
||||
statusChannel = cservice.createChannel(new ChannelDescriptor<>(Integer.class, configuration.getOtfPrefix()+":USTAT"));
|
||||
|
||||
OTFScalerChannelSensor s2 = new OTFScalerChannelSensor("id1", 0);
|
||||
OTFScalerChannelSensor s3 = new OTFScalerChannelSensor("id2", 1);
|
||||
TimestampSensor s4 = new TimestampSensor("id3");
|
||||
OTFNamedChannelSensor s5 = new OTFNamedChannelSensor("id4", configuration.getAnalogIn1());
|
||||
|
||||
Map<String, String> macros = new HashMap<>();
|
||||
macros.put("PREFIX", configuration.getOtfPrefix());
|
||||
TemplateOTF template = new TemplateOTF();
|
||||
cservice.createAnnotatedChannels(template, macros);
|
||||
|
||||
|
||||
// ZigZag loop
|
||||
loopZigZag = new OTFLoop(template, configuration.getServer(), configuration.getShare(), configuration.getSmbShare(), true);
|
||||
loopZigZag.setActuator("id0", configuration.getMotor1(), null, 0, 8, 0.5, 0.5, 0);
|
||||
loopZigZag.getSensors().add(s2);
|
||||
loopZigZag.getSensors().add(s3);
|
||||
loopZigZag.getSensors().add(s4);
|
||||
loopZigZag.getSensors().add(s5);
|
||||
|
||||
|
||||
// Normal loop
|
||||
loop = new OTFLoop(template, configuration.getServer(), configuration.getShare(), configuration.getSmbShare(), false);
|
||||
loop.setActuator("id0", configuration.getMotor1(), null, 0, 8, 0.5, 0.5, 0);
|
||||
loop.getSensors().add(s2);
|
||||
loop.getSensors().add(s3);
|
||||
loop.getSensors().add(s4);
|
||||
loop.getSensors().add(s5);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
cservice.destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.loops.otf.OTFLoop#execute()}.
|
||||
* Test ordinary 1D OTF scan
|
||||
* @throws ExecutionException
|
||||
* @throws ChannelException
|
||||
* @throws TimeoutException
|
||||
* @throws CAException
|
||||
*/
|
||||
@Test
|
||||
public void testExecute() throws InterruptedException, TimeoutException, ChannelException, ExecutionException {
|
||||
|
||||
Object l = new Object(){
|
||||
boolean first = true;
|
||||
@Subscribe
|
||||
public void onMessage(DataMessage m) {
|
||||
if(first){
|
||||
first = false;
|
||||
|
||||
int numberOfSensors = 5;
|
||||
if(m.getMetadata().size() != numberOfSensors){
|
||||
fail("Loop returned wrong number of components inside the data message metadata");
|
||||
}
|
||||
|
||||
boolean fail = false;
|
||||
for(int x=0;x<numberOfSensors; x++){
|
||||
if(! m.getMetadata().get(x).getId().equals("id"+x)){
|
||||
fail = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(fail){
|
||||
fail("Ids of the component metadata elements inside the data message metadata is not correct");
|
||||
}
|
||||
}
|
||||
logger.info(m.toString());
|
||||
}
|
||||
};
|
||||
|
||||
loop.getEventBus().register(l);
|
||||
|
||||
loop.prepare();
|
||||
loop.execute();
|
||||
loop.cleanup();
|
||||
|
||||
if(statusChannel.getValue()!=1){
|
||||
fail("OTF C Logic status is not on INACTIVE");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.loops.otf.OTFLoop#execute()}.
|
||||
* Test OTF ZigZag mode
|
||||
* @throws ExecutionException
|
||||
* @throws ChannelException
|
||||
* @throws TimeoutException
|
||||
* @throws CAException
|
||||
*/
|
||||
@Test
|
||||
public void testExecuteZigZag() throws InterruptedException, TimeoutException, ChannelException, ExecutionException {
|
||||
|
||||
loopZigZag.getEventBus().register(new TestCollector());
|
||||
|
||||
loopZigZag.prepare();
|
||||
|
||||
loopZigZag.execute();
|
||||
loopZigZag.execute();
|
||||
|
||||
loopZigZag.cleanup();
|
||||
|
||||
if(statusChannel.getValue()!=1){
|
||||
fail("OTF C Logic status is not on INACTIVE");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.loops.otf.OTFLoop#execute()}.
|
||||
* Test abort functionality while executing an OTF scan
|
||||
* @throws ExecutionException
|
||||
* @throws ChannelException
|
||||
* @throws TimeoutException
|
||||
* @throws CAException
|
||||
*/
|
||||
@Test
|
||||
public void testExecuteAbort() throws InterruptedException, TimeoutException, ChannelException, ExecutionException {
|
||||
|
||||
loop.getEventBus().register(new TestCollector());
|
||||
|
||||
// Thread to simulate asynchronous abort operation
|
||||
Thread t1 = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Thread.sleep(6000); // Wait some seconds before aborting the loop
|
||||
loop.abort();
|
||||
} catch (InterruptedException e) {
|
||||
logger.log(Level.SEVERE, "An Exception occured while testing the abort functionality", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
t1.start();
|
||||
|
||||
loop.prepare();
|
||||
|
||||
loop.execute();
|
||||
|
||||
loop.cleanup();
|
||||
|
||||
if(statusChannel.getValue()!=1){
|
||||
fail("OTF C Logic status is not on INACTIVE");
|
||||
}
|
||||
}
|
||||
|
||||
class TestCollector {
|
||||
@Subscribe
|
||||
public void onMessage(Message m) {
|
||||
if (m instanceof DataMessage) {
|
||||
DataMessage x = (DataMessage) m;
|
||||
logger.info(x.toString());
|
||||
} else if (m instanceof ControlMessage) {
|
||||
logger.info("---- " + m.toString() + " ----");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,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.core.messages.DataMessage;
|
||||
import ch.psi.fda.core.messages.EndOfStreamMessage;
|
||||
import ch.psi.fda.core.messages.Message;
|
||||
import ch.psi.fda.core.messages.Metadata;
|
||||
|
||||
public class ParallelCrlogicStreamMergeTest {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(ParallelCrlogicStreamMergeTest.class.getName());
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMerge() throws InterruptedException {
|
||||
|
||||
List<Metadata> dmm = new ArrayList<>();
|
||||
dmm.add(new Metadata("cractuator"));
|
||||
dmm.add(new Metadata("tstamp"));
|
||||
|
||||
BlockingQueue<Message> dataQueue = new LinkedBlockingQueue<Message>();
|
||||
DataMessage dm = new DataMessage(dmm);
|
||||
dm.getData().add(0.0035d);
|
||||
dm.getData().add(10.000000123);
|
||||
dataQueue.add(dm);
|
||||
|
||||
dm = new DataMessage(dmm);
|
||||
dm.getData().add(0.015);
|
||||
dm.getData().add(10.000000143);
|
||||
dataQueue.add(dm);
|
||||
|
||||
dm = new DataMessage(dmm);
|
||||
dm.getData().add(0.026);
|
||||
dm.getData().add(10.000000163);
|
||||
dataQueue.add(dm);
|
||||
|
||||
dataQueue.add(new EndOfStreamMessage());
|
||||
|
||||
|
||||
List<Metadata> dmm2 = new ArrayList<>();
|
||||
dmm2.add(new Metadata("milli"));
|
||||
dmm2.add(new Metadata("nano"));
|
||||
dmm2.add(new Metadata("sensor1"));
|
||||
|
||||
BlockingQueue<Message> dataQueue2 = new LinkedBlockingQueue<Message>();
|
||||
DataMessage dm2 = new DataMessage(dmm2);
|
||||
dm2.getData().add(9000d);
|
||||
dm2.getData().add(122d);
|
||||
dm2.getData().add(0.1d);
|
||||
dataQueue2.add(dm2);
|
||||
|
||||
dm2 = new DataMessage(dmm2);
|
||||
dm2.getData().add(10000d);
|
||||
dm2.getData().add(122d);
|
||||
dm2.getData().add(1d);
|
||||
dataQueue2.add(dm2);
|
||||
|
||||
dm2 = new DataMessage(dmm2);
|
||||
dm2.getData().add(10000d);
|
||||
dm2.getData().add(153d);
|
||||
dm2.getData().add(2d);
|
||||
dataQueue2.add(dm2);
|
||||
|
||||
dm2 = new DataMessage(dmm2);
|
||||
dm2.getData().add(10000d);
|
||||
dm2.getData().add(162d);
|
||||
dm2.getData().add(3d);
|
||||
dataQueue2.add(dm2);
|
||||
|
||||
dataQueue2.add(new EndOfStreamMessage());
|
||||
|
||||
EventBus b = new EventBus();
|
||||
b.register(new Object(){
|
||||
@Subscribe
|
||||
public void onMessage(Message m){
|
||||
logger.info(m.toString());
|
||||
}
|
||||
});
|
||||
ParallelCrlogicStreamMerge streamMerge = new ParallelCrlogicStreamMerge(dataQueue, dataQueue2, b);
|
||||
streamMerge.merge();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
# Specify the handlers to create in the root logger
|
||||
##handlers = java.util.logging.ConsoleHandler, java.util.logging.FileHandler
|
||||
handlers = java.util.logging.ConsoleHandler
|
||||
|
||||
# Set the default logging level for the root logger
|
||||
.level=ALL
|
||||
|
||||
# Set the default logging level for new ConsoleHandler instances
|
||||
java.util.logging.ConsoleHandler.level=ALL
|
||||
|
||||
# Set the default formatter for new ConsoleHandler instances
|
||||
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
|
||||
|
||||
# Set the default logging level for new FileHandler instances
|
||||
##java.util.logging.FileHandler.level=ALL
|
||||
|
||||
# Set the default formatter for new ConsoleHandler instances
|
||||
##java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter
|
||||
|
||||
# Naming of the output file:
|
||||
##java.util.logging.FileHandler.pattern=/Users/ebner/Workspace/Eclipse/workspace-xasec/ch.psi.x10/resources/logs/fda-%u.%g.log
|
||||
|
||||
# Limiting size of output file in bytes (10000kb):
|
||||
##java.util.logging.FileHandler.limit=10000000
|
||||
|
||||
# Number of output files to cycle through, by appending an
|
||||
# integer to the base file name:
|
||||
##java.util.logging.FileHandler.count=10
|
||||
|
||||
# Set the default logging level for the logger named com.mycompany
|
||||
ch.psi.fda.level=ALL
|
||||
com.cosylab.epics.level=ALL
|
||||
@@ -1,4 +0,0 @@
|
||||
# Test properties file
|
||||
ch.psi.jcae.ContextFactory.addressList=129.129.130.255 129.129.130.37 129.129.145.26 129.129.130.88 129.129.130.142
|
||||
|
||||
ch.psi.jcae.ChannelBeanFactory.retries=4
|
||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
6
gradle/wrapper/gradle-wrapper.properties
vendored
Normal 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
@@ -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
@@ -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
|
||||
|
Before Width: | Height: | Size: 9.7 KiB After Width: | Height: | Size: 9.7 KiB |
|
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 45 KiB |
|
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 51 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
54
src/main/assembly/assembly.xml
Normal file
@@ -0,0 +1,54 @@
|
||||
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
|
||||
|
||||
|
||||
<id>bin</id>
|
||||
<!-- Generates a zip package containing the needed files -->
|
||||
<formats>
|
||||
<format>zip</format>
|
||||
</formats>
|
||||
|
||||
<!-- Adds dependencies to zip package under lib directory -->
|
||||
<dependencySets>
|
||||
<dependencySet>
|
||||
<outputDirectory>lib</outputDirectory>
|
||||
<unpack>false</unpack>
|
||||
</dependencySet>
|
||||
</dependencySets>
|
||||
|
||||
<fileSets>
|
||||
<!-- Adds startup scripts to the root directory of zip package -->
|
||||
<fileSet>
|
||||
<fileMode>0755</fileMode>
|
||||
<directory>src/main/assembly/bin</directory>
|
||||
<outputDirectory>bin</outputDirectory>
|
||||
<includes>
|
||||
<include>*</include>
|
||||
</includes>
|
||||
</fileSet>
|
||||
<!-- <fileSet>
|
||||
<directory>src/main/assembly/www</directory>
|
||||
<outputDirectory>www</outputDirectory>
|
||||
<includes>
|
||||
<include>**/*</include>
|
||||
</includes>
|
||||
</fileSet> -->
|
||||
<!-- <fileSet>
|
||||
<fileMode>0755</fileMode>
|
||||
<directory>src/main/assembly/var</directory>
|
||||
<outputDirectory>var</outputDirectory>
|
||||
<includes>
|
||||
<include>**/*</include>
|
||||
</includes>
|
||||
</fileSet> -->
|
||||
<!-- adds jar package to the root directory of zip package -->
|
||||
<!-- <fileSet>
|
||||
<directory>target</directory>
|
||||
<outputDirectory></outputDirectory>
|
||||
<includes>
|
||||
<include>*.jar</include>
|
||||
</includes>
|
||||
</fileSet> -->
|
||||
</fileSets>
|
||||
</assembly>
|
||||
40
src/main/assembly/bin/convert
Normal 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 -cp $CLASSPATH -Djava.util.logging.config.file=${APPLICATION_HOME}/config/logging.properties $VM_ARGUMENTS ch.psi.fda.ui.ConversionMain $ARGUMENTS
|
||||
40
src/main/assembly/bin/scan
Normal 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.RemoteAcquisitionMain $ARGUMENTS
|
||||
40
src/main/assembly/bin/scan_local
Normal 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
|
||||
42
src/main/assembly/bin/server
Normal file
@@ -0,0 +1,42 @@
|
||||
#!/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
|
||||
|
||||
|
||||
#HUB_BASE=$BASEDIR/../
|
||||
#export HUB_BASE
|
||||
java $VM_ARGUMENTS -cp $CLASSPATH -Dch.psi.fda.home=${APPLICATION_HOME} -Djava.util.logging.config.file=${APPLICATION_HOME}/config/logging.properties ch.psi.fda.rest.FdaServer $ARGUMENTS
|
||||
40
src/main/assembly/bin/viewer
Normal 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 -cp $CLASSPATH -Djava.util.logging.config.file=${APPLICATION_HOME}/config/logging.properties $VM_ARGUMENTS ch.psi.fda.ui.VisualizationZMQMain $ARGUMENTS
|
||||
40
src/main/assembly/bin/visualize
Normal 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 -cp $CLASSPATH -Djava.util.logging.config.file=${APPLICATION_HOME}/config/logging.properties $VM_ARGUMENTS ch.psi.fda.ui.VisualizationMain $ARGUMENTS
|
||||
BIN
src/main/assembly/www/apple-touch-icon-114x114-precomposed.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
src/main/assembly/www/apple-touch-icon-144x144-precomposed.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
src/main/assembly/www/apple-touch-icon-57x57-precomposed.png
Normal file
|
After Width: | Height: | Size: 730 B |
BIN
src/main/assembly/www/apple-touch-icon-72x72-precomposed.png
Normal file
|
After Width: | Height: | Size: 854 B |
BIN
src/main/assembly/www/apple-touch-icon-precomposed.png
Normal file
|
After Width: | Height: | Size: 730 B |
BIN
src/main/assembly/www/apple-touch-icon.png
Normal file
|
After Width: | Height: | Size: 730 B |
1109
src/main/assembly/www/css/bootstrap-responsive.css
vendored
Normal file
9
src/main/assembly/www/css/bootstrap-responsive.min.css
vendored
Normal file
6158
src/main/assembly/www/css/bootstrap.css
vendored
Normal file
9
src/main/assembly/www/css/bootstrap.min.css
vendored
Normal file
22
src/main/assembly/www/css/main.css
Normal file
@@ -0,0 +1,22 @@
|
||||
|
||||
|
||||
/* ==========================================================================
|
||||
Author's custom styles
|
||||
========================================================================== */
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
BIN
src/main/assembly/www/favicon.ico
Normal file
|
After Width: | Height: | Size: 766 B |
BIN
src/main/assembly/www/img/glyphicons-halflings-white.png
Normal file
|
After Width: | Height: | Size: 8.6 KiB |
BIN
src/main/assembly/www/img/glyphicons-halflings.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
222
src/main/assembly/www/index.html
Normal 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> - © 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>
|
||||
6
src/main/assembly/www/js/jquery-2.0.0.min.js
vendored
Normal file
1
src/main/assembly/www/js/main.js
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
2268
src/main/assembly/www/js/vendor/bootstrap.js
vendored
Normal file
6
src/main/assembly/www/js/vendor/bootstrap.min.js
vendored
Normal file
5
src/main/assembly/www/js/vendor/jquery-1.9.1.min.js
vendored
Normal file
11
src/main/assembly/www/js/vendor/modernizr-2.6.2-respond-1.1.0.min.js
vendored
Normal file
17
src/main/java/ch/psi/fda/DescriptorProvider.java
Normal 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();
|
||||
|
||||
}
|
||||
28
src/main/java/ch/psi/fda/EContainer.java
Normal 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();
|
||||
|
||||
}
|
||||
22
src/main/java/ch/psi/fda/EContainerFactory.java
Normal 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);
|
||||
}
|
||||
@@ -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;
|
||||
@@ -106,7 +102,7 @@ import ch.psi.fda.model.v1.SimpleScalarDetector;
|
||||
import ch.psi.fda.model.v1.Timestamp;
|
||||
import ch.psi.fda.model.v1.Variable;
|
||||
import ch.psi.fda.model.v1.VariableParameterMapping;
|
||||
import ch.psi.fda.serializer.DataSerializerTXT;
|
||||
import ch.psi.fda.serializer.SerializerTXT;
|
||||
import ch.psi.jcae.Channel;
|
||||
import ch.psi.jcae.ChannelDescriptor;
|
||||
import ch.psi.jcae.ChannelException;
|
||||
@@ -119,8 +115,6 @@ import ch.psi.jcae.util.ComparatorREGEX;
|
||||
/**
|
||||
* Data acquisition engine for performing scans
|
||||
* Mapping is specific to scan model version 1.0
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
public class Acquisition {
|
||||
|
||||
@@ -130,7 +124,7 @@ public class Acquisition {
|
||||
|
||||
private ActionLoop actionLoop;
|
||||
private Manipulator manipulator;
|
||||
private DataSerializerTXT serializer;
|
||||
private SerializerTXT serializer;
|
||||
|
||||
private List<Manipulation> manipulations;
|
||||
private volatile boolean active = false;
|
||||
@@ -233,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);
|
||||
@@ -250,7 +248,7 @@ public class Acquisition {
|
||||
b.register(this.manipulator);
|
||||
|
||||
|
||||
this.serializer = new DataSerializerTXT(datafile, true);
|
||||
this.serializer = new SerializerTXT(datafile, true);
|
||||
bus.register(serializer);
|
||||
}
|
||||
else{
|
||||
@@ -259,7 +257,7 @@ public class Acquisition {
|
||||
mapScan(collector, smodel);
|
||||
// col = collector;
|
||||
|
||||
this.serializer = new DataSerializerTXT(datafile, true);
|
||||
this.serializer = new SerializerTXT(datafile, true);
|
||||
bus.register(serializer);
|
||||
}
|
||||
}
|
||||
@@ -269,7 +267,13 @@ public class Acquisition {
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public void execute() throws InterruptedException {
|
||||
|
||||
String hostname;
|
||||
try {
|
||||
hostname = InetAddress.getLocalHost().getHostName();
|
||||
} catch (UnknownHostException e) {
|
||||
hostname="unknown";
|
||||
}
|
||||
|
||||
try{
|
||||
active = true;
|
||||
|
||||
@@ -277,38 +281,16 @@ public class Acquisition {
|
||||
actionLoop.execute();
|
||||
actionLoop.cleanup();
|
||||
|
||||
// Send notifications out to all recipients that want to have success notifications
|
||||
try {
|
||||
String hostname = InetAddress.getLocalHost().getHostName();
|
||||
notificationAgent.sendNotification("Notification - FDA Execution Finished", "The execution of the FDA on '"+hostname+"' for file '"+datafile.getName()+"' finished successfully\n\nYou received this message because you are listed in the notification list for this data acquisition configuration.", false,true);
|
||||
} catch (UnknownHostException e1) {
|
||||
logger.log(Level.WARNING, "Unable to send notification", e1);
|
||||
}
|
||||
notificationAgent.sendNotification("Notification - FDA Execution Finished", "The execution of the FDA on '"+hostname+"' for file '"+datafile.getName()+"' finished successfully\n\nYou received this message because you are listed in the notification list for this data acquisition configuration.", false,true);
|
||||
}
|
||||
catch(RuntimeException e){
|
||||
logger.log(Level.WARNING, "Execution failed: ", e);
|
||||
|
||||
try {
|
||||
String hostname = InetAddress.getLocalHost().getHostName();
|
||||
notificationAgent.sendNotification("Notification - FDA Execution Failed", "The execution of the FDA failed on '"+hostname+"' for file '"+datafile.getName()+"'\n\nYou received this message because you are listed in the notification list for this data acquisition configuration.", true,false);
|
||||
} catch (UnknownHostException e1) {
|
||||
logger.log(Level.WARNING, "Unable to send notification", e1);
|
||||
}
|
||||
|
||||
notificationAgent.sendNotification("Notification - FDA Execution Failed", "The execution of the FDA failed on '"+hostname+"' for file '"+datafile.getName()+"'\n\nYou received this message because you are listed in the notification list for this data acquisition configuration.", true,false);
|
||||
throw e;
|
||||
}
|
||||
catch(InterruptedException e){
|
||||
logger.log(Level.WARNING, "Execution interrupted: ", e);
|
||||
|
||||
// Execution got aborted.
|
||||
try {
|
||||
String hostname = InetAddress.getLocalHost().getHostName();
|
||||
notificationAgent.sendNotification("Notification - FDA Execution was aborted", "The execution of the FDA on '"+hostname+"' for file '"+datafile.getName()+"' was aborted\n\nYou received this message because you are listed in the notification list for this data acquisition configuration.", false, true);
|
||||
} catch (UnknownHostException e1) {
|
||||
logger.log(Level.WARNING, "Unable to send notification", e1);
|
||||
}
|
||||
// throw e;
|
||||
|
||||
notificationAgent.sendNotification("Notification - FDA Execution was aborted", "The execution of the FDA on '"+hostname+"' for file '"+datafile.getName()+"' was aborted\n\nYou received this message because you are listed in the notification list for this data acquisition configuration.", false, true);
|
||||
}
|
||||
finally{
|
||||
active = false;
|
||||
@@ -340,10 +322,6 @@ public class Acquisition {
|
||||
// Clear global variables Jython
|
||||
jVariableDictionary.clear();
|
||||
|
||||
// // Destroy the CA context
|
||||
// cservice.destroy();
|
||||
// logger.fine("ChannelService destroyed");
|
||||
|
||||
// Remove log handler
|
||||
if(logHandler!=null){
|
||||
logger.fine("Close log handler");
|
||||
@@ -352,15 +330,8 @@ public class Acquisition {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Abort acquisition
|
||||
*/
|
||||
public void abort(){
|
||||
|
||||
actionLoop.abort();
|
||||
// if(acquisitionThread!=null){
|
||||
// acquisitionThread.interrupt();
|
||||
// }
|
||||
}
|
||||
|
||||
public String getDatafileName(){
|
||||
@@ -399,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());
|
||||
@@ -979,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;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1149,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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
package ch.psi.fda.aq;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
@@ -29,27 +30,15 @@ import java.util.logging.Logger;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import ch.psi.fda.install.ApplicationConfigurator;
|
||||
|
||||
/**
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
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
|
||||
@@ -77,27 +66,21 @@ public class AcquisitionConfiguration {
|
||||
* The constructor will read the configuration from the /fda.properties file (resource) located in the classpath.
|
||||
*/
|
||||
public AcquisitionConfiguration(){
|
||||
loadConfiguration();
|
||||
}
|
||||
|
||||
|
||||
public void loadConfiguration(){
|
||||
loadConfiguration(null);
|
||||
loadConfiguration(System.getProperty(FDA_CONFIG_FILE));
|
||||
}
|
||||
|
||||
/**
|
||||
* Load configuration from properties file
|
||||
*/
|
||||
public void loadConfiguration(String file) {
|
||||
if(file == null){
|
||||
file = System.getProperty(FDA_CONFIG_FILE);
|
||||
}
|
||||
Properties properties = new Properties();
|
||||
|
||||
File cfile = null;
|
||||
// Only read in the property file if a file is specified
|
||||
if(file != null){
|
||||
cfile = new File(file);
|
||||
try {
|
||||
properties.load(new FileReader(file));
|
||||
properties.load(new FileReader(cfile));
|
||||
} catch (FileNotFoundException e) {
|
||||
throw new RuntimeException("Configuration file "+file+" not found", e);
|
||||
} catch (IOException e) {
|
||||
@@ -109,25 +92,16 @@ 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", "");
|
||||
crlogicPrefix = properties.getProperty(AcquisitionConfiguration.class.getPackage().getName()+".crlogic.prefix", "");
|
||||
crlogicIoc= properties.getProperty(AcquisitionConfiguration.class.getPackage().getName()+".crlogic.ioc", "");
|
||||
|
||||
otfUseCrlogic = new Boolean(properties.getProperty(AcquisitionConfiguration.class.getPackage().getName()+".otf.useCrlogic", "false"));
|
||||
otfCrlogicPrefix = properties.getProperty(AcquisitionConfiguration.class.getPackage().getName()+".otf.crlogicPrefix", "");
|
||||
otfCrlogicKeepTmpFiles = new Boolean(properties.getProperty(AcquisitionConfiguration.class.getPackage().getName()+".otf.crlogicKeepTmpFiles", "false"));
|
||||
|
||||
if(System.getProperty(ApplicationConfigurator.FDA_HOME_ARGUMENT)!=null){ // TODO remove
|
||||
dataBaseDirectory = System.getProperty(ApplicationConfigurator.FDA_HOME_ARGUMENT)+"/data";
|
||||
dataBaseDirectory = properties.getProperty(AcquisitionConfiguration.class.getPackage().getName()+".data.dir",".");
|
||||
if(cfile!=null && dataBaseDirectory.matches("^\\.\\.?/.*")){ // if basedir starts with . or .. we assume the data directory to be relative to the directory of the configuration file
|
||||
dataBaseDirectory = cfile.getParentFile().getAbsolutePath()+"/"+dataBaseDirectory;
|
||||
}
|
||||
else{
|
||||
dataBaseDirectory = "./data";
|
||||
}
|
||||
|
||||
dataFilePrefix = properties.getProperty(AcquisitionConfiguration.class.getPackage().getName()+".data.filePrefix","");
|
||||
|
||||
|
||||
actorMoveTimeout = new Long(properties.getProperty(AcquisitionConfiguration.class.getPackage().getName()+".actorMoveTimeout","600000"));
|
||||
|
||||
smptServer= properties.getProperty(AcquisitionConfiguration.class.getPackage().getName()+".notification.host","mail.psi.ch");
|
||||
@@ -162,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;
|
||||
@@ -259,5 +184,4 @@ public class AcquisitionConfiguration {
|
||||
public void setSmptServer(String smptServer) {
|
||||
this.smptServer = smptServer;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -25,11 +25,11 @@ import java.util.List;
|
||||
import com.google.common.eventbus.EventBus;
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
|
||||
import ch.psi.fda.core.messages.DataMessage;
|
||||
import ch.psi.fda.core.messages.Metadata;
|
||||
import ch.psi.fda.core.messages.StreamDelimiterMessage;
|
||||
import ch.psi.fda.core.messages.EndOfStreamMessage;
|
||||
import ch.psi.fda.core.messages.Message;
|
||||
import ch.psi.fda.messages.DataMessage;
|
||||
import ch.psi.fda.messages.EndOfStreamMessage;
|
||||
import ch.psi.fda.messages.Message;
|
||||
import ch.psi.fda.messages.Metadata;
|
||||
import ch.psi.fda.messages.StreamDelimiterMessage;
|
||||
|
||||
/**
|
||||
* Collector class that is collecting and merging data from different Queues.
|
||||
@@ -26,9 +26,9 @@ import com.google.common.eventbus.EventBus;
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
|
||||
import ch.psi.fda.core.Manipulation;
|
||||
import ch.psi.fda.core.messages.DataMessage;
|
||||
import ch.psi.fda.core.messages.Message;
|
||||
import ch.psi.fda.core.messages.Metadata;
|
||||
import ch.psi.fda.messages.DataMessage;
|
||||
import ch.psi.fda.messages.Message;
|
||||
import ch.psi.fda.messages.Metadata;
|
||||
|
||||
/**
|
||||
* Applies manipulations to the data stream
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
50
src/main/java/ch/psi/fda/aq/XScanContainer.java
Normal 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();
|
||||
}
|
||||
}
|
||||
29
src/main/java/ch/psi/fda/aq/XScanDescriptor.java
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -1,114 +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;
|
||||
|
||||
/**
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
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());
|
||||
|
||||
}
|
||||
|
||||
public static List<SeriesDataFilter> mapVisualizations(List<Visualization> vl){
|
||||
List<SeriesDataFilter> filters = new ArrayList<SeriesDataFilter>();
|
||||
/**
|
||||
* Create a vdescriptor out of the scan description
|
||||
* @param vl
|
||||
* @return
|
||||
*/
|
||||
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){
|
||||
|
||||
@@ -178,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
|
||||
@@ -254,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;
|
||||
}
|
||||
|
||||
}
|
||||
36
src/main/java/ch/psi/fda/aq/XScanFactory.java
Normal 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());
|
||||
}
|
||||
|
||||
}
|
||||
151
src/main/java/ch/psi/fda/cdump/Cdump.java
Normal 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;
|
||||
}
|
||||
}
|
||||
87
src/main/java/ch/psi/fda/cdump/CdumpConfiguration.java
Normal 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;
|
||||
}
|
||||
}
|
||||
73
src/main/java/ch/psi/fda/cdump/CdumpEContainer.java
Normal 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();
|
||||
}
|
||||
|
||||
}
|
||||
26
src/main/java/ch/psi/fda/cdump/CdumpEContainerFactory.java
Normal 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);
|
||||
}
|
||||
}
|
||||
25
src/main/java/ch/psi/fda/cdump/CdumpEDescriptor.java
Normal 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;
|
||||
}
|
||||
}
|
||||
44
src/main/java/ch/psi/fda/cdump/CdumpEDescriptorProvider.java
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
102
src/main/java/ch/psi/fda/cdump/CdumpListener.java
Normal 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());
|
||||
}
|
||||
}
|
||||
107
src/main/java/ch/psi/fda/cdump/ui/CdumpMain.java
Normal 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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -21,8 +21,8 @@ package ch.psi.fda.core;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import ch.psi.fda.core.messages.DataMessage;
|
||||
import ch.psi.fda.core.messages.Metadata;
|
||||
import ch.psi.fda.messages.DataMessage;
|
||||
import ch.psi.fda.messages.Metadata;
|
||||
|
||||
public interface Manipulation {
|
||||
|
||||
@@ -16,25 +16,21 @@
|
||||
* along with this code. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package ch.psi.fda;
|
||||
package ch.psi.fda.core;
|
||||
|
||||
/**
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
public class TestConfiguration {
|
||||
private static final TestConfiguration instance = new TestConfiguration();
|
||||
|
||||
private final String otfPrefix = "MTEST-HW3-OTFX";
|
||||
private final String crlogicPrefix = "MTEST-HW3-CRL";
|
||||
private final String prefixScaler = "MTEST-HW3:JS";
|
||||
private final String server = "yoke.psi.ch";
|
||||
private final String share = "/usr/nfs";
|
||||
private final String smbShare = "smb://test:test@"+server+"/nfs/"; // It is important to have the last slash / !
|
||||
private final String server = "MTEST-VME-HW3";
|
||||
|
||||
private final String motor1 = "MTEST-HW3:MOT1";
|
||||
private final String analogIn1 = "MTEST-HW3-AI1:AI_01";
|
||||
|
||||
private final String ioc = "MTEST-VME-HW3.psi.ch";
|
||||
|
||||
private TestConfiguration(){
|
||||
}
|
||||
|
||||
@@ -63,20 +59,6 @@ public class TestConfiguration {
|
||||
return server;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the share
|
||||
*/
|
||||
public String getShare() {
|
||||
return share;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the smbShare
|
||||
*/
|
||||
public String getSmbShare() {
|
||||
return smbShare;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the motor1
|
||||
*/
|
||||
@@ -98,5 +80,8 @@ public class TestConfiguration {
|
||||
return otfPrefix;
|
||||
}
|
||||
|
||||
public String getIoc() {
|
||||
return ioc;
|
||||
}
|
||||
|
||||
}
|
||||