123 Commits

Author SHA1 Message Date
f2e3bf23e8 Added an release notes file 2014-08-07 14:28:07 +02:00
f39822ec74 updated referenced library 2014-07-28 16:29:25 +02:00
5038912472 updated pom deploy url 2014-07-28 12:38:34 +02:00
8ab87b8332 Updated version ... 2014-07-28 11:13:23 +02:00
8f698e82ba upgraded xscan version 2014-05-12 11:40:15 +02:00
58e92684ad Updated version 2014-05-12 11:17:19 +02:00
5a6396cfb7 Added initial administration web page. 2014-05-09 09:29:41 +02:00
57ecb121b2 improved return values ... 2014-05-06 16:14:21 +02:00
3ce7282214 Improved logging 2014-05-06 13:50:50 +02:00
16d18288b6 improved termination of the execution container 2014-05-06 13:15:51 +02:00
76ce595f87 removed author comment 2014-04-30 07:51:53 +02:00
486d11db2b Finished cleanup 2014-04-30 07:45:16 +02:00
fa2416492e Refactored test packages 2014-04-30 07:34:31 +02:00
db097eba8f added new startup script 2014-04-30 07:29:33 +02:00
838f6fd385 moved classes to ui package 2014-04-30 07:28:14 +02:00
1c9eca2a1c handle end of stream correctly 2014-04-30 07:27:43 +02:00
f30aa6495f refactored classes 2014-04-30 07:17:06 +02:00
a15356190d moved classes 2014-04-30 07:07:33 +02:00
88f4dd2b19 cleaned up configuraiton management and startup scripts 2014-04-30 07:00:25 +02:00
9f4c6c0356 re-organized some stuff ... 2014-04-29 11:44:10 +02:00
84fb119932 cleaned up cleanup procedure 2014-04-29 11:26:22 +02:00
311eae3cbc changes ... 2014-04-29 11:06:21 +02:00
9529d7f088 Renamed classes to better represent what they are doing 2014-04-29 10:34:26 +02:00
e597b5cd12 stuff 2014-04-28 16:06:10 +02:00
8ab6f7965b moved to correct package 2014-04-28 13:57:40 +02:00
4bb984cc1c Removed lots of stuff from the project 2014-04-28 13:56:52 +02:00
b64f31e778 some more cleanups and fixes
-- however still lots of bugs in there !
2014-04-28 11:46:36 +02:00
43a8347924 added gitignore file 2014-04-25 12:44:22 +02:00
f520ff4337 removed xmlscan based classes and imported ch.psi.fda.xscan library
instead
2014-04-25 12:39:49 +02:00
5995b2ed5c use of edescriptor also for the server/client setup of FDA 2014-04-22 08:43:14 +02:00
e20cab4874 Fixed viewer 2014-04-16 08:43:58 +02:00
576d7eb048 Refactored visualizer to support vdescriptor 2014-04-16 08:34:24 +02:00
21f86d7d69 Updated provider to also generate a vdescriptor 2014-04-14 13:14:45 +02:00
aa1681aaf3 Cleaned messed up stuff 2014-04-11 16:15:38 +02:00
da182adcd2 updated edescriptor thingi 2014-04-11 15:47:09 +02:00
8d1bd4e816 moved certain rest related classes 2014-04-10 15:23:15 +02:00
07d6b47885 added injection and fixed shutdown problems 2014-04-10 15:19:39 +02:00
87781b8f06 Added new abstraction layer 2014-04-10 14:11:40 +02:00
28bd7c40d8 removed unused option 2014-04-09 16:27:54 +02:00
dcd394b586 updated readme formatting 2014-04-08 10:11:02 +02:00
76c40ccf28 Made zmq port configureable
Updated Readme.md file
2014-04-08 10:09:05 +02:00
8522d46813 renamed fda script to server and added script to startup the viewer 2014-04-07 15:11:01 +02:00
1077ec8ab3 Added flag to generate serializable model classes (xjb.xjb)
Improved viewer to update/change the plots whenever a new scan starts...
Therefore the visualization configuration is always send before any of
the scan data is sent.
2014-04-07 11:02:40 +02:00
da0e0eab79 Updated to latest fdaq 2014-01-22 13:38:35 +01:00
ac54407e34 upgraded to latest fdaq version 2014-01-22 11:29:23 +01:00
b0d4ef9d8b Made home variable visible 2014-01-21 08:41:07 +01:00
f8ee1bd666 updated readme 2014-01-20 13:30:45 +01:00
8d37cdbeca created all in one jar for gui application. 2014-01-20 13:12:25 +01:00
fbe03b7ade Added tracking id for isActive call 2014-01-20 11:12:20 +01:00
d866fa0eda fixed rest documentation 2014-01-15 16:09:39 +01:00
2b0877c65d Documented fda rest api 2014-01-15 16:08:06 +01:00
d7f1b15927 new package version
FDA-106
FDA-1
2014-01-15 14:31:28 +01:00
35a4949907 Rest server now also takes ch.psi.fda.home variable into account
FDA-106
2014-01-15 13:38:03 +01:00
30355deacc removed setting of java.util.logging.config.file inside this class as
this has no effect!
2014-01-15 13:37:07 +01:00
eb0aa9a1b6 Cleaned up configuration mess 2014-01-15 13:14:56 +01:00
b447ec12d7 FDA-1
Added function to wait for the termination of a request
2014-01-15 11:04:24 +01:00
ae78b8c7a7 Removed unnecessary queue in AcquisitionEngine 2014-01-15 10:15:00 +01:00
c9ff7ccf2c tests ... 2014-01-15 09:05:51 +01:00
c01995675e decreased log level for logging complete message send out by the zmq
streamer
2014-01-14 13:47:05 +01:00
e4885d11e1 added startup scripts: FDA-106
created assembly descriptor for build
Renamed RestServer to FdaServer
2014-01-14 11:39:10 +01:00
407aff2e24 Upgrade fdaq and cdump code dependencies ... 2014-01-14 11:08:59 +01:00
9d6ae89f13 Added TODO comment for reminding that filtering is not yet done 2014-01-09 09:17:27 +01:00
fafea6dc69 FDA-103
Created first version of Cdump REST service
2014-01-09 09:10:25 +01:00
3e841c7596 FDA-102 2014-01-09 08:35:50 +01:00
542379545b Added (singleton) fdaq engine class to be able to unregister the zmq
streamer and to avoid having more than one thing driving the fdaq box
...
2014-01-08 16:30:59 +01:00
4d0f329e72 removed class because of no time to fully implement it ...
will add it later .
2014-01-08 16:11:40 +01:00
488fa5c908 FDA-102
moved request object to rest.model package
2014-01-08 16:10:12 +01:00
d550e59254 Implemented FDAQ REST API and started to with Cdump 2014-01-08 09:58:26 +01:00
685ac0cd2d renamed ScanService to FDAService 2013-12-20 15:25:09 +01:00
9476f9b57c cleaned comments 2013-12-20 14:35:37 +01:00
8888172ede Renamed class RestClient to ControlClient 2013-12-20 14:31:44 +01:00
e324987c8e FDA-1
Improved client - Now multiple clients can submit scans and only the one
submitted the scan will receive the data as well as can abor the scan.
2013-12-20 14:28:32 +01:00
76e9ea1bed FDA-1
Improved server and client
2013-12-20 13:43:16 +01:00
244001fd99 First working (messy) version of client/server split
FDA-1
2013-12-20 08:54:55 +01:00
55faaa2aa3 FDA-1
Improved rest server
2013-12-19 11:23:56 +01:00
ab0d1654c1 fixed pom for artifact upload 2013-12-18 11:09:47 +01:00
726cf9c0ff fixed pom 2013-12-17 15:31:54 +01:00
03c7d84b05 Renamed serializer classes (removed Data prefix)
Moved SerializerTXT to core project
2013-12-17 15:20:53 +01:00
54fb16a0e9 Renamed package from core.messages to messages 2013-12-17 15:18:09 +01:00
f96b85f6d0 Renamed test case 2013-12-17 15:16:44 +01:00
696893ba16 Renamed unnecessary interface DataSerializer
moved messages package into own project
2013-12-17 15:11:38 +01:00
d84ce43676 Update readme 2013-12-17 14:56:59 +01:00
e625185b6d Updated version to 2.0.x
Added Readme.md file - Starting of development documentation
2013-11-27 11:44:48 +01:00
a40573d320 Cleaned up injects, added ZMQ streaming and viewer 2013-11-27 09:55:14 +01:00
70089581c4 First version with asynchronous execution 2013-10-24 10:03:23 +02:00
08cbd0bad0 got first working version of REST server 2013-10-24 08:38:33 +02:00
f4d5102ea3 Implemented REST API and server for executing scans 2013-10-23 15:16:49 +02:00
e483f90837 remove comments 2013-10-23 11:55:41 +02:00
795b269bd0 minor changes 2013-10-21 13:21:01 +02:00
3cb7458e64 removed comment 2013-10-21 12:40:04 +02:00
51d7b36219 Probably fixed CRLOGIC thing as such ... 2013-10-21 11:49:29 +02:00
67e7f9a6c8 fixed scrlogic 2013-10-21 10:59:11 +02:00
491812ddeb fixed otf code 2013-10-21 09:45:06 +02:00
40cc7f6a31 fixed stuff for the new data transfer format 2013-10-21 08:41:22 +02:00
9386f42d06 Somehow works better than before 2013-10-17 08:59:33 +02:00
855535134e Got Visualization work 2013-10-17 07:55:49 +02:00
e2921ff1f4 fixed lots of stuff regarding new message format ... 2013-10-17 07:35:28 +02:00
36cd4335ab Preparation for reworking messaging format 2013-10-16 11:30:38 +02:00
d92534ec37 Removed unnecessary function parameter 2013-10-16 10:54:47 +02:00
ca871ad478 some cleanup in CRLOGIC 2013-10-15 16:13:08 +02:00
b65764ac57 removed injection classes/libraries as not needed 2013-10-15 15:55:47 +02:00
63e681c3bb update version and added configuration for single jar 2013-10-15 15:53:41 +02:00
48cda75405 removed unecessary JythonGlobalVariableDictionary class 2013-10-15 09:40:14 +02:00
4b615d29a6 Cleanup and restructuring notification agent 2013-10-15 08:44:18 +02:00
d8f1e2d8f1 see commit before 2013-10-15 08:26:03 +02:00
768ea9f254 Cleanup Crlogic code 2013-10-14 16:42:00 +02:00
2cba6e7991 Cleanup OTF scan 2013-10-14 16:10:54 +02:00
cb6ec74859 cleanup ... 2013-10-14 13:21:25 +02:00
36f717c8bf more cleanup 2013-10-14 13:06:50 +02:00
716eeba98b cleanup comments 2013-10-14 12:57:21 +02:00
c1c8170f36 Restructuring code 2013-10-14 12:54:57 +02:00
c8031db1fd Cleanup ChannelAccessCondition* classes 2013-10-14 11:31:29 +02:00
a2d9216e84 Removed destroy() method from actuator and action interface 2013-10-14 11:06:55 +02:00
57eca36d27 Cleaned up code
Removed lots of duplicated code, merged classes, etc.
2013-10-14 10:34:40 +02:00
809caa3ed1 Fixed tests 2013-10-09 11:23:34 +02:00
3532f95acb Renamed template files 2013-10-09 09:23:37 +02:00
5d2c2b94d6 Fixed remaining broken tests 2013-10-09 09:15:59 +02:00
2520573d12 Exchanged Channel Access library with latest version
Fixing of the code is still going on!
2013-10-08 16:36:17 +02:00
97ab9fa5b2 Removed unnecessary dependency 2013-10-04 14:39:15 +02:00
debc54a28a do not execute the test case 2013-10-04 14:12:52 +02:00
55ed5ac764 Upgraded mail libraries to latest version 2013-10-04 14:12:18 +02:00
84c86b8d9f cleanup comments 2013-10-04 13:37:03 +02:00
b38654056b minor comments cleanup 2013-10-04 13:22:38 +02:00
196 changed files with 12923 additions and 30197 deletions

View File

@@ -6,7 +6,6 @@
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" path="target/generated-sources/xjc"/>
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
<attributes>
<attribute name="maven.pomderived" value="true"/>

107
ch.psi.fda/Readme.md Normal file
View File

@@ -0,0 +1,107 @@
# 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`

View File

@@ -0,0 +1,2 @@
# 3.0.0
* Update the fda.properties file and replace ch.psi.fda.aq.data.baseDirectory with ch.psi.fda.aq.data.dir.

View File

@@ -3,14 +3,45 @@
<modelVersion>4.0.0</modelVersion>
<groupId>ch.psi</groupId>
<artifactId>fda</artifactId>
<version>1.1.40</version>
<version>2.4.3</version>
<dependencies>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>15.0</version>
<groupId>ch.psi</groupId>
<artifactId>ch.psi.fda.core</artifactId>
<version>2.3.0</version>
</dependency>
<!-- These 3 libraries are just needed for testing -->
<dependency>
<groupId>ch.psi.fda</groupId>
<artifactId>ch.psi.fda.xscan</artifactId>
<version>2.3.2</version>
</dependency>
<dependency>
<groupId>ch.psi</groupId>
<artifactId>ch.psi.fda.cdump</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>ch.psi</groupId>
<artifactId>ch.psi.fda.fdaq</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>ch.psi</groupId>
<artifactId>jcae</artifactId>
<version>2.4.1</version>
</dependency>
<dependency>
<groupId>ch.psi</groupId>
<artifactId>plot</artifactId>
<version>1.1.31</version>
</dependency>
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
@@ -18,64 +49,48 @@
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-grizzly2-http</artifactId>
<version>2.5.1</version>
</dependency>
<dependency>
<groupId>ch.psi</groupId>
<artifactId>jcae</artifactId>
<version>1.0.30</version>
</dependency>
<!-- Plotting library -->
<dependency>
<groupId>ch.psi</groupId>
<artifactId>plot</artifactId>
<version>1.1.30</version>
</dependency>
<!-- Java SMB/CIFS library -->
<dependency>
<groupId>jcifs</groupId>
<artifactId>jcifs</artifactId>
<version>1.3.17</version>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-sse</artifactId>
<version>2.5.1</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>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>2.5.1</version>
</dependency>
<!-- CLI Libraries -->
<dependency>
<groupId>org.jeromq</groupId>
<artifactId>jeromq</artifactId>
<version>0.2.0</version>
</dependency>
<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>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4.1</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>
@@ -95,11 +110,12 @@
<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>
<configuration>
<additionalparam>-Xdoclint:none</additionalparam> <!-- Disable Java8 strict Javadoc checking -->
</configuration>
<executions>
<execution>
<id>attach-javadocs</id>
@@ -109,11 +125,9 @@
</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>
@@ -123,101 +137,19 @@
</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>
</plugins>
</pluginManagement>
</build>
<distributionManagement>
<snapshotRepository>
<id>i.snapshots</id>
<name>Artifactory Snapshots</name>
<url>http://yoke/artifactory/libs-snapshots-local</url>
<url>http://yoke.psi.ch:8081/artifactory/libs-snapshots-local</url>
</snapshotRepository>
<repository>
<id>i.releases</id>
<name>Atrifactory Releases</name>
<url>http://yoke/artifactory/libs-releases-local</url>
<url>http://yoke.psi.ch:8081/artifactory/libs-releases-local</url>
</repository>
</distributionManagement>
</project>

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 730 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 854 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 730 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 730 B

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 766 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

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

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,299 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.aq;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Properties;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import ch.psi.fda.install.ApplicationConfigurator;
/**
* @author ebner
*
*/
public class AcquisitionConfiguration {
private static final Logger logger = Logger.getLogger(AcquisitionConfiguration.class.getName());
private static final AcquisitionConfiguration instance = new AcquisitionConfiguration();
private String otfChannelPrefix;
private String otfNfsServer;
private String otfNfsShare;
private String otfSmbShare;
private String otfScalerPrefix;
private boolean otfUseCrlogic;
private String otfCrlogicPrefix;
private boolean otfCrlogicKeepTmpFiles;
/**
* Base directory for data. The directory may contain date macros. The string may contain any @see java.text.SimpleDateFormat
* patterns within ${ } brackets. The macros are resolved with the actual time while the get method
* of this property is called.
*/
private String dataBaseDirectory = System.getProperty("user.home");
/**
* Prefix of the data file. The prefix may contain date macros. The string may contain any @see java.text.SimpleDateFormat
* patterns within ${ } brackets. The macros are resolved with the actual time while the get method
* of this property is called.
*/
private String dataFilePrefix = "";
/**
* Maximum time for a actor move
*/
private Long actorMoveTimeout = 600000l; // 10 Minutes maximum move time
private String smptServer;
/**
* Default Constructor
* The constructor will read the configuration from the /fda.properties file (resource) located in the classpath.
*/
private AcquisitionConfiguration(){
loadConfiguration();
}
/**
* Get instance of this configuration
* @return configuration
*/
public static AcquisitionConfiguration getInstance(){
return(instance);
}
/**
* Load configuration from properties file
*/
private void loadConfiguration() {
String config = System.getProperty(ApplicationConfigurator.FDA_CONFIG_FILE_ARGUMENT);
Properties properties = new Properties();
if(config != null){
try {
properties.load(new FileReader(config));
} catch (FileNotFoundException e) {
throw new RuntimeException("Configuration file "+config+" not found", e);
} catch (IOException e) {
throw new RuntimeException("Cannot read configuration file "+config, e);
}
}
else{
logger.warning("No configfile specified !");
}
// The defaults are set here
otfChannelPrefix = properties.getProperty(AcquisitionConfiguration.class.getPackage().getName()+".otf.channelPrefix", "");
otfScalerPrefix = properties.getProperty(AcquisitionConfiguration.class.getPackage().getName()+".otf.scalerPrefix", "");
otfNfsServer = properties.getProperty(AcquisitionConfiguration.class.getPackage().getName()+".otf.nfsServer", "");
otfNfsShare = properties.getProperty(AcquisitionConfiguration.class.getPackage().getName()+".otf.nfsShare", "");
otfSmbShare = properties.getProperty(AcquisitionConfiguration.class.getPackage().getName()+".otf.smbShare", "");
otfUseCrlogic = new Boolean(properties.getProperty(AcquisitionConfiguration.class.getPackage().getName()+".otf.useCrlogic", "false"));
otfCrlogicPrefix = properties.getProperty(AcquisitionConfiguration.class.getPackage().getName()+".otf.crlogicPrefix", "");
otfCrlogicKeepTmpFiles = new Boolean(properties.getProperty(AcquisitionConfiguration.class.getPackage().getName()+".otf.crlogicKeepTmpFiles", "false"));
// Workaround
// dataBaseDirectory = properties.getProperty(AcquisitionEngineConfiguration.class.getPackage().getName()+".data.baseDirectory", ".");
if(System.getProperty(ApplicationConfigurator.FDA_HOME_ARGUMENT)!=null){
dataBaseDirectory = System.getProperty(ApplicationConfigurator.FDA_HOME_ARGUMENT)+"/data";
}
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");
}
/**
* Reload this configuration from the corresponding properties file
* @throws IOException
*/
public void reloadConfiguration() throws IOException{
loadConfiguration();
}
/**
* @return the otfChannelPrefix
*/
public String getOtfChannelPrefix() {
return otfChannelPrefix;
}
/**
* @return the otfScalerPrefix
*/
public String getOtfScalerPrefix() {
return otfScalerPrefix;
}
/**
* @return the otfNfsServer
*/
public String getOtfNfsServer() {
return otfNfsServer;
}
/**
* @return the otfNfsShare
*/
public String getOtfNfsShare() {
return otfNfsShare;
}
/**
* @return the otfSmbShare
*/
public String getOtfSmbShare() {
return otfSmbShare;
}
/**
* @return the otfUseCrlogic
*/
public boolean isOtfUseCrlogic() {
return otfUseCrlogic;
}
/**
* @return the dataBaseDirectory
*/
public String getDataBaseDirectory() {
return dataBaseDirectory;
}
/**
* @return the dataFilePrefix
*/
public String getDataFilePrefix() {
return dataFilePrefix;
}
/**
* @return the smptServer
*/
public String getSmptServer() {
return smptServer;
}
/**
* @return the otfCrlogicPrefix
*/
public String getOtfCrlogicPrefix() {
return otfCrlogicPrefix;
}
/**
* @return the otfCrlogicKeepTmpFiles
*/
public boolean isOtfCrlogicKeepTmpFiles() {
return otfCrlogicKeepTmpFiles;
}
/**
* @return the actorMoveTimeout
*/
public Long getActorMoveTimeout() {
return actorMoveTimeout;
}
public String replaceMacros(String string, Date date, String name){
String newString = string;
// Replace scan name macros
newString = newString.replaceAll("\\$\\{name\\}", name);
// Replace date macros
Pattern pattern = Pattern.compile("\\$\\{[a-z,A-Z,-,_,:]*\\}");
Matcher matcher = pattern.matcher(newString);
while(matcher.find()){
String datePattern = matcher.group();
datePattern = datePattern.replaceAll("\\$\\{", "");
datePattern = datePattern.replaceAll("\\}", "");
SimpleDateFormat datef = new SimpleDateFormat(datePattern);
newString = matcher.replaceFirst(datef.format(date));
matcher = pattern.matcher(newString);
}
return newString;
}
public void setOtfChannelPrefix(String otfChannelPrefix) {
this.otfChannelPrefix = otfChannelPrefix;
}
public void setOtfNfsServer(String otfNfsServer) {
this.otfNfsServer = otfNfsServer;
}
public void setOtfNfsShare(String otfNfsShare) {
this.otfNfsShare = otfNfsShare;
}
public void setOtfSmbShare(String otfSmbShare) {
this.otfSmbShare = otfSmbShare;
}
public void setOtfScalerPrefix(String otfScalerPrefix) {
this.otfScalerPrefix = otfScalerPrefix;
}
public void setOtfUseCrlogic(boolean otfUseCrlogic) {
this.otfUseCrlogic = otfUseCrlogic;
}
public void setOtfCrlogicPrefix(String otfCrlogicPrefix) {
this.otfCrlogicPrefix = otfCrlogicPrefix;
}
public void setOtfCrlogicKeepTmpFiles(boolean otfCrlogicKeepTmpFiles) {
this.otfCrlogicKeepTmpFiles = otfCrlogicKeepTmpFiles;
}
public void setDataBaseDirectory(String dataBaseDirectory) {
this.dataBaseDirectory = dataBaseDirectory;
}
public void setDataFilePrefix(String dataFilePrefix) {
this.dataFilePrefix = dataFilePrefix;
}
public void setActorMoveTimeout(Long actorMoveTimeout) {
this.actorMoveTimeout = actorMoveTimeout;
}
public void setSmptServer(String smptServer) {
this.smptServer = smptServer;
}
}

View File

@@ -1,18 +0,0 @@
package ch.psi.fda.aq;
import gov.aps.jca.CAException;
import ch.psi.jcae.ChannelBeanFactory;
import com.google.inject.AbstractModule;
public class AcquisitionModule extends AbstractModule {
@Override
protected void configure() {
try {
bind(ChannelBeanFactory.class).toInstance(ChannelBeanFactory.getFactory());
} catch (CAException e) {
throw new RuntimeException(e);
}
}
}

View File

@@ -1,155 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.aq;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.logging.Logger;
import com.google.common.eventbus.EventBus;
import ch.psi.fda.core.messages.ComponentMetadata;
import ch.psi.fda.core.messages.DataMessage;
import ch.psi.fda.core.messages.DataMessageMetadata;
import ch.psi.fda.core.messages.DataQueue;
import ch.psi.fda.core.messages.StreamDelimiterMessage;
import ch.psi.fda.core.messages.EndOfStreamMessage;
import ch.psi.fda.core.messages.Message;
/**
* Collector class that is collecting and merging data from different Queues.
* @author ebner
*
*/
public class Collector implements Runnable{
// Get Logger
private static Logger logger = Logger.getLogger(Collector.class.getName());
/**
* List of queues and their metadata this collector is responsible to readout.
* The logic is as follows:
* Read out the last queue until the first queue in the list has the EndOfLoopMessage.
*/
private List<DataQueue> queues;
/**
* Outgoing queue of this collector
*/
private EventBus bus;
/**
* Constructor
*/
public Collector(EventBus b){
queues = new ArrayList<DataQueue>();
this.bus = b;
}
/* (non-Javadoc)
* @see java.lang.Runnable#run()
*/
@Override
public void run() {
if(queues.size()>0){
try{
readQueue(0, null);
}
catch(InterruptedException e){
// Readout aborted through interrupt
}
}
else{
// No queue registered for reading
}
bus.post(new EndOfStreamMessage());
logger.info("END");
}
private void readQueue(int index, DataMessage m) throws InterruptedException{
BlockingQueue<Message> q = queues.get(index).getQueue();
// Read Message
Message message = q.take();
while(message instanceof DataMessage){
// Create new data message
DataMessage dm = new DataMessage();
if(m!=null){
dm.getData().addAll(m.getData());
}
dm.getData().addAll(((DataMessage)message).getData());
if(index<(queues.size()-1)){
readQueue(index+1, dm);
}
else{
// Write message to outgoing queue
bus.post(dm);
}
// Read next message
message = q.take();
}
if(message instanceof EndOfStreamMessage){
// Translate EndOfStream to StreamDelimiter message
StreamDelimiterMessage ddm = new StreamDelimiterMessage(queues.size()-1-index, ((EndOfStreamMessage)message).isIflag());
// Write message to outgoing queue
bus.post(ddm);
}
}
/**
* @return the queues
*/
public List<DataQueue> getQueues() {
return queues;
}
/**
* Get the outgoing data metadata
*/
public DataMessageMetadata getMetadata(){
DataMessageMetadata dataMessageMetadata = new DataMessageMetadata();
// Generate new combined metadata and add dimension information to the components
int nq = queues.size();
for(int i=0;i<nq;i++){
DataQueue q = queues.get(i);
for(ComponentMetadata cm: q.getDataMessageMetadata().getComponents()){
// The dimension number is the number of queues minus the index of the current queue minus 1 (because dimension index starts at 0)
dataMessageMetadata.getComponents().add(new ComponentMetadata(cm.getId(), nq-i-1));
}
}
return(dataMessageMetadata);
}
}

View File

@@ -1,46 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core;
/**
* @author ebner
*
*/
public interface Action {
/**
* Execute logic of the action
*/
public void execute() throws InterruptedException;
/**
* Abort the execution logic of the action
*/
public void abort();
/**
* Destroy action.
* Can be used for the cleanup of used resources of the action (e.g. to close connections, ...) if
* this cannot be done automatically by the GarbageCollector.
*
* After calling this method the action must not be executed any more!
*/
public void destroy();
}

View File

@@ -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;
import java.util.List;
import ch.psi.fda.core.messages.DataQueue;
/**
* Loop of actions to accomplish a task. Depending on the loop
* actions may be executed in a different way.
*
* @author ebner
*
*/
public interface ActionLoop extends Action {
/**
* Prepare ActionLoop for execution.
*/
public void prepare();
/**
* Cleanup resources used by this ActionLoop while it was executed.
*/
public void cleanup();
/**
* Get the pre actions of the Loop
* @return pre actions
*/
public List<Action> getPreActions();
/**
* Get the post actions of the loop
* @return post actions
*/
public List<Action> getPostActions();
/**
* @return is a datagroup
*/
public boolean isDataGroup();
/**
* Set whether data of the loop belongs to a own data group
* @param dataGroup
*/
public void setDataGroup(boolean dataGroup);
public DataQueue getDataQueue();
}

View File

@@ -1,64 +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;
/**
*
* @author ebner
*
*/
public interface Actor {
/**
* Set actor value
*/
public void set() throws InterruptedException;
/**
* Function to check whether the actor has a next set value
* @return Returns true if there is an actor value for the next iteration.
* False if there is no actor value (i.e. this will be the last iteration in the ActionLoop)
*/
public boolean hasNext();
/**
* Initialize the actor to the start
*/
public void init();
/**
* Reverse the set values of the actor
*/
public void reverse();
/**
* Reset the actuator to its initial configuration
*/
public void reset();
/**
* Destroy action.
* Can be used for the cleanup of used resources of the actor (e.g. to close connections, ...) if
* this cannot be done automatically by the GarbageCollector.
*
* After calling this method the actor must not be used any more!
*/
public void destroy();
}

View File

@@ -1,47 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core;
import java.util.concurrent.Callable;
/**
* Callable used for parallel execution of the set method of an actor
* @author ebner
*
*/
public class ActorSetCallable implements Callable<Object> {
// Callable actor
private Actor actor;
public ActorSetCallable(Actor actor){
this.actor = actor;
}
/* (non-Javadoc)
* @see java.util.concurrent.Callable#call()
*/
@Override
public Object call() throws Exception {
actor.set();
return null;
}
}

View File

@@ -1,87 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core;
/**
* Singleton object for holing the core engine configuration
*
* @author ebner
*/
public class EngineConfiguration {
/**
* Flag to indicate whether the engine should fail if there is an error while reading out a sensor.
*/
private boolean failOnSensorError = true;
/**
* Flag to indicate whether the set value of the actor should be verified after the set operation.
* Having this flag on true will enable detecting for example that a motor hit the end switch or
* did not move correctly.
*/
private boolean checkActorSet = true;
/**
* Singleton instance
*/
private final static EngineConfiguration instance = new EngineConfiguration();
private EngineConfiguration(){
}
/**
* Get singleton instance of this class
* @return Engine configuration
*/
public static EngineConfiguration getInstance(){
return instance;
}
/**
* @return the failOnSensorError
*/
public boolean isFailOnSensorError() {
return failOnSensorError;
}
/**
* @param failOnSensorError the failOnSensorError to set
*/
public void setFailOnSensorError(boolean failOnSensorError) {
this.failOnSensorError = failOnSensorError;
}
/**
* @return the checkActorSet
*/
public boolean isCheckActorSet() {
return checkActorSet;
}
/**
* @param checkActorSet the checkActorSet to set
*/
public void setCheckActorSet(boolean checkActorSet) {
this.checkActorSet = checkActorSet;
}
}

View File

@@ -1,53 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core;
/**
* Guard to protect specific activities. A guard can be used to check for environment changes while a
* certain activity was executed.
*
* Example:
* An Guard can be used to check whether an injection happened while the the detector were read.
*
* @author ebner
*
*/
public interface Guard {
/**
* Initialize guard object and its internal state.
*/
public void init();
/**
* Check the status of the guard.
* @return Returns true if the guard condition was not constrainted since the last init call. False otherwise.
*/
public boolean check();
/**
* Destroy guard.
* Can be used for the cleanup of used resources of the guard (e.g. to close connections, ...) if
* this cannot be done automatically by the GarbageCollector.
*
* After calling this method the guard must not be used any more!
*/
public void destroy();
}

View File

@@ -1,50 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core;
/**
* The sensor interface describes an entity that can be read out like a
* simple channel or (image) detector. Depending on the sensor type the
* returned data is of a certain type.
* @author ebner
*
*/
public interface Sensor {
/**
* Readout sensor.
* @return Sensor value. The type of the returned value depends on the sensor type.
*/
public Object read() throws InterruptedException;
/**
* Get the global id of the sensor
* @return id of sensor
*/
public String getId();
/**
* Destroy sensor.
* Can be used for the cleanup of used resources of the sensor (e.g. to close connections, ...) if
* this cannot be done automatically by the GarbageCollector.
*
* After calling this method the sensor must not be used any more!
*/
public void destroy();
}

View File

@@ -1,142 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.actions;
import java.util.logging.Logger;
import gov.aps.jca.CAException;
import ch.psi.fda.core.Action;
import ch.psi.jcae.ChannelBean;
import ch.psi.jcae.ChannelBeanFactory;
/**
* Perform a put on the specified Channel Access channel. The put can be done synchronous or
* asynchronously.
* @author ebner
*
*/
public class ChannelAccessCondition<E> implements Action {
// Get Logger
private static Logger logger = Logger.getLogger(ChannelAccessCondition.class.getName());
/**
* Channel to set
*/
private final ChannelBean<E> channel;
/**
* Value to wait for
*/
private final E expectedValue;
private final Long timeout;
private volatile boolean abort = false;
private volatile Thread waitT = null;
/**
* Constructor
* @param channelName Name of the channel to set the value
* @param expectedValue Value to wait for
* @param timeout Timeout of the condition in milliseconds (null accepted - will take default wait timeout for channels ch.psi.jcae.ChannelBeanFactory.waitTimeout)
*
* @throws IllegalArgumentException Unable to initialize channel,
* Timeout specified is not >=0
*/
@SuppressWarnings("unchecked")
public ChannelAccessCondition(String channelName, E expectedValue, Long timeout){
if(timeout !=null && timeout<=0){
throw new IllegalArgumentException("Timeout must be > 0");
}
try {
this.channel = (ChannelBean<E>) ChannelBeanFactory.getFactory().createChannelBean( (Class<E>) expectedValue.getClass(), channelName, false);
} catch (CAException e) {
// Convert Exception into unchecked RuntimeException
throw new IllegalArgumentException("Unable to initialize actuator channel [name:"+channelName+"]",e);
} catch (InterruptedException e) {
throw new RuntimeException("Unable to initialize actuator channel [name:"+channelName+"]",e);
}
this.expectedValue = expectedValue;
if(timeout==null){
this.timeout = channel.getWaitTimeout();
}
else{
this.timeout = timeout;
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Action#execute()
*/
/**
* @throws InterruptedException
* @throws RuntimeException Channel value did not reach expected value (within the specified timeout period)
*/
@Override
public void execute() throws InterruptedException {
abort=false;
logger.finest("Checking channel "+channel.getName()+" for value "+expectedValue+" [timeout: "+timeout+"]" );
try{
waitT = Thread.currentThread();
channel.waitForValue(expectedValue, timeout); // Workaround use 10seconds default set timeout to check several times whether the channel has reached the value
} catch (CAException e) {
throw new RuntimeException("Channel [name:"+channel.getName()+"] did not reach expected value "+expectedValue+" ", e);
} catch(InterruptedException e){
if(!abort){
throw e;
}
}
finally{
waitT=null;
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Action#abort()
*/
@Override
public void abort() {
abort=true;
if(waitT!=null){
waitT.interrupt();
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Action#destroy()
*/
@Override
public void destroy() {
// Destroy channel
try {
logger.finest("Destroy action channel: "+channel.getName());
channel.destroy();
} catch (CAException e) {
throw new RuntimeException("Unable to destroy channel ["+channel.getName()+"]",e);
}
}
}

View File

@@ -1,156 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.actions;
import java.util.Comparator;
import java.util.logging.Logger;
import gov.aps.jca.CAException;
import ch.psi.fda.core.Action;
import ch.psi.jcae.ChannelBean;
import ch.psi.jcae.ChannelBeanFactory;
/**
* Condition a channnel needs to match
* Only accepts channels of type Integer
*
* @author ebner
*
*/
public class ChannelAccessConditionAnd implements Action {
// Get Logger
private static Logger logger = Logger.getLogger(ChannelAccessConditionAnd.class.getName());
/**
* Channel to set
*/
private final ChannelBean<Integer> channel;
/**
* Value to wait for
*/
private final Integer expectedValue;
private final Long timeout;
private volatile boolean abort = false;
private volatile Thread waitT = null;
/**
* Constructor
* @param channelName Name of the channel to set the value
* @param expectedValue Value to wait for
* @param timeout Timeout of the condition in milliseconds (null accepted - will take default wait timeout for channels ch.psi.jcae.ChannelBeanFactory.waitTimeout)
*
* @throws IllegalArgumentException Unable to initialize channel,
* Timeout specified is not >=0
*/
@SuppressWarnings("unchecked")
public ChannelAccessConditionAnd(String channelName, Integer expectedValue, Long timeout){
if(timeout !=null && timeout<=0){
throw new IllegalArgumentException("Timeout must be > 0");
}
try {
this.channel = (ChannelBean<Integer>) ChannelBeanFactory.getFactory().createChannelBean( (Class<Integer>) expectedValue.getClass(), channelName, false);
} catch (CAException e) {
// Convert Exception into unchecked RuntimeException
throw new IllegalArgumentException("Unable to initialize actuator channel [name:"+channelName+"]",e);
} catch (InterruptedException e) {
throw new RuntimeException("Unable to initialize actuator channel [name:"+channelName+"]",e);
}
this.expectedValue = expectedValue;
if(timeout==null){
this.timeout = channel.getWaitTimeout();
}
else{
this.timeout = timeout;
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Action#execute()
*/
/**
* @throws InterruptedException
* @throws RuntimeException Channel value did not reach expected value (within the specified timeout period)
*/
@Override
public void execute() throws InterruptedException {
abort=false;
logger.finest("Checking channel "+channel.getName()+" for value "+expectedValue+" [timeout: "+timeout+"]" );
try{
waitT = Thread.currentThread();
channel.waitForValue(expectedValue, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
int one = o1;
int two = o2;
if((one & two) != 0){
return 0;
}
return 1;
}
}
, timeout); // Workaround use 10seconds default set timeout to check several times whether the channel has reached the value
} catch (CAException e) {
throw new RuntimeException("Channel [name:"+channel.getName()+"] did not reach expected value "+expectedValue+" ", e);
} catch(InterruptedException e){
if(!abort){
throw e;
}
}
finally{
waitT=null;
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Action#abort()
*/
@Override
public void abort() {
abort=true;
if(waitT!=null){
waitT.interrupt();
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Action#destroy()
*/
@Override
public void destroy() {
// Destroy channel
try {
logger.finest("Destroy action channel: "+channel.getName());
channel.destroy();
} catch (CAException e) {
throw new RuntimeException("Unable to destroy channel ["+channel.getName()+"]",e);
}
}
}

View File

@@ -1,156 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.actions;
import java.util.Comparator;
import java.util.logging.Logger;
import gov.aps.jca.CAException;
import ch.psi.fda.core.Action;
import ch.psi.jcae.ChannelBean;
import ch.psi.jcae.ChannelBeanFactory;
/**
* Or condition of a channel
* Only supports Integer values and channel
*
* @author ebner
*
*/
public class ChannelAccessConditionOr implements Action {
// Get Logger
private static Logger logger = Logger.getLogger(ChannelAccessConditionOr.class.getName());
/**
* Channel to set
*/
private final ChannelBean<Integer> channel;
/**
* Value to wait for
*/
private final Integer expectedValue;
private final Long timeout;
private volatile boolean abort = false;
private volatile Thread waitT = null;
/**
* Constructor
* @param channelName Name of the channel to set the value
* @param expectedValue Value to wait for
* @param timeout Timeout of the condition in milliseconds (null accepted - will take default wait timeout for channels ch.psi.jcae.ChannelBeanFactory.waitTimeout)
*
* @throws IllegalArgumentException Unable to initialize channel,
* Timeout specified is not >=0
*/
@SuppressWarnings("unchecked")
public ChannelAccessConditionOr(String channelName, Integer expectedValue, Long timeout){
if(timeout !=null && timeout<=0){
throw new IllegalArgumentException("Timeout must be > 0");
}
try {
this.channel = (ChannelBean<Integer>) ChannelBeanFactory.getFactory().createChannelBean( (Class<Integer>) expectedValue.getClass(), channelName, false);
} catch (CAException e) {
// Convert Exception into unchecked RuntimeException
throw new IllegalArgumentException("Unable to initialize actuator channel [name:"+channelName+"]",e);
} catch (InterruptedException e) {
throw new RuntimeException("Unable to initialize actuator channel [name:"+channelName+"]",e);
}
this.expectedValue = expectedValue;
if(timeout==null){
this.timeout = channel.getWaitTimeout();
}
else{
this.timeout = timeout;
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Action#execute()
*/
/**
* @throws InterruptedException
* @throws RuntimeException Channel value did not reach expected value (within the specified timeout period)
*/
@Override
public void execute() throws InterruptedException {
abort=false;
logger.finest("Checking channel "+channel.getName()+" for value "+expectedValue+" [timeout: "+timeout+"]" );
try{
waitT = Thread.currentThread();
channel.waitForValue(expectedValue, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
int one = o1;
int two = o2;
if((one | two) != 0){
return 0;
}
return 1;
}
}
, timeout); // Workaround use 10seconds default set timeout to check several times whether the channel has reached the value
} catch (CAException e) {
throw new RuntimeException("Channel [name:"+channel.getName()+"] did not reach expected value "+expectedValue+" ", e);
} catch(InterruptedException e){
if(!abort){
throw e;
}
}
finally{
waitT=null;
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Action#abort()
*/
@Override
public void abort() {
abort=true;
if(waitT!=null){
waitT.interrupt();
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Action#destroy()
*/
@Override
public void destroy() {
// Destroy channel
try {
logger.finest("Destroy action channel: "+channel.getName());
channel.destroy();
} catch (CAException e) {
throw new RuntimeException("Unable to destroy channel ["+channel.getName()+"]",e);
}
}
}

View File

@@ -1,149 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.actions;
import java.util.Comparator;
import java.util.logging.Logger;
import gov.aps.jca.CAException;
import ch.psi.fda.core.Action;
import ch.psi.jcae.ChannelBean;
import ch.psi.jcae.ChannelBeanFactory;
/**
* Regex condition
* Only supports String value/channel.
* @author ebner
*
*/
public class ChannelAccessConditionRegex implements Action {
// Get Logger
private static Logger logger = Logger.getLogger(ChannelAccessConditionRegex.class.getName());
/**
* Channel to set
*/
private final ChannelBean<String> channel;
/**
* Value to wait for
*/
private final String expectedValue;
private final Long timeout;
private volatile boolean abort = false;
private volatile Thread waitT = null;
/**
* Constructor
* @param channelName Name of the channel to set the value
* @param expectedValue Value to wait for
* @param timeout Timeout of the condition in milliseconds (null accepted - will take default wait timeout for channels ch.psi.jcae.ChannelBeanFactory.waitTimeout)
*
* @throws IllegalArgumentException Unable to initialize channel,
* Timeout specified is not >=0
*/
@SuppressWarnings("unchecked")
public ChannelAccessConditionRegex(String channelName, String expectedValue, Long timeout){
if(timeout !=null && timeout<=0){
throw new IllegalArgumentException("Timeout must be > 0");
}
try {
this.channel = (ChannelBean<String>) ChannelBeanFactory.getFactory().createChannelBean( (Class<String>) expectedValue.getClass(), channelName, false);
} catch (CAException e) {
// Convert Exception into unchecked RuntimeException
throw new IllegalArgumentException("Unable to initialize actuator channel [name:"+channelName+"]",e);
} catch (InterruptedException e) {
throw new RuntimeException("Unable to initialize actuator channel [name:"+channelName+"]",e);
}
this.expectedValue = expectedValue;
if(timeout==null){
this.timeout = channel.getWaitTimeout();
}
else{
this.timeout = timeout;
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Action#execute()
*/
/**
* @throws InterruptedException
* @throws RuntimeException Channel value did not reach expected value (within the specified timeout period)
*/
@Override
public void execute() throws InterruptedException {
abort=false;
logger.finest("Checking channel "+channel.getName()+" for value "+expectedValue+" [timeout: "+timeout+"]" );
try{
waitT = Thread.currentThread();
channel.waitForValue(expectedValue, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.matches(o2) ? 0:1;
}
}, timeout); // Workaround use 10seconds default set timeout to check several times whether the channel has reached the value
} catch (CAException e) {
throw new RuntimeException("Channel [name:"+channel.getName()+"] did not reach expected value "+expectedValue+" ", e);
} catch(InterruptedException e){
if(!abort){
throw e;
}
}
finally{
waitT=null;
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Action#abort()
*/
@Override
public void abort() {
abort=true;
if(waitT!=null){
waitT.interrupt();
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Action#destroy()
*/
@Override
public void destroy() {
// Destroy channel
try {
logger.finest("Destroy action channel: "+channel.getName());
channel.destroy();
} catch (CAException e) {
throw new RuntimeException("Unable to destroy channel ["+channel.getName()+"]",e);
}
}
}

View File

@@ -1,142 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.actions;
import java.util.logging.Logger;
import gov.aps.jca.CAException;
import ch.psi.fda.core.Action;
import ch.psi.jcae.ChannelBean;
import ch.psi.jcae.ChannelBeanFactory;
/**
* Perform a put on the specified Channel Access channel. The put can be done synchronous or
* asynchronously.
* @author ebner
*
*/
public class ChannelAccessPut<E> implements Action {
// Get Logger
private static Logger logger = Logger.getLogger(ChannelAccessPut.class.getName());
/**
* Channel to set
*/
private final ChannelBean<E> channel;
/**
* Value to set
*/
private final E value;
/**
* Put mode, true = fire and forget, false = wait for response
*/
private final boolean asynchronous;
private final Long timeout;
/**
* Constructor
* @param channelName Name of the channel to set the value
* @param value Value to set
* @param asynchronous Flag whether to set the value synchronous (wait for response) or asynchronously (fire and forget)
* @param timeout Timeout used for set operation (time that set need to come back)
*
* @throws IllegalArgumentException Unable to initialize channel
*/
@SuppressWarnings("unchecked")
public ChannelAccessPut(String channelName, E value, boolean asynchronous, Long timeout){
try {
this.channel = ChannelBeanFactory.getFactory().createChannelBean((Class<E>)value.getClass(), channelName, false);
} catch (CAException e) {
// Convert Exception into unchecked RuntimeException
throw new IllegalArgumentException("Unable to initialize actuator channel [name:"+channelName+"]",e);
} catch (InterruptedException e) {
throw new RuntimeException("Unable to initialize actuator channel [name:"+channelName+"]",e);
}
this.value = value;
this.asynchronous = asynchronous;
this.timeout = timeout;
}
/**
* Additional constructor for convenience. This constructor defaults the operation type to synchronous put.
* @param channelName Name of the channel to set the value
* @param value Value to set
*
* @throws RuntimeException Unable to initialize channel
*/
public ChannelAccessPut(String channelName, E value){
this(channelName, value, false, null);
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Action#execute()
*/
/**
* @throws InterruptedException
* @throws RuntimeException Cannot set value on channel
*/
@Override
public void execute() throws InterruptedException {
logger.finest("Put to channel: "+channel.getName()+ " asynchronous: "+asynchronous);
try{
if(asynchronous){
channel.setValueNoWait(value);
}
else{
if(timeout==null){
channel.setValue(value);
}
else{
channel.setValue(value, timeout);
}
}
} catch (CAException e) {
// Convert Exception into unchecked RuntimeException
throw new RuntimeException("Unable to set channel [name:"+channel.getName()+"] to value "+value, e);
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Action#abort()
*/
@Override
public void abort() {
// This action cannot be aborted, therefore this method is not implemented
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Action#destroy()
*/
@Override
public void destroy() {
// Destroy channel
try {
logger.finest("Destroy action channel: "+channel.getName());
channel.destroy();
} catch (CAException e) {
throw new RuntimeException("Unable to destroy channel ["+channel.getName()+"]",e);
}
}
}

View File

@@ -1,59 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.actions;
import ch.psi.fda.core.Action;
/**
* Wait a specific time until executing the next action ...
* @author ebner
*
*/
public class Delay implements Action {
private final long time;
/**
* @param time Time to wait in milliseconds
*/
public Delay(long time){
// Check if delay time is positive and >0
if(time<=0){
throw new IllegalArgumentException("Wait time must be >0");
}
this.time = time;
}
@Override
public void execute() throws InterruptedException {
Thread.sleep(time);
}
@Override
public void abort() {
}
@Override
public void destroy() {
}
}

View File

@@ -1,187 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.actions;
import gov.aps.jca.CAException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import ch.psi.fda.core.Action;
import ch.psi.fda.core.scripting.JythonParameterMapping;
import ch.psi.fda.core.scripting.JythonParameterMappingChannel;
import ch.psi.jcae.ChannelBean;
import ch.psi.jcae.ChannelBeanFactory;
/**
* @author ebner
*
*/
public class JythonAction implements Action {
private static Logger logger = Logger.getLogger(JythonAction.class.getName());
/**
* Pattern of the entry function of the jython script
*/
private static final String entryFunction = "process";
private static final String entryFunctionPattern = "def "+entryFunction+"\\((.*)\\):";
/**
* Script engine of the manipulator
*/
private ScriptEngine engine;
/**
* Jython entry call
*/
private String jythonCall;
private Map<String,Object> gvariables = new HashMap<String,Object>();
public JythonAction(String script, List<JythonParameterMappingChannel> mapping){
// Workaround for Jython memory leak
// http://blog.hillbrecht.de/2009/07/11/jython-memory-leakout-of-memory-problem/
System.setProperty("python.options.internalTablesImpl","weak");
// Create new script engine
this.engine = new ScriptEngineManager().getEngineByName("python");
// Determine script entry function and the function parameters
Pattern pattern = Pattern.compile(entryFunctionPattern);
Matcher matcher = pattern.matcher(script);
String[] functionParameters = null;
if(matcher.find() && matcher.groupCount()==1){
logger.finest("Entry function '"+entryFunctionPattern+"' found - Identified parameters: "+matcher.group(1));
if(matcher.group(1).matches(" *")){
functionParameters = new String[0];
}
else{
functionParameters = matcher.group(1).split(" *, *");
}
}
else{
throw new IllegalArgumentException("Cannot determine entry function: "+entryFunctionPattern);
}
// Check whether all function parameters have a mapping
for(int i=0;i<functionParameters.length; i++){
String p = functionParameters[i];
p = p.trim();
boolean found = false;
for(JythonParameterMapping pm: mapping){
if(pm.getVariable().equals(p)){
found=true;
break;
}
}
if(!found){
throw new IllegalArgumentException("No mapping compontent found for parameter "+p);
}
}
// Check whether more mappings are specified than function parameters
if(functionParameters.length<mapping.size()){
throw new IllegalArgumentException("More mappings than function parameters are specified");
}
// Load manipulation script
try {
engine.eval(script);
} catch (ScriptException e) {
throw new RuntimeException("Unable to load manipulation script", e);
}
StringBuffer buffer = new StringBuffer();
buffer.append(entryFunction);
buffer.append("( "); // Need to have trailing space as otherwise there will be a problem if no paramters are specified
for(JythonParameterMappingChannel b: mapping){
// Create channel
ChannelBean<?> cb;
try {
cb = ChannelBeanFactory.getFactory().createChannelBean(b.getType(), b.getChannel(), true);
} catch (CAException e) {
throw new IllegalArgumentException("Unable to establish channel: "+b.getChannel(), e);
} catch (InterruptedException e) {
throw new RuntimeException("Unable to establish channel: "+b.getChannel(), e);
}
// Assign channel bean to variable
engine.put(b.getVariable(), cb);
buffer.append(b.getVariable());
buffer.append(",");
}
buffer.setCharAt(buffer.length()-1, ')');
jythonCall = buffer.toString();
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Action#execute()
*/
@Override
public void execute() {
// Set global variables - WORKAROUND gvariables
// This block is not in initialization as we want to assure that all invocations
// of this manipulation will get the same value (i.e. to prevent inconsistent behaviour
// if variable was changed during an execution of the manipulation)
for(String k: gvariables.keySet()){
engine.put(k, gvariables.get(k));
}
try {
engine.eval(jythonCall);
} catch (ScriptException e) {
throw new RuntimeException("Action failed while executing the Jython script",e);
}
}
@Override
public void abort() {
}
@Override
public void destroy() {
}
/**
* Workaround to put variables into the jython engine.
* @param name
* @param value
*/
public void setVariable(String name, Object value){
gvariables.put(name, value);
}
}

View File

@@ -1,165 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.actions;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.logging.Level;
import java.util.logging.Logger;
import ch.psi.fda.core.Action;
/**
* Action that executes a specified script when it is executed.
* @author ebner
*
*/
public class ShellAction implements Action{
// Get Logger
private static Logger logger = Logger.getLogger(ShellAction.class.getName());
private volatile Process process;
private volatile boolean abort = false;
private boolean checkExitValue = true;
private int exitValue = 0;
/**
* Name (full path if it is not in the system path) of the script to execute when
* the execute() function of this action is invoked.
*/
private final String script;
/**
* Constructor
* @param script Name of the script to execute when this action is invoked
*
* @throws IllegalArgumentException Specified script does not exist
*/
public ShellAction(String script){
String[] scri = script.split("[ ,\t]");
File s = new File(scri[0]);
if(!s.exists()){
throw new IllegalArgumentException("Script "+script+" does not exist.");
}
this.script = script;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Action#execute()
*/
/**
* @throws InterruptedException
* @throws RuntimeException Script did not exit with 0,
* Execution was interrupted,
* IO problem occurred
*/
@Override
public void execute() throws InterruptedException {
try{
abort = false;
logger.fine("Execute script "+script);
process = Runtime.getRuntime().exec(new String[]{"/bin/bash","-c",script});
int exitVal = process.waitFor();
// Log output of the shell script if loglevel is finest
if(logger.isLoggable(Level.FINEST)){
logger.finest("STDOUT [BEGIN]");
// TODO The readout of the stream should be in parallel to the processing of the script! I.e. the output appears in the log as it is generated by the script!
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = null;
while((line=reader.readLine()) != null){
logger.finest(line);
}
logger.finest("STDOUT [END]");
logger.finest("STDERR [BEGIN]");
// TODO The readout of the stream should be in parallel to the processing of the script! I.e. the output appears in the log as it is generated by the script!
reader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
line = null;
while((line=reader.readLine()) != null){
logger.finest(line);
}
logger.finest("STDERR [END]");
}
logger.fine("Script ["+script+"] return value: "+exitVal);
if(abort){
throw new RuntimeException("Script ["+script+"] was aborted");
}
else{
// Check script exit value to 0 if != 0 then throw an runtime exception
if(checkExitValue && exitVal != exitValue){
throw new RuntimeException("Script ["+script+"] returned with an exit value not equal to 0");
}
}
process = null; // Ensure that the process is null
}
catch(IOException e){
// Convert Exception into unchecked RuntimeException
throw new RuntimeException("Unable to execute script: "+script,e);
}
}
@Override
public void abort() {
abort=true;
// This action cannot be aborted, therefore this function is not implemented.
if(process!=null){
// Terminate process via kill
process.destroy();
}
}
@Override
public void destroy() {
}
/**
* @return the checkExitValue
*/
public boolean isCheckExitValue() {
return checkExitValue;
}
/**
* @param checkExitValue the checkExitValue to set
*/
public void setCheckExitValue(boolean checkExitValue) {
this.checkExitValue = checkExitValue;
}
/**
* @return the exitValue
*/
public int getExitValue() {
return exitValue;
}
/**
* @param exitValue the exitValue to set
*/
public void setExitValue(int exitValue) {
this.exitValue = exitValue;
}
}

View File

@@ -1,350 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.actors;
import gov.aps.jca.CAException;
import java.util.logging.Logger;
import ch.psi.fda.core.Actor;
import ch.psi.fda.core.EngineConfiguration;
import ch.psi.jcae.ChannelBean;
import ch.psi.jcae.ChannelBeanFactory;
/**
* This actuator sets an Channel Access channel from a start to an end value by doing discrete steps.
* @author ebner
*
*/
public class ChannelAccessFunctionActuator<T> implements Actor {
// Get Logger
private static Logger logger = Logger.getLogger(ChannelAccessFunctionActuator.class.getName());
private boolean asynchronous = false;
/**
* Start value of the actuator
*/
private double start;
/**
* End value of the actuator
*/
private double end;
/**
* Step size of the move
*/
private double stepSize;
/**
* Move direction (start&lt;end = 1, start&gt;end = -1)
*/
private int direction;
/**
* Execution count of actuator. This variable is used to minimize the floating point
* rounding errors for calculating the next step.
*/
private int count;
/**
* Flag that indicates whether there is a next set value for the Actor
*/
private boolean next;
/**
* Value to set at next @see ch.psi.fda.engine.Actor#set() call
*/
private double value;
/**
* Level of accuracy the positioner need to have (e.g. if a positioner is set to 1 the readback set value
* of the positioner need to have at lease 1+/-accuracy)
* Default is stepSize/2
*/
private double accuracy;
/**
* Channel Access channel of the actuator
*/
private ChannelBean<Double> channel;
/**
* Channel Access channel of the actuator
*/
private ChannelBean<T> doneChannel = null;
private final T doneValue;
private final long doneDelay;
private final double originalStart;
private final double originalEnd;
private final int originalDirection;
/**
* Move timeout
*/
private Long timeout;
private final Function function;
/**
* Constructor - Initialize actor
* @param channelName
* @param start
* @param end
* @param stepSize
* @param timeout Maximum move time (in milliseconds)
*/
public ChannelAccessFunctionActuator(String channelName, Function function, double start, double end, double stepSize, Long timeout){
this(channelName, null, null, 0, function, start, end, stepSize, timeout);
}
/**
* Constructor
* @param channelName
* @param doneChannelName If null actor will not wait (for this channel) to continue
* @param doneValue
* @param doneDelay Delay in seconds before checking the done channel
* @param start
* @param end
* @param stepSize
* @param timeout Maximum move time (in milliseconds)
*/
@SuppressWarnings("unchecked")
public ChannelAccessFunctionActuator(String channelName, String doneChannelName, T doneValue, double doneDelay, Function function, double start, double end, double stepSize, Long timeout){
this.doneValue = doneValue;
this.doneDelay = (long) Math.floor((doneDelay*1000));
this.start = start;
this.end = end;
if(stepSize <= 0){
throw new IllegalArgumentException("Step size ["+stepSize+"] must be > 0");
}
this.stepSize = stepSize;
this.accuracy = stepSize/2;
// Validate and save timeout parameter
if(timeout!=null && timeout<=0){
throw new IllegalArgumentException("Timeout must be >0 or null");
}
else{
this.timeout = timeout;
}
if(function==null){
throw new IllegalArgumentException("Function must not be null");
}
this.function = function;
init();
// Save original settings
this.originalStart = start;
this.originalEnd = end;
this.originalDirection = direction;
// Initialize/create Channel Access channel
try {
channel = ChannelBeanFactory.getFactory().createChannelBean(Double.class, channelName, false);
} catch (CAException e) {
// Convert Exception into unchecked RuntimeException
throw new IllegalArgumentException("Unable to initialize actuator channel [name:"+channelName+"]",e);
} catch (InterruptedException e) {
throw new RuntimeException("Unable to initialize actuator channel [name:"+channelName+"]",e);
}
if(doneChannelName != null){
try {
doneChannel = ChannelBeanFactory.getFactory().createChannelBean((Class<T>)doneValue.getClass(), doneChannelName, false);
} catch (CAException e) {
// Convert Exception into unchecked RuntimeException
throw new IllegalArgumentException("Unable to initialize actuator channel [name:"+doneChannelName+"]",e);
} catch (InterruptedException e) {
throw new RuntimeException("Unable to initialize actuator channel [name:"+doneChannelName+"]",e);
}
}
}
/* (non-Javadoc)
* @see ch.psi.fda.engine.Actor#set()
*/
@Override
public void set() throws InterruptedException {
// Throw an IllegalStateException in the case that set is called although there is no next step.
if(!next){
throw new IllegalStateException("The actuator does not have any next step.");
}
// Set actuator channel
logger.finest("Set actuator channel "+channel.getName()+" to value: "+value);
try {
double fvalue = function.calculate(value);
if(!asynchronous){
if(timeout==null){
channel.setValue(fvalue);
}
else{
channel.setValue(fvalue, timeout);
}
}
else{
channel.setValueNoWait(fvalue);
}
if(doneChannel != null){
Thread.sleep(doneDelay);
doneChannel.waitForValue(doneValue);
}
// Check whether the set value is really on the value that was set before.
if(EngineConfiguration.getInstance().isCheckActorSet()){
double c = channel.getValue(true);
double a = Math.abs( c - fvalue );
if ( a > accuracy ){
throw new RuntimeException("Actor could not be set to the value "+fvalue+" The readback of the set value does not match the value that was set [value: "+c+" delta: "+a+" accuracy: "+accuracy+"]");
}
}
} catch (CAException e) {
// Convert Exception into unchecked RuntimeException
throw new RuntimeException("Unable to move actuator [channel: "+channel.getName()+"] to value "+value,e);
}
count++;
double nextValue = start+(count*stepSize*direction); // Done like this to keep floating point rounding errors minimal
if((direction==1&&nextValue<=end)||(direction==-1&nextValue>=end)){
// Apply function
// nextValue = function.calculate(nextValue);
logger.fine("Next actor value: "+nextValue);
value=nextValue;
this.next = true;
}
else{
// There is no next set value
this.next = false;
}
}
/* (non-Javadoc)
* @see ch.psi.fda.engine.Actor#hasNext()
*/
@Override
public boolean hasNext() {
return next;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#init()
*/
@Override
public void init() {
this.count = 0;
// Determine move direction
this.direction = 1;
if(start>end){
direction=-1; // Move in negative direction
}
// Set first set value to the start value
this.value = start;
this.next = true;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#reverse()
*/
@Override
public synchronized void reverse() {
double oldStart = start;
this.start = this.end;
this.end = oldStart;
// Determine move direction
this.direction = 1;
if(this.start>this.end){
direction=-1; // Move in negative direction
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#reset()
*/
@Override
public void reset() {
this.start = this.originalStart;
this.end = this.originalEnd;
this.direction = this.originalDirection;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#destroy()
*/
@Override
public void destroy() {
// Destroy channel
try {
logger.finest("Destroy actor channel: "+channel.getName());
channel.destroy();
} catch (CAException e) {
throw new RuntimeException("Unable to destroy channel ["+channel.getName()+"]",e);
}
// Destroy done channel if exists
if(doneChannel != null){
try {
logger.finest("Destroy actor done channel: "+doneChannel.getName());
doneChannel.destroy();
} catch (CAException e) {
throw new RuntimeException("Unable to destroy channel ["+channel.getName()+"]",e);
}
}
}
/**
* @return the asynchronous
*/
public boolean isAsynchronous() {
return asynchronous;
}
/**
* @param asynchronous the asynchronous to set
*/
public void setAsynchronous(boolean asynchronous) {
this.asynchronous = asynchronous;
}
}

View File

@@ -1,329 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.actors;
import gov.aps.jca.CAException;
import java.util.logging.Logger;
import ch.psi.fda.core.Actor;
import ch.psi.fda.core.EngineConfiguration;
import ch.psi.jcae.ChannelBean;
import ch.psi.jcae.ChannelBeanFactory;
/**
* This actuator sets an Channel Access channel from a start to an end value by doing discrete steps.
* @author ebner
*
*/
public class ChannelAccessLinearActuator<T> implements Actor {
// Get Logger
private static Logger logger = Logger.getLogger(ChannelAccessLinearActuator.class.getName());
private boolean asynchronous = false;
/**
* Start value of the actuator
*/
private double start;
/**
* End value of the actuator
*/
private double end;
/**
* Step size of the move
*/
private double stepSize;
/**
* Move direction (start&lt;end = 1, start&gt;end = -1)
*/
private int direction;
/**
* Execution count of actuator. This variable is used to minimize the floating point
* rounding errors for calculating the next step.
*/
private int count;
/**
* Flag that indicates whether there is a next set value for the Actor
*/
private boolean next;
/**
* Value to set at next @see ch.psi.fda.engine.Actor#set() call
*/
private double value;
/**
* Level of accuracy the positioner need to have (e.g. if a positioner is set to 1 the readback set value
* of the positioner need to have at lease 1+/-accuracy)
* Default is stepSize/2
*/
private double accuracy;
/**
* Channel Access channel of the actuator
*/
private ChannelBean<Double> channel;
/**
* Channel Access channel of the actuator
*/
private ChannelBean<T> doneChannel = null;
private final T doneValue;
private final long doneDelay;
private final double originalStart;
private final double originalEnd;
private final int originalDirection;
/**
* Move timeout
*/
private Long timeout;
/**
* Constructor
* @param channelName
* @param doneChannelName If null actor will not wait (for this channel) to continue
* @param doneValue
* @param doneDelay Delay in seconds before checking the done channel
* @param start
* @param end
* @param stepSize
* @param timeout Maximum move time (in milliseconds)
*/
@SuppressWarnings("unchecked")
public ChannelAccessLinearActuator(String channelName, String doneChannelName, T doneValue, double doneDelay, double start, double end, double stepSize, Long timeout){
this.doneValue = doneValue;
this.doneDelay = (long) Math.floor((doneDelay*1000));
this.start = start;
this.end = end;
if(stepSize <= 0){
throw new IllegalArgumentException("Step size ["+stepSize+"] must be > 0");
}
this.stepSize = stepSize;
this.accuracy = stepSize/2;
// Validate and save timeout parameter
if(timeout!=null && timeout<=0){
throw new IllegalArgumentException("Timeout must be >0 or null");
}
else{
this.timeout = timeout;
}
init();
// Save original settings
this.originalStart = start;
this.originalEnd = end;
this.originalDirection = direction;
// Initialize/create Channel Access channel
try {
channel = ChannelBeanFactory.getFactory().createChannelBean(Double.class, channelName, false);
} catch (CAException e) {
// Convert Exception into unchecked RuntimeException
throw new IllegalArgumentException("Unable to initialize actuator channel [name:"+channelName+"]",e);
} catch (InterruptedException e) {
throw new RuntimeException("Unable to initialize actuator channel [name:"+channelName+"]",e);
}
if(doneChannelName != null){
try {
doneChannel = ChannelBeanFactory.getFactory().createChannelBean((Class<T>) doneValue.getClass(), doneChannelName, false);
} catch (CAException e) {
// Convert Exception into unchecked RuntimeException
throw new IllegalArgumentException("Unable to initialize actuator channel [name:"+doneChannelName+"]",e);
} catch (InterruptedException e) {
throw new RuntimeException("Unable to initialize actuator channel [name:"+doneChannelName+"]",e);
}
}
}
/* (non-Javadoc)
* @see ch.psi.fda.engine.Actor#set()
*/
@Override
public void set() throws InterruptedException {
// Throw an IllegalStateException in the case that set is called although there is no next step.
if(!next){
throw new IllegalStateException("The actuator does not have any next step.");
}
// Set actuator channel
logger.finest("Set actuator channel "+channel.getName()+" to value: "+value);
try {
if(!asynchronous){
if(timeout==null){
channel.setValue(value);
}
else{
channel.setValue(value, timeout);
}
}
else{
channel.setValueNoWait(value);
}
if(doneChannel != null){
Thread.sleep(doneDelay);
doneChannel.waitForValue(doneValue);
}
// Check whether the set value is really on the value that was set before.
if(EngineConfiguration.getInstance().isCheckActorSet()){
double c = channel.getValue(true);
double a = Math.abs( c - value );
if ( a > accuracy ){
throw new RuntimeException("Actor could not be set to the value "+value+" The readback of the set value does not match the value that was set [value: "+c+" delta: "+a+" accuracy: "+accuracy+"]");
}
}
} catch (CAException e) {
// Convert Exception into unchecked RuntimeException
throw new RuntimeException("Unable to move actuator [channel: "+channel.getName()+"] to value "+value,e);
}
count++;
double nextValue = start+(count*stepSize*direction); // Done like this to keep floating point rounding errors minimal
if((direction==1&&nextValue<=end)||(direction==-1&nextValue>=end)){
logger.fine("Next actor value: "+nextValue);
value=nextValue;
this.next = true;
}
else{
// There is no next set value
this.next = false;
}
}
/* (non-Javadoc)
* @see ch.psi.fda.engine.Actor#hasNext()
*/
@Override
public boolean hasNext() {
return next;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#init()
*/
@Override
public void init() {
this.count = 0;
// Determine move direction
this.direction = 1;
if(start>end){
direction=-1; // Move in negative direction
}
// Set first set value to the start value
this.value = start;
this.next = true;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#reverse()
*/
@Override
public synchronized void reverse() {
double oldStart = start;
this.start = this.end;
this.end = oldStart;
// Determine move direction
this.direction = 1;
if(this.start>this.end){
direction=-1; // Move in negative direction
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#reset()
*/
@Override
public void reset() {
this.start = this.originalStart;
this.end = this.originalEnd;
this.direction = this.originalDirection;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#destroy()
*/
@Override
public void destroy() {
// Destroy channel
try {
logger.finest("Destroy actor channel: "+channel.getName());
channel.destroy();
} catch (CAException e) {
throw new RuntimeException("Unable to destroy channel ["+channel.getName()+"]",e);
}
// Destroy done channel if exists
if(doneChannel != null){
try {
logger.finest("Destroy actor done channel: "+doneChannel.getName());
doneChannel.destroy();
} catch (CAException e) {
throw new RuntimeException("Unable to destroy channel ["+channel.getName()+"]",e);
}
}
}
/**
* @return the asynchronous
*/
public boolean isAsynchronous() {
return asynchronous;
}
/**
* @param asynchronous the asynchronous to set
*/
public void setAsynchronous(boolean asynchronous) {
this.asynchronous = asynchronous;
}
}

View File

@@ -1,314 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.actors;
import gov.aps.jca.CAException;
import java.util.logging.Logger;
import ch.psi.fda.core.Actor;
import ch.psi.fda.core.EngineConfiguration;
import ch.psi.jcae.ChannelBean;
import ch.psi.jcae.ChannelBeanFactory;
/**
* This actuator sets an Channel Access channel by using the positions from the given table.
* @author ebner
*
*/
public class ChannelAccessTableActuator<T> implements Actor {
// Get Logger
private static Logger logger = Logger.getLogger(ChannelAccessTableActuator.class.getName());
private boolean asynchronous = false;
/**
* Position table
*/
private final double[] table;
/**
* Level of accuracy the positioner need to have (e.g. if a positioner is set to 1 the readback set value
* of the positioner need to have at lease 1+/-accuracy)
*/
private double accuracy = 0.1;
/**
* Execution count of actuator. This variable is used to minimize the floating point
* rounding errors for calculating the next step.
*/
private int count;
/**
* Flag that indicates whether there is a next set value for the Actor
*/
private boolean next;
/**
* Channel Access channel of the actuator
*/
private ChannelBean<Double> channel;
/**
* Channel Access channel of the actuator
*/
private ChannelBean<T> doneChannel = null;
private final T doneValue;
private final long doneDelay;
/**
* Flag that indicates whether the actor moves in the positive direction
*/
private boolean positiveDirection = true;
private final boolean originalPositiveDirection;
/**
* Maximum move time (in milliseconds)
*/
private Long timeout = null;
/**
* Constructor - Initialize actor
* @param channelName Name of the channel to set
* @param table Position table with the explicit positions for each step
* @param timeout Maximum move time (in milliseconds)
*/
public ChannelAccessTableActuator(String channelName, double[] table, Long timeout){
this(channelName, null, null, 0, table, timeout);
}
/**
* Constructor
* @param channelName
* @param doneChannelName
* @param doneValue
* @param doneDelay
* @param table
* @param timeout Maximum move time (in milliseconds)
*/
@SuppressWarnings("unchecked")
public ChannelAccessTableActuator(String channelName, String doneChannelName, T doneValue, double doneDelay, double[] table, Long timeout){
this.doneValue = doneValue;
this.doneDelay = (long) Math.floor((doneDelay*1000));
if(table==null){
throw new IllegalArgumentException("Null table is not accepted");
}
if(table.length==0){
throw new IllegalArgumentException("Position table need to have at least one position");
}
this.table = table;
// Validate and save timeout parameter
if(timeout!=null && timeout<=0){
throw new IllegalArgumentException("Timeout must be >0 or null");
}
else{
this.timeout = timeout;
}
init();
// Save the initial direction
this.originalPositiveDirection = positiveDirection;
// Initialize/create Channel Access channel
try {
channel = ChannelBeanFactory.getFactory().createChannelBean(Double.class, channelName, false);
} catch (CAException e) {
// Convert Exception into unchecked RuntimeException
throw new IllegalArgumentException("Unable to initialize actuator channel [name:"+channelName+"]",e);
} catch (InterruptedException e) {
throw new RuntimeException("Unable to initialize actuator channel [name:"+channelName+"]",e);
}
if(doneChannelName != null){
try {
doneChannel = ChannelBeanFactory.getFactory().createChannelBean((Class<T>)doneValue.getClass(), doneChannelName, false);
} catch (CAException e) {
// Convert Exception into unchecked RuntimeException
throw new IllegalArgumentException("Unable to initialize actuator channel [name:"+doneChannelName+"]",e);
} catch (InterruptedException e) {
throw new RuntimeException("Unable to initialize actuator channel [name:"+doneChannelName+"]",e);
}
}
}
/* (non-Javadoc)
* @see ch.psi.fda.engine.Actor#set()
*/
@Override
public void set() throws InterruptedException {
// Throw an IllegalStateException in the case that set is called although there is no next step.
if(!next){
throw new IllegalStateException("The actuator does not have any next step.");
}
// Set actuator channel
logger.finest("Set actuator channel "+channel.getName()+" to value: "+table[count]);
try {
if(!asynchronous){
if(timeout==null){
channel.setValue(table[count]);
}
else{
channel.setValue(table[count], timeout);
}
}
else{
channel.setValueNoWait(table[count]);
}
if(doneChannel != null){
Thread.sleep(doneDelay);
doneChannel.waitForValue(doneValue);
}
// Check whether the set value is really on the value that was set before.
if(doneChannel==null && !asynchronous && EngineConfiguration.getInstance().isCheckActorSet()){
if ( Math.abs( channel.getValue() - table[count] ) > accuracy ){
throw new RuntimeException("Actor could not be set to the value "+table[count]+" The readback of the set value does not match the value that was set");
}
}
} catch (CAException e) {
// Convert Exception into unchecked RuntimeException
throw new RuntimeException("Move actuator [channel: "+channel.getName()+"] to value "+table[count],e);
}
if(positiveDirection){
count++;
if(count<table.length){
this.next = true;
}
else{
// There is no next set value
this.next = false;
}
}
else{
count--;
if(count>=0){
this.next = true;
}
else{
// There is no next set value
this.next = false;
}
}
}
/* (non-Javadoc)
* @see ch.psi.fda.engine.Actor#hasNext()
*/
@Override
public boolean hasNext() {
return next;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#init()
*/
@Override
public void init() {
// Set first set value to the start value
if(positiveDirection){
this.count = 0; // Set count to the first element
}
else{
this.count = table.length-1; // Set count to the last element
}
if(table.length>0){
this.next = true;
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#reverse()
*/
@Override
public void reverse() {
if(positiveDirection){
positiveDirection=false;
}
else{
positiveDirection=true;
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#reset()
*/
@Override
public void reset() {
this.positiveDirection = this.originalPositiveDirection;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#destroy()
*/
@Override
public void destroy() {
// Destroy channel
try {
logger.finest("Destroy actor channel: "+channel.getName());
channel.destroy();
} catch (CAException e) {
throw new RuntimeException("Unable to destroy channel ["+channel.getName()+"]",e);
}
// Destroy done channel if exists
if(doneChannel != null){
try {
logger.finest("Destroy actor done channel: "+doneChannel.getName());
doneChannel.destroy();
} catch (CAException e) {
throw new RuntimeException("Unable to destroy channel ["+channel.getName()+"]",e);
}
}
}
/**
* @return the asynchronous
*/
public boolean isAsynchronous() {
return asynchronous;
}
/**
* @param asynchronous the asynchronous to set
*/
public void setAsynchronous(boolean asynchronous) {
this.asynchronous = asynchronous;
}
}

View File

@@ -1,261 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.actors;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
import ch.psi.fda.core.Action;
import ch.psi.fda.core.Actor;
/**
* Complex actuator that consists of a list of other actuators. The steps of this actor are composed out of the
* steps of the actors that this actuator consists of.
* First all the steps of the first actor are used, after that the steps of the next actor are done.
* Before the first step of an actor pre actions are available and after the last step of an actor a post action is available.
*
* @author ebner
*
*/
public class ComplexActuator implements Actor {
// Get Logger
private static Logger logger = Logger.getLogger(ComplexActuator.class.getName());
/**
* List of actors this actor is made of
*/
private final List<Actor> actors;
/**
* Actions that are executed directly before the first step of this actor
*/
private final List<Action> preActions;
/**
* Actions that are executed directly after the last step of this actor
*/
private final List<Action> postActions;
/**
* Flag that indicates whether there is a next set value for the Actor
*/
private boolean next;
/**
* Index of the actor currently used
*/
private int actualActorCount;
/**
* Actor currently used to perform steps
*/
private Actor actualActor;
/**
* Flag to indicate the first set() execution of this actor.
* This flag is used to decide whether to execute the pre actions.
*/
private boolean firstrun;
/**
* Constructor
*/
public ComplexActuator(){
this.actors = new ArrayList<Actor>();
this.preActions = new ArrayList<Action>();
this.postActions = new ArrayList<Action>();
this.next = false;
this.actualActorCount = 0;
this.firstrun = true;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#set()
*/
@Override
public void set() throws InterruptedException {
// Throw an IllegalStateException in the case that set is called although there is no next step.
if(!next){
throw new IllegalStateException("The actuator does not have any next step.");
}
// PRE actions
if(firstrun){
this.firstrun = false;
// Execute pre actions
logger.finest("Execute pre actions");
for(Action action: preActions){
action.execute();
}
}
actualActor.set(); // If the actor has no next step then something is wrong in the init/next step logic
// If the last point of the actual actuator is set take the next actuator in the list if there is one available
while(!actualActor.hasNext()&&actualActorCount<actors.size()){
actualActorCount++;
if(actualActorCount<actors.size()){
actualActor = actors.get(actualActorCount);
}
else{
break;
}
}
if(actualActor.hasNext()){
this.next = true;
}
else{
this.next = false;
// Execute post actions
logger.finest("Execute post actions");
for(Action action: postActions){
action.execute();
}
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#hasNext()
*/
@Override
public boolean hasNext() {
return next;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#init()
*/
@Override
public void init() {
// Initialize all actors this actor consist of
for(Actor a: actors){
a.init();
}
// Set the actual actor to the first actor in the list
actualActorCount=0;
if(actualActorCount<actors.size()){
actualActor = actors.get(actualActorCount);
// Check whether the actor has a next step, if not increase to the next one
// This is needed because the first actor might not have any step ... (very unlikely but bad things happens some time)
while(!actualActor.hasNext()&&actualActorCount<actors.size()){
actualActorCount++;
if(actualActorCount<actors.size()){
actualActor = actors.get(actualActorCount);
}
else{
break;
}
}
if(actualActor.hasNext()){
this.next = true;
}
else{
this.next = false;
}
}
else{
actualActor=null;
this.next=false;
}
this.firstrun = true;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#reverse()
*/
@Override
public void reverse() {
// Reverse all actors this actor consist of
for(Actor a: actors){
a.reverse();
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#reset()
*/
@Override
public void reset() {
// Reset all actors this actor consist of
for(Actor a: actors){
a.reset();
}
}
/**
* Get the list of actors of this ComplexActor
* @return the actors
*/
public List<Actor> getActors() {
return actors;
}
/**
* @return the preActions
*/
public List<Action> getPreActions() {
return preActions;
}
/**
* @return the postActions
*/
public List<Action> getPostActions() {
return postActions;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#destroy()
*/
@Override
public void destroy() {
// Destroy preActions
for(Action a: preActions){
a.destroy();
}
// Destroy actors
for(Actor a: actors){
a.destroy();
}
// Destroy postActions
for(Action a: postActions){
a.destroy();
}
}
}

View File

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

View File

@@ -1,114 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.actors;
import java.util.Map;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import ch.psi.fda.core.scripting.JythonGlobalVariable;
/**
* @author ebner
*
*/
public class JythonFunction implements Function {
// Get Logger
private static final Logger logger = Logger.getLogger(JythonFunction.class.getName());
public static final String ENTRY_FUNCTION_NAME = "calculate";
private static final String ENTRY_FUNCTION_PATTERN = "def "+ENTRY_FUNCTION_NAME+"\\((.*)\\):";
/**
* Script engine of the manipulator
*/
private ScriptEngine engine;
private String additionalParameter = "";
public JythonFunction(String script, Map<String, JythonGlobalVariable> map){
// Create new script engine
this.engine = new ScriptEngineManager().getEngineByName("python");
// Determine script entry function and the function parameters
String[] parameter;
Pattern pattern = Pattern.compile(ENTRY_FUNCTION_PATTERN);
Matcher matcher = pattern.matcher(script);
if(matcher.find() && matcher.groupCount()==1){
if(!matcher.group(1).trim().equals("")){
logger.finest("Entry function '"+ENTRY_FUNCTION_PATTERN+"' found - Identified parameters: "+matcher.group(1));
parameter = matcher.group(1).split(" *, *");
}
else{
parameter = new String[0];
}
}
else{
throw new IllegalArgumentException("Cannot determine entry function: "+ENTRY_FUNCTION_PATTERN);
}
// Check whether all parameters are mapped
StringBuilder b = new StringBuilder();
for(int i=1;i<parameter.length; i++){ // Starting at 1 because first argument is implicit.
if(!map.containsKey(parameter[i])){
throw new IllegalArgumentException("Function parameter "+parameter[i]+" is not mapped");
}
b.append(",");
b.append(parameter[i]);
}
additionalParameter = b.toString();
// Set variables in Jython engine
for(String k: map.keySet()){
engine.put(k, map.get(k));
}
// Load manipulation script
try {
engine.eval(script);
} catch (ScriptException e) {
throw new RuntimeException("Unable to load manipulation script", e);
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.actors.Function#calculate(double)
*/
@Override
public double calculate(double parameter) {
logger.fine("Function called");
try {
logger.info("calculate( "+parameter+""+additionalParameter+" )");
return ((Double) engine.eval("calculate( "+parameter+""+additionalParameter+" )"));
} catch (ScriptException e) {
throw new RuntimeException("Calculating actuator step failed while executing the Jython script",e);
}
}
}

View File

@@ -1,188 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.actors;
import ch.psi.fda.core.Actor;
/**
* Special actuator for the OTFLoop. This type of actor must not be used in any other
* type of loop than OTFLoop. If it is used it will, depending on the loop, immediately stop the loop
* as it no single step.
* @author ebner
*
*/
public class OTFActuator implements Actor {
/**
* Name of the motor channel
*/
private final String name;
/**
* Channel name of the encoder;
*/
private final String readback;
private double start;
private double end;
private final double stepSize;
private final double integrationTime;
private final String id;
/**
* Additional backlash for the motor
*/
private final double additionalBacklash;
public OTFActuator(String id, String name, String readback, double start, double end, double stepSize, double integrationTime, double additionalBacklash){
this.id = id;
this.name = name;
this.readback = readback;
this.start = start;
this.end = end;
this.stepSize = stepSize;
this.integrationTime = integrationTime;
this.additionalBacklash = additionalBacklash;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#set()
*/
@Override
public void set() {
// Do nothing
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#hasNext()
*/
@Override
public boolean hasNext() {
return false;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @return the readback
*/
public String getReadback() {
return readback;
}
/**
* @return the start
*/
public double getStart() {
return start;
}
/**
* @return the end
*/
public double getEnd() {
return end;
}
/**
* @return the stepSize
*/
public double getStepSize() {
return stepSize;
}
/**
* @return the integrationTime
*/
public double getIntegrationTime() {
return integrationTime;
}
/**
* @return the additionalBacklash
*/
public double getAdditionalBacklash() {
return additionalBacklash;
}
/**
* @return the id
*/
public String getId() {
return id;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#init()
*/
@Override
public void init() {
// Not implemented
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#reverse()
*/
@Override
public void reverse() {
// Not implemented
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#reset()
*/
@Override
public void reset() {
// Not implemented
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#destroy()
*/
@Override
public void destroy() {
// Nothing to be done
}
/**
* @param start the start to set
*/
public void setStart(double start) {
this.start = start;
}
/**
* @param end the end to set
*/
public void setEnd(double end) {
this.end = end;
}
}

View File

@@ -1,135 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.actors;
import ch.psi.fda.core.Actor;
import ch.psi.fda.core.Sensor;
/**
* Pseudo actor that is literally doing nothing for n times
* @author ebner
*
*/
public class PseudoActuatorSensor implements Actor, Sensor {
/**
* Execution count of actuator.
*/
private int count;
/**
* Number of counts for this actuator
*/
private final int counts;
private final String id;
/**
* Constructor
* @param counts
* @param id Id of the Actor/Sensor
*/
public PseudoActuatorSensor(String id, int counts){
if(counts < 1){
throw new IllegalArgumentException("Count ["+counts+"] must be > 0");
}
this.id = id;
this.counts = counts;
init();
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#set()
*/
@Override
public void set() {
// Throw an IllegalStateException in the case that set is called although there is no next step.
if(!hasNext()){
throw new IllegalStateException("The actuator does not have any next step.");
}
count++;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#hasNext()
*/
@Override
public boolean hasNext() {
return (count<counts);
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#init()
*/
@Override
public void init() {
count=0; // Set count back to 0
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#reverse()
*/
@Override
public void reverse() {
// Not implemented
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#reset()
*/
@Override
public void reset() {
// NOt implemented
}
// Sensor implementation
/* (non-Javadoc)
* @see ch.psi.fda.core.Sensor#read()
*/
@Override
public Object read() {
return new Double(count); // Return actual count
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Sensor#getId()
*/
@Override
public String getId() {
return this.id;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Actor#destroy()
*/
@Override
public void destroy() {
// Nothing to be done
}
}

View File

@@ -1,117 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.guard;
import gov.aps.jca.CAException;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import ch.psi.fda.core.Guard;
/**
* Guard checking channels to meet a certain condition
* @author ebner
*
*/
public class ChannelAccessGuard implements Guard {
// Get Logger
private static Logger logger = Logger.getLogger(ChannelAccessGuard.class.getName());
/**
* Flag to indicate whether a guard condition failed since the last init call
* true: all conditions met, false: at least one condition failed
*/
private boolean check = true;
private final List<ChannelAccessGuardCondition> conditions;
/**
* Constructor
* @param conditions
*/
public ChannelAccessGuard(List<ChannelAccessGuardCondition> conditions){
this.conditions = conditions;
// Create channel that contribute to the status of the guard
for(final ChannelAccessGuardCondition condition: conditions){
condition.getChannel().addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if(! evt.getNewValue().equals(condition.getValue())){
check=false;
}
}
});
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Guard#init()
*/
@Override
public void init() {
check = true;
// Check one time if all conditions are met
for(ChannelAccessGuardCondition condition: conditions){
try{
if(! (condition.getChannel().getValue(true)).equals(condition.getValue()) ){
check=false;
// Early exit
break;
}
}
catch(CAException e){
logger.log(Level.WARNING, "Unable ", e);
check=false;
} catch (InterruptedException e) {
throw new RuntimeException("Guard interrupted ",e);
}
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Guard#check()
*/
@Override
public boolean check() {
return check;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Guard#destroy()
*/
@Override
public void destroy() {
// Destroy Guard Conditions
for(ChannelAccessGuardCondition condition: conditions){
condition.destroy();
}
}
}

View File

@@ -1,96 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.guard;
import java.util.logging.Logger;
import gov.aps.jca.CAException;
import ch.psi.jcae.ChannelBean;
import ch.psi.jcae.ChannelBeanFactory;
/**
* Channel and condition that need to be met.
* @author ebner
*
*/
public class ChannelAccessGuardCondition {
// Get Logger
private static Logger logger = Logger.getLogger(ChannelAccessGuardCondition.class.getName());
/**
* Channel name
*/
private final ChannelBean<?> channel;
/**
* Value of the channel to meet condition
*/
private final Object value;
/**
* Constructor
* @param channel Name of the channel that contributes to a guard
* @param value
*/
public ChannelAccessGuardCondition(String channel, Object value){
try {
this.channel = ChannelBeanFactory.getFactory().createChannelBean(value.getClass(), channel, true);
} catch (CAException e) {
// Convert Exception into unchecked RuntimeException
throw new IllegalArgumentException("Unable to initialize actuator channel [name:"+channel+"]",e);
} catch (InterruptedException e) {
throw new RuntimeException("Unable to initialize actuator channel [name:"+channel+"]",e);
}
this.value = value;
}
/**
* @return the channel
*/
public ChannelBean<?> getChannel() {
return channel;
}
/**
* @return the value
*/
public Object getValue() {
return value;
}
/**
* Destroy guard condition.
* Can be used for the cleanup of used resources of the guard condition (e.g. to close connections, ...) if
* this cannot be done automatically by the GarbageCollector.
*
* After calling this method the guard condition must not be used any more!
*/
public void destroy(){
// Destroy channel
try {
logger.finest("Destroy guard condition channel: "+channel.getName());
channel.destroy();
} catch (CAException e) {
throw new RuntimeException("Unable to destroy channel ["+channel.getName()+"]",e);
}
}
}

View File

@@ -1,590 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.loops;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.logging.Logger;
import ch.psi.fda.core.Action;
import ch.psi.fda.core.ActionLoop;
import ch.psi.fda.core.Actor;
import ch.psi.fda.core.ActorSetCallable;
import ch.psi.fda.core.Guard;
import ch.psi.fda.core.Sensor;
import ch.psi.fda.core.messages.ComponentMetadata;
import ch.psi.fda.core.messages.DataMessage;
import ch.psi.fda.core.messages.DataMessageMetadata;
import ch.psi.fda.core.messages.DataQueue;
import ch.psi.fda.core.messages.EndOfStreamMessage;
import ch.psi.fda.core.messages.Message;
/**
* Loop of actions to accomplish a task or test.
* @author ebner
*
*/
public class ActorSensorLoop implements ActionLoop {
// Get Logger
private static Logger logger = Logger.getLogger(ActorSensorLoop.class.getName());
/**
* Flag to indicate whether the data of this loop will be grouped
* According to this flag the dataGroup flag in EndOfStream will be set.
*/
private boolean dataGroup = false;
/**
* List of additional action loops that are executed at the end of each
* iteration of the loop
*/
private List<ActionLoop> actionLoops;
/**
* List of actions that are executed at the beginning of the loop.
*/
private List<Action> preActions;
/**
* List of actions that are executed at the end of the loop.
*/
private List<Action> postActions;
/**
* List of actions that are executed before the actors are set
*/
private List<Action> preActorActions;
/**
* List of actions that are executed after all actors have been set
*/
private List<Action> postActorActions;
/**
* List of actions that are executed before the sensors are read out
*/
private List<Action> preSensorActions;
/**
* List of actions that are executed after all sensors have been read out
*/
private List<Action> postSensorActions;
/**
* List of actors of this loop
*/
private List<Actor> actors;
/**
* List of sensors of this loop
*/
private List<Sensor> sensors;
/**
* Data queue sensor data is posted to. A message consists of a list of data objects
* that are read out of the sensors of this loop.
*/
private BlockingQueue<Message> dataQueue;
/**
* Guard used to check whether the environment was ok while reading out the sensors
*/
private Guard guard = null;
private volatile boolean loop = false;
private volatile boolean abort = false;
private final boolean zigZag;
private List<ActorSetCallable> pactors;
/**
* Default constructor
*/
public ActorSensorLoop(){
this(false);
}
/**
* Create instance of the
*/
public ActorSensorLoop(boolean zigZag){
this.zigZag = zigZag;
this.actionLoops = new ArrayList<ActionLoop>();
this.preActions = new ArrayList<Action>();
this.postActions = new ArrayList<Action>();
this.preActorActions = new ArrayList<Action>();
this.postActorActions = new ArrayList<Action>();
this.preSensorActions = new ArrayList<Action>();
this.postSensorActions = new ArrayList<Action>();
this.actors = new ArrayList<Actor>();
this.pactors = new ArrayList<ActorSetCallable>();
this.sensors = new ArrayList<Sensor>();
this.dataQueue = new LinkedBlockingQueue<Message>(1000);
}
/* (non-Javadoc)
* @see ch.psi.fda.engine.ActionLoop#execute()
*/
/**
* Executes the actor sensor loop. The actor sensor loop is build up as follows:
* preActions
* loop{
* check actors - abort if there are no new steps
* pre actor actions
* set actors
* post actor actions
* pre sensor actions
* read sensors
* post sensor actions
* execute additional registered action loops
* }
* postActions
* @throws InterruptedException
*/
@Override
public void execute() throws InterruptedException {
abort = false;
/**
* Thread pool for parallel execution of tasks
*/
ExecutorService executorService = Executors.newCachedThreadPool();
loop = true;
// Execute pre actions
for(Action action: preActions){
action.execute();
}
// Initialize actors of Loop
for(Actor actor: actors){
actor.init();
}
// Variable to store the last guard status
boolean guardOK=true;
try{
// Execute loop logic
while(loop){
if(guardOK){
// If actors are defined for the loop check whether all of them
// have a next step defined if there is no actor defined only run this loop once
if(actors.size()>0){
// Check whether the actors of this loop have a next step. If not
// abort the loop
boolean hasNext = true;
for(Actor actor: actors){
if(!actor.hasNext()){
hasNext=false;
break; // Stop actor check loop
}
}
// If not all actors have a next step abort the loop
if(!hasNext){
break; // Stop action loop
}
}
else{
// No actors defined, only run loop once
loop = false;
}
// Execute pre actor actions
for(Action action: preActorActions){
action.execute();
}
if(abort){ // End loop if abort was issued
break;
}
// Set actors
// for(Actor actor: actors){
// actor.set();
// }
// Parallel set of the actors
try {
for (Future<Object> f : executorService.invokeAll(pactors)) {
f.get(); //Blocks until the async set() is finished
}
} catch (ExecutionException e) {
throw new RuntimeException("Setting the actors failed",e);
}
// Execute post actor actions
for(Action action: postActorActions){
action.execute();
}
if(abort){ // End loop if abort was issued
break;
}
}
if(guard!=null){
// Initialize guard
guard.init();
guardOK=guard.check();
// Wait until guard is ok
while(!guardOK){
logger.info("Waiting for guard condition(s) to be met");
// Sleep 100 milliseconds before next check
Thread.sleep(1000);
// Check whether the loop is not aborted, if it is aborted
// break the wait loop (afterwards also the loop loop is aborted)
if(!loop){
break;
}
guard.init();
guardOK=guard.check();
}
// If loop is aborted proceed to next iteration an abort loop
if(!loop){
continue;
}
}
// Execute pre sensor actions
for(Action action: preSensorActions){
action.execute();
}
if(abort){ // End loop if abort was issued
break;
}
// Read sensors
DataMessage message = new DataMessage();
for(Sensor sensor: sensors){
// Readout sensor
Object o = sensor.read();
// Add sensor data item to message
message.getData().add(o);
}
// Execute post sensor actions
for(Action action: postSensorActions){
action.execute();
}
if(abort){ // End loop if abort was issued
break;
}
// Check guard if one is registered
if(guard!=null){
guardOK=guard.check();
}
if(guardOK){
// Post a message with the sensor data
dataQueue.put(message);
// Loop all configured ActionLoop objects
for(ActionLoop actionLoop: actionLoops){
actionLoop.execute();
}
}
}
// Execute post actions
for(Action action: postActions){
action.execute();
}
}
finally{
// Ensure that data stream is terminated ...
// Issue end of loop control message
// Set iflag of the EndOfStreamMessage according to dataGroup flag of this loop
dataQueue.put(new EndOfStreamMessage(dataGroup));
}
if(zigZag){
// Reverse actors for the next run
for(Actor actor: actors){
actor.reverse();
}
}
executorService.shutdownNow();
}
/* (non-Javadoc)
* @see ch.psi.fda.engine.ActionLoop#abort()
*/
@Override
public void abort(){
abort = true;
loop = false;
// To abort all wait actions interrupt this thread
for(Action a: preSensorActions){
a.abort();
}
// Recursively abort all registered action loops
for(ActionLoop actionLoop: actionLoops){
actionLoop.abort();
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.ActionLoop#prepare()
*/
@Override
public void prepare() {
// Put in prepare code here
// Create callable for all actors
pactors.clear();
for(final Actor a: actors){
pactors.add(new ActorSetCallable(a));
}
// Reset all actuators
for(Actor a: actors){
a.reset();
}
// Recursively call prepare() method of all registered action loops
for(ActionLoop actionLoop: actionLoops){
actionLoop.prepare();
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.ActionLoop#cleanup()
*/
@Override
public void cleanup() {
// Put in cleanup code here
// Recursively call cleanup() method of all registered action loops
for(ActionLoop actionLoop: actionLoops){
actionLoop.cleanup();
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Action#destroy()
*/
@Override
public void destroy() {
// Call destroy method of sub components
for(Action a: preActions){
logger.finest("Destroy pre-action");
a.destroy();
}
for(Action a: postActions){
logger.finest("Destroy post-action");
a.destroy();
}
for(Action a: preActorActions){
logger.finest("Destroy pre-actor action");
a.destroy();
}
for(Action a: postActorActions){
logger.finest("Destroy post-actor action");
a.destroy();
}
for(Action a: preSensorActions){
logger.finest("Destroy pre-sensor action");
a.destroy();
}
for(Action a: postSensorActions){
logger.finest("Destroy post-sensor action");
a.destroy();
}
for(Actor a: actors){
logger.finest("Destroy actor");
a.destroy();
}
for(Sensor s: sensors){
logger.finest("Destroy sensor");
s.destroy();
}
if(guard != null){
logger.finest("Destroy guard");
guard.destroy();
}
// Recursively call cleanup() method of all registered action loops
for(ActionLoop actionLoop: actionLoops){
logger.finest("Destroy action loop");
actionLoop.destroy();
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.ActionLoop#getPreActions()
*/
@Override
public List<Action> getPreActions() {
return preActions;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.ActionLoop#getPostActions()
*/
@Override
public List<Action> getPostActions() {
return postActions;
}
/**
* The structure of the data message depends on the sensors registered at this loop
* at the time this method is called.
* @return the data queue and the metadata of the data messages
*/
public DataQueue getDataQueue() {
DataMessageMetadata m = new DataMessageMetadata();
// Build up data message metadata based on the sensors currently registered.
for(Sensor s: sensors){
m.getComponents().add(new ComponentMetadata(s.getId()));
}
return new DataQueue(dataQueue, m);
}
// Getter functions for variable parts
/**
* @return the actionLoops
*/
public List<ActionLoop> getActionLoops() {
return actionLoops;
}
/**
* @return the preActorActions
*/
public List<Action> getPreActorActions() {
return preActorActions;
}
/**
* @return the postActorActions
*/
public List<Action> getPostActorActions() {
return postActorActions;
}
/**
* @return the preSensorActions
*/
public List<Action> getPreSensorActions() {
return preSensorActions;
}
/**
* @return the postSensorActions
*/
public List<Action> getPostSensorActions() {
return postSensorActions;
}
/**
* @return the actors
*/
public List<Actor> getActors() {
return actors;
}
/**
* @return the sensors
*/
public List<Sensor> getSensors() {
return sensors;
}
/**
* @return the guard
*/
public Guard getGuard() {
return guard;
}
/**
* @param guard the guard to set
*/
public void setGuard(Guard guard) {
this.guard = guard;
}
/**
* @return the dataGroup
*/
public boolean isDataGroup() {
return dataGroup;
}
/**
* @param dataGroup the dataGroup to set
*/
public void setDataGroup(boolean dataGroup) {
this.dataGroup = dataGroup;
}
}

View File

@@ -1,162 +0,0 @@
/**
*
* Copyright 2012 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* This code is distributed in the hope that it will be useful, but without any
* warranty; without even the implied warranty of merchantability or fitness for
* a particular purpose. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.loops;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import jcifs.smb.SmbFile;
/**
* @author ebner
*
*/
public class DistributedFile {
private SmbFile smbfile = null;
private File file = null;
public DistributedFile(SmbFile file){
this.smbfile = file;
}
public DistributedFile(File file){
this.file = file;
}
public DistributedFile(String url) throws MalformedURLException{
if(url.startsWith("smb://")){
smbfile = new SmbFile(url);
}
else {
file = new File(url);
}
}
public String getCanonicalPath() throws IOException{
if(smbfile!=null){
return(smbfile.getCanonicalPath());
}
else{
return file.getCanonicalPath();
}
}
/**
* @return
* @throws IOException
*/
public boolean exists() throws IOException {
if(smbfile!=null){
return(smbfile.exists());
}
else{
return file.exists();
}
}
/**
* @return
*/
public boolean isDirectory() throws IOException {
if(smbfile!=null){
return(smbfile.isDirectory());
}
else{
return file.isDirectory();
}
}
/**
* @return
*/
public DistributedFile[] listFiles() throws IOException {
if(smbfile!=null){
SmbFile[] files = smbfile.listFiles();
DistributedFile[] dfiles = new DistributedFile[files.length];
for(int i=0;i<files.length;i++){
dfiles[i] = new DistributedFile(files[i]);
}
return(dfiles);
}
else{
File[] files = file.listFiles();
DistributedFile[] dfiles = new DistributedFile[files.length];
for(int i=0;i<files.length;i++){
dfiles[i] = new DistributedFile(files[i]);
}
return(dfiles);
}
}
/**
* @return
*/
public String getName() {
if(smbfile!=null){
return(smbfile.getName());
}
else{
return file.getName();
}
}
/**
* @return
*/
public boolean isFile() throws IOException {
if(smbfile!=null){
return(smbfile.isFile());
}
else{
return file.isFile();
}
}
/**
*
*/
public void delete() throws IOException {
if(smbfile!=null){
smbfile.delete();
}
else{
file.delete();
}
}
/**
* @return
*/
public InputStreamReader getInputStream() throws IOException {
if(smbfile!=null){
return(new InputStreamReader(smbfile.getInputStream()));
}
else{
return new FileReader(file);
}
}
}

View File

@@ -1,770 +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 gov.aps.jca.CAException;
import java.util.List;
import ch.psi.jcae.annotation.CaChannel;
import ch.psi.jcae.ChannelBean;
/**
* Bean holding all OTF channels and functionality
* @author ebner
*
*/
public class OTFBean {
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 =":UMOT")
private ChannelBean<String> motor;
@CaChannel(type=String.class, name=":MENC")
private ChannelBean<String> encoder;
@CaChannel(type=Double.class, name=":UBEG")
private ChannelBean<Double> begin;
@CaChannel(type=Double.class, name=":UBEG.DRVL")
private ChannelBean<Double> beginMin;
@CaChannel(type=Double.class, name=":UBEG.DRVH")
private ChannelBean<Double> beginMax;
@CaChannel(type=Double.class, name=":UEND")
private ChannelBean<Double> end;
@CaChannel(type=Double.class, name=":UEND.DRVL")
private ChannelBean<Double> endMin;
@CaChannel(type=Double.class, name=":UEND.DRVH")
private ChannelBean<Double> endMax;
@CaChannel(type=Double.class, name=":USSIZ")
private ChannelBean<Double> stepSize;
@CaChannel(type=Double.class, name=":USSIZ.DRVL")
private ChannelBean<Double> stepSizeMin;
@CaChannel(type=Double.class, name=":UITIM")
private ChannelBean<Double> integrationTime;
@CaChannel(type=Double.class, name=":UITIM.DRVL")
private ChannelBean<Double> integrationTimeMin;
@CaChannel(type=Double.class, name=":UITIM.DRVH")
private ChannelBean<Double> integrationTimeMax;
@CaChannel(type=Double.class, name=":UBCL")
private ChannelBean<Double> userBacklash;
@CaChannel(type=String.class, name=":NFSSE")
private ChannelBean<String> nfsServer;
@CaChannel(type=String.class, name=":NFSSH")
private ChannelBean<String> nfsShare;
@CaChannel(type=String.class, name=":DFNAM")
private ChannelBean<String> fileName;
@CaChannel(type=String.class, name=":FFORM")
private ChannelBean<String> fileNameFormat;
@CaChannel(type=Integer.class, name=":FCNT")
private ChannelBean<Integer> fileCount;
@CaChannel(type=Integer.class, name=":FCNT.B")
private ChannelBean<Integer> resetFileCounter;
@CaChannel(type=Boolean.class, name=":FAPPE")
private ChannelBean<Boolean> appendFile;
@CaChannel(type=Boolean.class, name=":FUSE")
private ChannelBean<Boolean> fileNameGeneration;
@CaChannel(type=Boolean.class, name=":UZIGZ")
private ChannelBean<Boolean> zigZag;
@CaChannel(type=Integer.class, name=":UCOM")
private ChannelBean<Integer> command;
@CaChannel(type=Boolean.class, name=":SCRU", monitor=true)
private ChannelBean<Boolean> scanRunning;
@CaChannel(type=Boolean.class, name=":MUENC")
private ChannelBean<Boolean> useEncoder;
@CaChannel(type=String.class, name={":CTM0",":CTM1",":CTM2",":CTM3",":CTM4",":CTM5",":CTM6",":CTM7"})
private List<ChannelBean<String>> monitoredChannels;
@CaChannel(type=Boolean.class, name=":OTF", monitor=true)
private ChannelBean<Boolean> running;
@CaChannel(type=Integer.class, name=":USTAT", monitor=true)
private ChannelBean<Integer> status;
@CaChannel(type=Boolean.class, name=":MOK", monitor=true)
private ChannelBean<Boolean> motorOk;
@CaChannel(type=Boolean.class, name=":EOK", monitor=true)
private ChannelBean<Boolean> encoderOk;
@CaChannel(type=String.class, name=":MSG")
private ChannelBean<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 (CAException 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 (CAException 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 CAException, InterruptedException{
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);
}
/**
* Get motor of the OTFScan axis
* @return Name of the OTF motor
* @throws CAException
*/
public String getMotor() throws CAException, InterruptedException {
return(this.motor.getValue());
}
/**
* Set motor of the OTFScan axis
* @param motor
* @throws CAException
*/
public void setMotor(String motor) throws CAException, InterruptedException {
this.motor.setValue(motor);
}
/**
* Get encoder of the OTFScan axis
* @return Name of the used encoder
* @throws CAException
*/
public String getEncoder() throws CAException, InterruptedException {
return(this.encoder.getValue());
}
/**
* Set encoder to use of the OTFScan axis
* @param encoder
* @throws CAException
*/
public void setEncoder(String encoder) throws CAException, InterruptedException {
this.encoder.setValue(encoder);
}
/**
* Get begin position of the scan
* @return Begin position scan
* @throws CAException
*/
public Double getBegin() throws CAException, InterruptedException {
return(this.begin.getValue());
}
/**
* Set begin position of scan
* @param begin
* @throws Exception
*/
public void setBegin(Double begin) throws CAException, InterruptedException {
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);
}
/**
* Get minimum value of the begin position
* @return Min value for begin
* @throws CAException
*/
public Double getMinBegin() throws CAException, InterruptedException {
return(this.beginMin.getValue());
}
/**
* Get maximum value of the begin position
* @return Max value for begin
* @throws CAException
*/
public Double getMaxBegin() throws CAException, InterruptedException {
return(this.beginMax.getValue());
}
/**
* Get end position of the scan
* @return End position scan
* @throws CAException
*/
public Double getEnd() throws CAException, InterruptedException {
return(this.end.getValue());
}
/**
* Set end positon of scan
* @param end
* @throws CAException
*/
public void setEnd(Double end) throws CAException, InterruptedException {
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);
}
/**
* Get minimum value of end position
* @return Min value for end
* @throws CAException
*/
public Double getMinEnd() throws CAException, InterruptedException {
return(this.endMin.getValue());
}
/**
* Get maximum value of end position
* @return Max value for end
* @throws CAException
*/
public Double getMaxEnd() throws CAException, InterruptedException {
return(this.endMax.getValue());
}
/**
* Get scan step size
* @return Step size
* @throws CAException
*/
public Double getStepSize() throws CAException, InterruptedException {
return(this.stepSize.getValue());
}
/**
* Set step size of scan
* @param stepSize
* @throws CAException
*/
public void setStepSize(Double stepSize) throws CAException, InterruptedException {
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);
}
/**
* Get minimum integration time
* @return Min value for step size
* @throws CAException
*/
public double getMinStepSize() throws CAException, InterruptedException {
return(this.stepSizeMin.getValue());
}
/**
* Get scan integration time (time that is spend in one step)
* @return Integration time
* @throws CAException
*/
public Double getIntegrationTime() throws CAException, InterruptedException {
return(this.integrationTime.getValue());
}
/**
* Set integration time of scan
* @param integrationTime
* @throws CAException
*/
public void setIntegrationTime(Double integrationTime) throws CAException, InterruptedException {
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);
}
/**
* Get minimum integration time
* @return Min value for integration time
* @throws CAException
*/
public Double getMinIntegrationTime() throws CAException, InterruptedException {
return(this.integrationTimeMin.getValue());
}
/**
* Get maximum integration time
* @return Max value for integration time
* @throws CAException
*/
public Double getMaxIntegrationTime() throws CAException, InterruptedException {
return(this.integrationTimeMax.getValue());
}
/**
* Get additional user defined backlash
* @return User backlash
* @throws CAException
*/
public Double getUserBacklash() throws CAException, InterruptedException {
return(this.userBacklash.getValue());
}
/**
* Set additional user defined backlash
* @param userBacklash
* @throws CAException
*/
public void setUserBacklash(Double userBacklash) throws CAException, InterruptedException {
if(userBacklash==null){
throw new IllegalArgumentException("User backlash must not be null");
}
this.userBacklash.setValue(userBacklash);
}
/**
* Get the current NFS server the data is written to
* @return Name of NFS server
* @throws CAException
*/
public String getNfsServer() throws CAException, InterruptedException {
return(this.nfsServer.getValue());
}
/**
* Set name of the NFS server the data is written to
* @param nfsServer
* @throws CAException
*/
public void setNfsServer(String nfsServer) throws CAException, InterruptedException {
this.nfsServer.setValue(nfsServer);
}
/**
* Get the NFS share the data is written to
* @return Name of NFS share
* @throws CAException
*/
public String getNfsShare() throws CAException, InterruptedException {
return(this.nfsShare.getValue());
}
/**
* Set name of the NFS share the data is written to
* @param nfsShare
* @throws CAException
*/
public void setNfsShare(String nfsShare) throws CAException, InterruptedException {
this.nfsShare.setValue(nfsShare);
}
/**
* Get the name of the data file
* @return Name of data file name
* @throws CAException
*/
public String getFileName() throws CAException, InterruptedException {
return(this.fileName.getValue());
}
/**
* Set name of the data file
* @param filename
* @throws CAException
*/
public void setFileName(String filename) throws CAException, InterruptedException {
this.fileName.setValue(filename);
}
/**
* Get File name formate
* @return Get format for file name
* @throws CAException
*/
public String getFileNameFormat() throws CAException, InterruptedException {
return(this.fileNameFormat.getValue());
}
/**
* Set file name formate of the data file
* @param fileNameFormat
* @throws Exception
*/
public void setFileNameFormat(String fileNameFormat) throws CAException, InterruptedException {
this.fileNameFormat.setValue(fileNameFormat);
}
/**
* Get value of the IOC based file name counter
* @return File counter
* @throws CAException
*/
public int getFileCounter() throws CAException, InterruptedException {
return(this.fileCount.getValue());
}
/**
* Reset the IOC based file counter
* @throws CAException
*/
public void resetFileCounter() throws CAException, InterruptedException {
this.resetFileCounter.setValue(1);
}
/**
* Get if append file option is activated
* @return Append file flag
* @throws CAException
*/
public boolean isAppendFile() throws CAException, InterruptedException {
return(this.appendFile.getValue());
}
/**
* Set whether to append the specified file if the file exists
* @param append
* @throws CAException
*/
public void setAppendFile(boolean append) throws CAException, InterruptedException {
this.appendFile.setValue(append);
}
/**
* Get if file name generation is on or off
* @return File name generation flag
* @throws CAException
*/
public boolean isFileNameGeneration() throws CAException, InterruptedException {
return(this.fileNameGeneration.getValue());
}
/**
* 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 CAException, InterruptedException {
this.fileNameGeneration.setValue(generation);
}
/**
* Get if ZigZag scan option is on or off
* @return ZigZag flag
* @throws CAException
*/
public boolean isZigZag() throws CAException, InterruptedException {
return(this.zigZag.getValue());
}
/**
* Set ZigZag scan mode on/off
* @param zigZag ZigZag mode on = true, ZigZag mode off = false
* @throws CAException
*/
public void setZigZag(boolean zigZag) throws CAException, InterruptedException {
this.zigZag.setValue(zigZag);
}
/**
* Get whether encoder is used
*/
public boolean isUseEncoder() throws CAException, InterruptedException {
return(this.useEncoder.getValue());
}
/**
* Set flag to use encoder
* @throws CAException
*/
public void setUseEncoder(boolean flag) throws CAException, InterruptedException {
this.useEncoder.setValue(flag);
}
/**
* Get the channels that are currently monitored by the OTFScan logic
* @return Names of the monitored channels
* @throws CAException
*/
public String[] getMonitoredChannels() throws CAException, InterruptedException {
String[] values = new String[this.monitoredChannels.size()];
for(int i=0; i<this.monitoredChannels.size();i++){
values[i] = monitoredChannels.get(i).getValue();
}
return(values);
}
/**
* 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 CAException, InterruptedException {
if(values.length>monitoredChannels.size()){
throw new IllegalArgumentException("Only up to "+monitoredChannels.size()+" monitored channels are supported by OTF");
}
for(int i=0; i<this.monitoredChannels.size(); i++){
if(values != null && i<values.length){
this.monitoredChannels.get(i).setValue(values[i]);
}
else{
this.monitoredChannels.get(i).setValue("");
}
}
}
/**
* Returns whether an scan is running
* @return Running flag
* @throws CAException
*/
public boolean isRunning() throws CAException, InterruptedException {
return(running.getValue());
}
/**
* Get status of the scan
* @return Status of the scan
* @throws CAException
*/
public Status getStatus() throws CAException, InterruptedException {
return(Status.values()[this.status.getValue()]);
}
/**
* Get the (error) message from the OTF records
* @return Message from OTF C logic
* @throws CAException
*/
public String getMessage() throws CAException, InterruptedException {
return(message.getValue());
}
/**
* 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 CAException, InterruptedException {
return(motorOk.getValue());
}
/**
* 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 CAException, InterruptedException {
motorOk.waitForValue(true, timeout);
}
/**
* 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 CAException, InterruptedException {
motorOk.waitForValue(false, timeout);
}
public void waitUntilEncoderOk(long timeout) throws CAException, InterruptedException {
if(!useEncoder.getValue()){
return;
}
encoderOk.waitForValue(true, timeout);
}
}

View File

@@ -1,521 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.loops;
import java.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.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.logging.Logger;
//import jcifs.smb.SmbException;
//import jcifs.smb.SmbFile;
import gov.aps.jca.CAException;
import ch.psi.fda.core.Action;
import ch.psi.fda.core.ActionLoop;
import ch.psi.fda.core.Sensor;
import ch.psi.fda.core.actors.OTFActuator;
import ch.psi.fda.core.messages.ComponentMetadata;
import ch.psi.fda.core.messages.DataMessage;
import ch.psi.fda.core.messages.DataMessageMetadata;
import ch.psi.fda.core.messages.DataQueue;
import ch.psi.fda.core.messages.EndOfStreamMessage;
import ch.psi.fda.core.messages.Message;
import ch.psi.fda.core.sensors.MillisecondTimestampSensor;
import ch.psi.fda.core.sensors.OTFNamedChannelSensor;
import ch.psi.fda.core.sensors.OTFReadbackSensor;
import ch.psi.fda.core.sensors.OTFScalerChannelSensor;
import ch.psi.jcae.ChannelBeanFactory;
/**
* ActionLoop that is implementing the OTF Scan logic.
* While executing the loop a full OTF scan procedure is executed.
* @author ebner
*
*/
public class OTFLoop implements ActionLoop {
// Get Logger
private static Logger logger = Logger.getLogger(OTFLoop.class.getName());
/**
* 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;
// Constants
/**
* 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 OTFBean 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;
/**
* Special OTF Actuator
*/
private OTFActuator actor = null;
/**
* 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;
/**
* Data queue sensor data is posted to. A message consists of a list of data objects
* that are read out of the sensors of this loop.
*/
private BlockingQueue<Message> dataQueue;
/**
* Flag that indicates that the loop was requested to abort.
*/
private volatile boolean abort = false;
/**
* Constructor
* @param channelPrefix Prefix of the OTF related records, e.g. MTEST-HW3-OTF
* @param server NFS server the OTF C Logic should put its data to
* @param share Share on NFS server to put the OTF C Logic data
* @param smbShare SMB share to get the data written by the OTF C Logic
* @param zigZag Operate loop in zig zag mode
*/
public OTFLoop(String channelPrefix, String server, String share, String smbShare, boolean zigZag){
// Initialize connection to the OTF records
try {
this.obean = new OTFBean();
ChannelBeanFactory.getFactory().createChannelBeans(obean, channelPrefix);
} catch (CAException e) {
throw new IllegalArgumentException("Unable to connect to the OTF channels",e);
} catch (InterruptedException e) {
throw new RuntimeException("Unable to connect to the OTF channels",e);
}
// 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>();
this.dataQueue = new LinkedBlockingQueue<Message>(2000);
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Action#execute()
*/
@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
dataQueue.put(new EndOfStreamMessage(dataGroup));
// Increase execution count
executionCount++;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Action#abort()
*/
@Override
public void abort() {
// Abort otf scan logic
obean.abort();
abort=true;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.ActionLoop#prepare()
*/
@Override
public void prepare() {
executionCount = 0;
// Set abort flag to false
abort=false;
// Check whether actor is set for the loop
if(actor == null){
throw new IllegalStateException("No actor specified for this loop");
}
// list with all monitored channels
List<String> monitoredChannels = new ArrayList<String>();
dataIndexes = new ArrayList<Integer>();
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 MillisecondTimestampSensor){
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(actor.getName());
obean.waitUntilMotorOk(timeout);
obean.setBegin(actor.getStart());
obean.setEnd(actor.getEnd());
obean.setStepSize(actor.getStepSize());
obean.setIntegrationTime(actor.getIntegrationTime());
// Override encoder if specified
if(actor.getReadback()!=null){
obean.setUseEncoder(true);
obean.setEncoder(actor.getReadback());
obean.waitUntilEncoderOk(timeout);
}
// Set user backlash
obean.setUserBacklash(actor.getAdditionalBacklash());
// 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(CAException e){
throw new RuntimeException("Unable to set OTF configuration parameters",e);
} catch (InterruptedException 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);
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.ActionLoop#cleanup()
*/
@Override
public void cleanup() {
// TODO Auto-generated method stub
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Action#destroy()
*/
@Override
public void destroy() {
// Close all connections used by the OTFBean
try {
ChannelBeanFactory.getFactory().destroyChannelBeans(obean);
} catch (CAException e) {
throw new RuntimeException("Unable to destroy channels",e);
} catch (InterruptedException e) {
throw new RuntimeException("Unable to destroy channels",e);
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.ActionLoop#getPreActions()
*/
@Override
public List<Action> getPreActions() {
return preActions;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.ActionLoop#getPostActions()
*/
@Override
public List<Action> getPostActions() {
return postActions;
}
/**
* The structure of the data message depends on the sensors registered at this loop
* at the time this method is called.
* @return the data queue and the metadata of the data messages
*/
public DataQueue getDataQueue() {
DataMessageMetadata m = new DataMessageMetadata();
// Build up data message metadata based on the sensors currently registered.
for(Sensor s: sensors){
m.getComponents().add(new ComponentMetadata(s.getId()));
}
return new DataQueue(dataQueue, m);
}
/**
* Collect data written by the OTFScan logic
* @param dataSet
* @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();
// 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));
}
}
dataQueue.put(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);
}
}
// Getter functions for variable parts
/**
* @return the sensors
*/
public List<Sensor> getSensors() {
return sensors;
}
/**
* @return the actor
*/
public OTFActuator getActor() {
return actor;
}
/**
* @param actor the actor to set
*/
public void setActor(OTFActuator actor) {
this.actor = actor;
}
/**
* @return the dataGroup
*/
public boolean isDataGroup() {
return dataGroup;
}
/**
* @param dataGroup the dataGroup to set
*/
public void setDataGroup(boolean dataGroup) {
this.dataGroup = dataGroup;
}
}

View File

@@ -1,157 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.loops.cr;
import ch.psi.jcae.ChannelBean;
import ch.psi.jcae.annotation.CaChannel;
/**
* @author ebner
*
*/
public class CrlogicChannelsTemplate {
/**
* Status of the OTFSCAN IOC logic
*/
public enum Status { SETUP, INACTIVE, INITIALIZE, ACTIVE, STOP, FAULT, ERROR };
/**
* Ticks per second - IOC setting
* ATTENTION - This field must only be set bu the IOC - ATTENTION
*/
@CaChannel(type=Integer.class, name =":TPS")
private ChannelBean<Integer> ticksPerSecond;
/**
* Status of the OTFSCAN IOC logic
*/
@CaChannel(type=String.class, name =":STATUS")
private ChannelBean<String> status;
/**
* Message from the OTFSCAN IOC logic
*/
@CaChannel(type=String.class, name =":MSG")
private ChannelBean<String> message;
/**
* IOC ticks between data acquisition interrupts
*/
@CaChannel(type=Integer.class, name =":TBINT")
private ChannelBean<Integer> ticksBetweenInterrupts;
/**
* Name or ip address of the NFS server to save the data to
* (depending on the IOC setup)
*/
@CaChannel(type=String.class, name =":NFSSE")
private ChannelBean<String> nfsServer;
/**
* Name of the NFS share on the NFS server
*/
@CaChannel(type=String.class, name =":NFSSH")
private ChannelBean<String> nfsShare;
/**
* Name of the data file
*/
@CaChannel(type=String.class, name =":DFNAM")
private ChannelBean<String> dataFile;
/**
* Flag to identify whether the data file should be appended
*/
@CaChannel(type=Boolean.class, name =":FAPPE")
private ChannelBean<Boolean> appendFile;
/**
* Readout resources
*/
@CaChannel(type=String[].class, name =":RRES")
private ChannelBean<String[]> readoutResources;
/**
* @return the ticksPerSecond
*/
public ChannelBean<Integer> getTicksPerSecond() {
return ticksPerSecond;
}
/**
* @return the status
*/
public ChannelBean<String> getStatus() {
return status;
}
/**
* @return the message
*/
public ChannelBean<String> getMessage() {
return message;
}
/**
* @return the ticksBetweenInterrupts
*/
public ChannelBean<Integer> getTicksBetweenInterrupts() {
return ticksBetweenInterrupts;
}
/**
* @return the nfsServer
*/
public ChannelBean<String> getNfsServer() {
return nfsServer;
}
/**
* @return the nfsShare
*/
public ChannelBean<String> getNfsShare() {
return nfsShare;
}
/**
* @return the dataFile
*/
public ChannelBean<String> getDataFile() {
return dataFile;
}
/**
* @return the appendFile
*/
public ChannelBean<Boolean> getAppendFile() {
return appendFile;
}
/**
* @return the readoutResources
*/
public ChannelBean<String[]> getReadoutResources() {
return readoutResources;
}
}

View File

@@ -1,47 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.loops.cr;
/**
* @author ebner
*
*/
public class CrlogicDeltaDataFilter {
private Double lastValue = null;
public void reset(){
lastValue = null;
}
public Double delta(Double value){
Double lvalue = lastValue;
lastValue = value;
if(lvalue==null){
return Double.NaN;
}
else{
// Return delta
return(value-lvalue);
}
}
}

View File

@@ -1,898 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.loops.cr;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.Semaphore;
import java.util.logging.Logger;
import jcifs.smb.SmbFile;
import gov.aps.jca.CAException;
import ch.psi.fda.core.Action;
import ch.psi.fda.core.ActionLoop;
import ch.psi.fda.core.Sensor;
import ch.psi.fda.core.actors.OTFActuator;
import ch.psi.fda.core.messages.ComponentMetadata;
import ch.psi.fda.core.messages.DataMessage;
import ch.psi.fda.core.messages.DataMessageMetadata;
import ch.psi.fda.core.messages.DataQueue;
import ch.psi.fda.core.messages.EndOfStreamMessage;
import ch.psi.fda.core.messages.Message;
import ch.psi.fda.core.sensors.MillisecondTimestampSensor;
import ch.psi.fda.core.sensors.OTFNamedChannelSensor;
import ch.psi.fda.core.sensors.OTFScalerChannelSensor;
import ch.psi.jcae.ChannelBeanFactory;
/**
* @author ebner
*
* While using Crlogic the IOC system clock rate should/must be set to 1000 (default 60)
*
* sysClkRateSet 1000
*
*/
public class CrlogicLoop implements ActionLoop {
// Get Logger
private static final Logger logger = Logger.getLogger(CrlogicLoop.class.getName());
/**
* Flag to indicate whether the data of this loop will be grouped
* According to this flag the dataGroup flag in EndOfStream will be set.
*/
private boolean dataGroup = false;
private boolean keepTmpFiles = false;
private BlockingQueue<String> readQueue = new LinkedBlockingQueue<String>();
private volatile boolean stopReadoutThread = false;
private Thread readoutThread;
// Constants
/**
* Default timeout (in milliseconds) for wait operations
*/
private long startStopTimeout = 8000;
/**
* Name of the NFS server to place the data of the OTF logic
*/
private final String server;
/**
* Share on the NFS server to put the OTF data on to
*/
private final String share;
/**
* SMB share to access the data written by the OTF C logic
*/
private final String smbShare;
/**
* Flag whether the actor of this loop should move in zig zag mode
*/
private final boolean zigZag;
boolean useReadback;
boolean useEncoder;
/**
* List of actions that are executed at the beginning of the loop.
*/
private List<Action> preActions;
/**
* List of actions that are executed at the end of the loop.
*/
private List<Action> postActions;
/**
* Prefix for the CRLOGIC channels
*/
private String prefix;
private CrlogicChannelsTemplate template;
private MotorChannelsTemplate motortemplate;
/**
* Semaphore to ensure that data is read in correct sequence
*/
private Semaphore semaphore = new Semaphore(1);
/**
* Special OTF Actuator
*/
private OTFActuator actuator = null;
/**
* List of sensors of this loop
*/
private List<Sensor> sensors;
private List<String> readoutResources;
private Map<Integer, CrlogicDeltaDataFilter> scalerIndices;
private CrlogicRangeDataFilter crlogicDataFilter;
/**
* Data queue sensor data is posted to. A message consists of a list of data objects
* that are read out of the sensors of this loop.
*/
private BlockingQueue<Message> dataQueue;
/**
* Abort status
*/
private boolean abort = false;
private boolean abortForce = false;
private Thread executionThread = null;
public CrlogicLoop(String prefix, String server, String share, String smbShare, boolean zigZag){
this.prefix = prefix;
this.server = server;
this.share = share;
this.smbShare = smbShare;
this.zigZag = zigZag;
// Initialize lists used by the loop
this.preActions = new ArrayList<Action>();
this.postActions = new ArrayList<Action>();
this.sensors = new ArrayList<Sensor>();
this.readoutResources = new ArrayList<String>();
this.scalerIndices = new HashMap<Integer, CrlogicDeltaDataFilter>();
this.crlogicDataFilter = new CrlogicRangeDataFilter();
this.dataQueue = new LinkedBlockingQueue<Message>(2000);
}
/**
* Collect data from share
* @param tmpFileName Name of the temporary file
* @throws InterruptedException
* @throws IOException
*/
private void collectData(String tmpDir, String tmpFileName) throws InterruptedException, IOException {
semaphore.acquire();
if (tmpDir.startsWith("smb:")) {
SmbFile tmpFile = new SmbFile(tmpDir, tmpFileName);
logger.info("Collect data from " + tmpFile.getCanonicalPath());
SmbFile lockfile = new SmbFile(tmpFile.getCanonicalPath() + ".lock");
logger.info("Wait until file is written [lock file: " + lockfile.getCanonicalPath() + "]");
// Wait until file is created
while ((!tmpFile.exists()) || lockfile.exists()) {
try{
Thread.sleep(100);
}
catch(InterruptedException e){
abort=true;
}
if(abort){
// If abort is issued while waiting for data immediately return without
// trying to read the data
return;
}
}
InputStreamReader inreader = new InputStreamReader(tmpFile.getInputStream());
BufferedReader in = new BufferedReader(inreader);
String line;
boolean firstline = true;
int linecount=0;
int mcounter=0;
// boolean wasInRangeBefore = false;
boolean discardAnyway = false;
while (true) {
line = in.readLine();
linecount++;
if (line == null) {
break;
} else {
// if(line.matches("^\\[.*")){
if (line.matches("^ *#.*")) {
// Skip header/comment lines
// logger.info("HEADER: " + line);
} else {
if (firstline) {
firstline = false;
continue;
}
// logger.info(line);
// Write into queue
DataMessage message = new DataMessage();
String[] tokens = line.split("\t");
boolean use = true;
for(int i=0;i<tokens.length;i++){
String t = tokens[i];
Double val;
if(i==0){
Double raw = new Double(t);
if(useEncoder){
val = crlogicDataFilter.calculatePositionMotorUseEncoder(raw);
}
else if(useReadback){
val = crlogicDataFilter.calculatePositionMotorUseReadback(raw);
}
else{
val = crlogicDataFilter.calculatePositionMotor(raw);
}
// Check whether data is within the configured range - otherwise drop data
use = crlogicDataFilter.filter(val);
// if(!use){
// break;
// }
}
else if(scalerIndices.containsKey(i)){
CrlogicDeltaDataFilter f = scalerIndices.get(i);
val = f.delta(new Double(t));
}
else{
val = new Double(t);
}
message.getData().add(val);
}
// Does not work if zigzag, ...
// // Use this to filter out motor retry movements at the end of the scan
// wasInRangeBefore = wasInRangeBefore | use;
// if(!use && wasInRangeBefore){
// discardAnyway=true;
// // Optimization - terminate read loop once range is left
// logger.info("Terminate read loop because point is outside range");
// break;
// }
// Filter data
if(use && !discardAnyway){
dataQueue.put(message);
mcounter++;
}
}
}
}
in.close();
inreader.close();
logger.info("Lines read: "+linecount+" Messages generated (after filtering): "+mcounter);
// Remove temporary file
if(!keepTmpFiles){
tmpFile.delete();
}
}
else{
// TODO - File in local file system
}
// Issue end of loop control message
dataQueue.put(new EndOfStreamMessage(dataGroup));
semaphore.release();
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Action#execute()
*/
@Override
public void execute() throws InterruptedException {
try{
double stepSize = actuator.getStepSize();
double start = actuator.getStart();
double end = actuator.getEnd();
double integrationTime = actuator.getIntegrationTime();
double ubacklash = actuator.getAdditionalBacklash();
// Set values for the datafilter
crlogicDataFilter.setStart(actuator.getStart());
crlogicDataFilter.setEnd(actuator.getEnd());
// Reset data filter
for(Integer k: scalerIndices.keySet()){
scalerIndices.get(k).reset();
}
synchronized(this){
// Set abort state to false
abort = false;
abortForce = false;
// Set execution thread to current thread
executionThread = Thread.currentThread();
}
// TODO each actuator will result in an additional sensor (at the beginning)
// Dependent on actuator settings (readback use encoder, ...)
// TODO filename generation?
final String tmpFileName = "tmp-"+System.currentTimeMillis()+".txt";
Long timeout = 600000l; // 10 minutes move timeout
// Check if logic is inactive, otherwise return early
if(!template.getStatus().getValue().equals(CrlogicChannelsTemplate.Status.INACTIVE.toString())){
logger.info("CRLOGIC is not inactive!");
// TODO Decide what to do in this situation
if(template.getStatus().getValue().equals(CrlogicChannelsTemplate.Status.FAULT.toString())){
// If in fault show message and recover
logger.info("CRLOGIC in FAULT state");
logger.info("Error message: "+template.getMessage().getValue());
logger.info("Recover logic and set it to INACTIVE");
template.getStatus().setValue(CrlogicChannelsTemplate.Status.INACTIVE.toString());
}
else if(template.getStatus().getValue().equals(CrlogicChannelsTemplate.Status.ACTIVE.toString())){
template.getStatus().setValue(CrlogicChannelsTemplate.Status.STOP.toString());
template.getStatus().waitForValue(CrlogicChannelsTemplate.Status.INACTIVE.toString(), startStopTimeout);
}
else{
throw new RuntimeException("CRLOGIC is not inactive");
}
}
logger.info("Set parameters");
template.getNfsServer().setValue(server);
template.getNfsShare().setValue(share);
template.getDataFile().setValue(tmpFileName);
int tps = template.getTicksPerSecond().getValue();
logger.info("Ticks per second: "+tps);
logger.info("Set readout resources");
template.getReadoutResources().setValue(readoutResources.toArray(new String[readoutResources.size()]));
// Set ticks between interrupt to integration time
int ticks = (int)(tps*integrationTime);
template.getTicksBetweenInterrupts().setValue(ticks);
// Prepare motor
double totalTimeSeconds = Math.abs((end-start)/stepSize*integrationTime);
int hours = (int) Math.floor(totalTimeSeconds/60/60);
int minutes = (int) Math.floor(totalTimeSeconds/60-hours*60);
int seconds = (int) Math.floor(totalTimeSeconds-hours*60*60-minutes*60);
logger.info("Estimated time: "+hours+":"+minutes+":"+seconds);
int direction = 1;
if(end-start<0){
direction = -1;
}
double motorBaseSpeed = motortemplate.getBaseSpeed().getValue();
double motorHighLimit = motortemplate.getHighLimit().getValue();
double motorLowLimit = motortemplate.getLowLimit().getValue();
double motorBacklash = motortemplate.getBacklashDistance().getValue();
boolean respectMotorMinSpeed = false; // if false set min speed to 0
double motorMinSpeed = 0;
if(respectMotorMinSpeed){
motorMinSpeed = motorBaseSpeed;
}
// Check user parameters
// TODO start and end values must be between the motor high and low value - otherwise fail
if(start>motorHighLimit || start<motorLowLimit){
// Start value is outside motor high and/or low value
logger.info("Start value is outside motor high and/or low value");
throw new IllegalArgumentException("Start value is outside motor high and/or low value");
}
if(end>motorHighLimit || end<motorLowLimit){
// End value is outside motor high and/or low value
logger.info("End value is outside motor high and/or low value");
throw new IllegalArgumentException("End value is outside motor high and/or low value");
}
// TODO Check minimum step size
int minimumTicks = 10;
double minStepSize = motorMinSpeed*(minimumTicks/tps);
if(stepSize<minStepSize){
// Step size is too small
logger.info("Step size is too small");
throw new IllegalArgumentException("Step size is too small");
}
// TODO Check integration time
if(motorMinSpeed>0){
double maxIntegrationTime = stepSize/motorMinSpeed;
if(integrationTime>maxIntegrationTime){
logger.info("Integration time is too big");
// Integration time is too big
throw new IllegalArgumentException("Integration time is too big");
}
}
double motorMaxSpeed = motortemplate.getVelocity().getValue();
double minIntegrationTime = Math.min( (stepSize/motorMaxSpeed), ((double)minimumTicks/(double)tps) );
if(integrationTime<minIntegrationTime){
// Integration time is too small
logger.info("Integration time is too small [min integration time: "+minIntegrationTime+"]");
throw new IllegalArgumentException("Integration time is too small [min integration time: "+minIntegrationTime+"]");
}
// TODO Calculate and set motor speed, backlash, etc.
double motorSpeed = stepSize/integrationTime;
double backlash = (0.5*motorSpeed*motortemplate.getAccelerationTime().getValue())+motorBacklash+ubacklash;
double realEnd = end+(backlash*direction);
double realStart = start-(backlash*direction);
// Move to start
logger.info("Move motor to start ["+realStart+"]");
motortemplate.getSetValue().setValue(realStart, timeout); // Will block until move is done
// Set motor paramters
// Backup settings
logger.info("Backup motor settings");
double backupSpeed = motortemplate.getVelocity().getValue();
double backupBacklash = motorBacklash;
double backupMinSpeed = motorBaseSpeed;
try{
// Set motor settings
logger.info("Update motor settings");
// if(!respectMotorMinSpeed){
// motortemplate.getBaseSpeed().setValue(0d);
// }
// Set base speed as fast as possible but not faster than the original base speed.
double base = motorBaseSpeed;
if(motorSpeed<base){
base = motorSpeed;
}
motortemplate.getBaseSpeed().setValue(base);
motortemplate.getVelocity().setValue(motorSpeed);
motortemplate.getBacklashDistance().setValue(0d);
// Execute pre actions
for(Action action: preActions){
action.execute();
}
// Start crlogic logic
logger.info("Start CRLOGIC");
template.getStatus().setValue(CrlogicChannelsTemplate.Status.INITIALIZE.toString());
try{
template.getStatus().waitForValue(CrlogicChannelsTemplate.Status.ACTIVE.toString(), startStopTimeout);
}
catch(CAException e){
logger.info( "Failed to start CRLOGIC. Logic in status: "+template.getStatus().getValue() );
if(template.getStatus().getValue().equals(CrlogicChannelsTemplate.Status.FAULT.toString())){
logger.info("Error message: "+template.getMessage().getValue());
}
// Recover to inactive
template.getStatus().setValue(CrlogicChannelsTemplate.Status.INACTIVE.toString());
// TODO Improve error handling
throw new RuntimeException("Failed to start CRLOGIC. Logic in status: "+template.getStatus().getValue()+ " Error message: "+template.getMessage().getValue(), e);
}
// Move motor(s) to end / wait until motor is stopped
logger.info("Move motor to end ["+realEnd+"]");
try{
motortemplate.getSetValue().setValue(realEnd, timeout); // Will block until move is done
}
catch (InterruptedException e) {
if(abort & (!abortForce)){
// Abort motor move
motortemplate.getCommand().setValue(MotorChannelsTemplate.Commands.Stop.ordinal());
motortemplate.getCommand().setValue(MotorChannelsTemplate.Commands.Go.ordinal());
}
else{
throw e;
}
}
logger.info("Motor reached end position");
// Stop crlogic logic
logger.info("Stop CRLOGIC");
template.getStatus().setValue(CrlogicChannelsTemplate.Status.STOP.toString());
// Wait until stopped
logger.info("Wait until stopped");
try{
template.getStatus().waitForValue(CrlogicChannelsTemplate.Status.INACTIVE.toString(), startStopTimeout);
}
catch(CAException e){
logger.info( "Failed to stop CRLOGIC. Logic in status: "+template.getStatus().getValue() );
// TODO Improve error handling
throw new RuntimeException("Failed to stop CRLOGIC. Logic in status: "+template.getStatus().getValue(), e);
}
logger.info("CRLOGIC is now stopped");
// Execute post actions
for(Action action: postActions){
action.execute();
}
}
finally{
logger.info("Restore motor settings");
motortemplate.getBaseSpeed().setValue(backupMinSpeed);
motortemplate.getVelocity().setValue(backupSpeed);
motortemplate.getBacklashDistance().setValue(backupBacklash);
}
// Request read of data file
readQueue.put(tmpFileName);
// // Read data
// Thread t = new Thread(new Runnable() {
//
// @Override
// public void run() {
// try {
// collectData(smbShare, tmpFileName);
// } catch (InterruptedException e) {
// throw new RuntimeException("Unable to read CRLOGIC raw data file",e);
// } catch (IOException e) {
// throw new RuntimeException("Unable to read CRLOGIC raw data file",e);
// }
// }
// });
// t.start();
if(zigZag){
// Swap start and end
double aend = actuator.getEnd();
actuator.setEnd(actuator.getStart());
actuator.setStart(aend);
}
synchronized(this){
executionThread = null;
}
}
catch(CAException e){
throw new RuntimeException("Unable to execute crloop", e);
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Action#abort()
*/
@Override
public void abort() {
abort(false);
}
/**
* Abort logic
* @param force
*/
public synchronized void abort(boolean force){
abort = true;
abortForce = force;
// executionThread variable guarded by "this"
if(executionThread != null){
executionThread.interrupt();
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Action#destroy()
*/
@Override
public void destroy() {
stopReadoutThread = true;
readoutThread.interrupt();
// TODO eventually interrupt readout thread
try {
ChannelBeanFactory.getFactory().destroyChannelBeans(template);
ChannelBeanFactory.getFactory().destroyChannelBeans(motortemplate);
template = null;
motortemplate = null;
} catch (Exception e) {
throw new RuntimeException("Unable to destroy CrlogicLoop", e);
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.ActionLoop#prepare()
*/
@Override
public void prepare() {
stopReadoutThread = false;
// Start readout Thread
readoutThread = new Thread(new Runnable() {
@Override
public void run() {
while(!stopReadoutThread){
String file;
try {
file = readQueue.take();
} catch (InterruptedException e) {
break;
}
// TODO Read file and
try {
collectData(smbShare, file);
} catch (InterruptedException e) {
throw new RuntimeException("Unable to read CRLOGIC raw data file",e);
} catch (IOException e) {
throw new RuntimeException("Unable to read CRLOGIC raw data file",e);
}
}
}
});
readoutThread.start();
try{
// Connect crlogic channels
template = new CrlogicChannelsTemplate();
logger.info("Connect channels");
ChannelBeanFactory.getFactory().createChannelBeans(template, prefix);
// Connect motor channels
motortemplate = new MotorChannelsTemplate();
ChannelBeanFactory.getFactory().createChannelBeans(motortemplate, actuator.getName());
useReadback = motortemplate.getUseReadback().getValue();
useEncoder = motortemplate.getUseEncoder().getValue();
logger.info("Motor type: "+ MotorChannelsTemplate.Type.values()[motortemplate.getType().getValue()]);
logger.info("Motor use readback: "+useReadback);
logger.info("Motor use encoder: "+useEncoder);
// TODO build up list of readout resources (based on sensors)
readoutResources.clear();
// first sensor is the actuator
// Determine mode of motor
if((!useReadback) && (!useEncoder)){
// Open loop
if(actuator.getReadback()!=null){
throw new IllegalArgumentException("Readback not supported if motor is configured in open loop");
}
else{
readoutResources.add(actuator.getName());
}
}
else if(useReadback && (!useEncoder)){
String readback;
// use readback link
if(actuator.getReadback()!=null){
// Use specified readback
readback = (actuator.getReadback());
}
else{
// Set resouce to readback link
readback = (motortemplate.getReadbackLink().getValue());
readback = readback.replaceAll(" +.*", ""); // remove NPP etc at the end
}
readoutResources.add(readback);
// Fill readback encoder settings
// Connect to encoder
EncoderChannelsTemplate encodertemplate = new EncoderChannelsTemplate();
ChannelBeanFactory.getFactory().createChannelBeans(encodertemplate, readback);
// Read encoder settings
if(encodertemplate.getDirection().getValue()==EncoderChannelsTemplate.Direction.Positive.ordinal()){
crlogicDataFilter.setEncoderDirection(1);
}
else{
crlogicDataFilter.setEncoderDirection(-1);
}
crlogicDataFilter.setEncoderOffset(encodertemplate.getOffset().getValue());
crlogicDataFilter.setEncoderResolution(encodertemplate.getResolution().getValue());
// Disconnect from encoder
ChannelBeanFactory.getFactory().destroyChannelBeans(encodertemplate);
}
else if (useEncoder && (!useReadback)){
// use readback link
if(actuator.getReadback()!=null){
throw new IllegalArgumentException("Readback not supported if motor is configured to use encoder");
}
else{
// Set resouce to readback link
readoutResources.add(actuator.getName()+"_ENC");
}
}
else{
throw new IllegalArgumentException("Motor configuration not supportet: use readback - "+useReadback+" use encoder - "+useEncoder);
}
// Fill Motor specific settings
if(motortemplate.getDirection().getValue()==MotorChannelsTemplate.Direction.Positive.ordinal()){
crlogicDataFilter.setMotorDirection(1);
}
else{
crlogicDataFilter.setMotorDirection(-1);
}
crlogicDataFilter.setMotorEncoderResolution(motortemplate.getEncoderResolution().getValue());
crlogicDataFilter.setMotorOffset(motortemplate.getOffset().getValue());
crlogicDataFilter.setMotorReadbackResolution(motortemplate.getReadbackResolution().getValue());
crlogicDataFilter.setMotorResolution(motortemplate.getMotorResolution().getValue());
// Clear all indices
scalerIndices.clear();
int c = 1; // We start at 1 because the actuator right now is an implicit sensor
for(Sensor s: sensors){
if(s instanceof OTFNamedChannelSensor){
// Monitored channel (MUST be configured MODULE ID'S)
OTFNamedChannelSensor so = (OTFNamedChannelSensor) s;
readoutResources.add(so.getName());
}
else if (s instanceof OTFScalerChannelSensor){
OTFScalerChannelSensor so = (OTFScalerChannelSensor) s;
readoutResources.add("SCALER"+so.getIndex());
scalerIndices.put(c, new CrlogicDeltaDataFilter());
}
else if (s instanceof MillisecondTimestampSensor){
readoutResources.add("TIMESTAMP");
}
else{
throw new IllegalArgumentException("Sensor type "+s.getClass()+" is not supported by this loop");
}
c++;
}
// Workaround - somehow one has to add an empty thing to the value otherwise the c logic
// does not pick up the end
readoutResources.add("");
}
catch(Exception e){
throw new RuntimeException("Unable to prepare crloop: ",e);
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.ActionLoop#cleanup()
*/
@Override
public void cleanup() {
// TODO Auto-generated method stub
}
/* (non-Javadoc)
* @see ch.psi.fda.core.ActionLoop#getPreActions()
*/
@Override
public List<Action> getPreActions() {
return preActions;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.ActionLoop#getPostActions()
*/
@Override
public List<Action> getPostActions() {
return postActions;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.ActionLoop#isDataGroup()
*/
@Override
public boolean isDataGroup() {
// TODO Auto-generated method stub
return dataGroup;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.ActionLoop#setDataGroup(boolean)
*/
@Override
public void setDataGroup(boolean dataGroup) {
this.dataGroup = dataGroup;
}
/**
* @return the sensors
*/
public List<Sensor> getSensors() {
return sensors;
}
/**
* @return the actor
*/
public OTFActuator getActor() {
return actuator;
}
/**
* @param actor the actor to set
*/
public void setActor(OTFActuator actor) {
this.actuator = actor;
}
/**
* The structure of the data message depends on the sensors registered at this loop
* at the time this method is called.
* @return the data queue and the metadata of the data messages
*/
public DataQueue getDataQueue() {
DataMessageMetadata m = new DataMessageMetadata();
// Build up data message metadata based on the sensors currently registered.
m.getComponents().add(new ComponentMetadata(actuator.getId()));
for(Sensor s: sensors){
m.getComponents().add(new ComponentMetadata(s.getId()));
}
return new DataQueue(dataQueue, m);
}
/**
* @return the keepTmpFiles
*/
public boolean isKeepTmpFiles() {
return keepTmpFiles;
}
/**
* @param keepTmpFiles the keepTmpFiles to set
*/
public void setKeepTmpFiles(boolean keepTmpFiles) {
this.keepTmpFiles = keepTmpFiles;
}
}

View File

@@ -1,274 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.loops.cr;
/**
* @author ebner
*
*/
public class CrlogicRangeDataFilter {
private double motorResolution = 1;
private int motorDirection = 1;
private double motorOffset = 0;
private double motorReadbackResolution = 1;
private double motorEncoderResolution = 1;
private double encoderOffset = 0;
private double encoderResolution = 1;
private int encoderDirection = 1;
private double start = 0;
private double end = 0;
private boolean positive = true;
/**
* Marker whether the value was equal
*/
private boolean wasEqualBefore = false;
/**
* @return the motorResolution
*/
public double getMotorResolution() {
return motorResolution;
}
/**
* @param motorResolution the motorResolution to set
*/
public void setMotorResolution(double motorResolution) {
this.motorResolution = motorResolution;
}
/**
* @return the motorDirection
*/
public int getMotorDirection() {
return motorDirection;
}
/**
* @param motorDirection the motorDirection to set
*/
public void setMotorDirection(int motorDirection) {
this.motorDirection = motorDirection;
}
/**
* @return the motorOffset
*/
public double getMotorOffset() {
return motorOffset;
}
/**
* @param motorOffset the motorOffset to set
*/
public void setMotorOffset(double motorOffset) {
this.motorOffset = motorOffset;
}
/**
* @return the motorReadbackResolution
*/
public double getMotorReadbackResolution() {
return motorReadbackResolution;
}
/**
* @param motorReadbackResolution the motorReadbackResolution to set
*/
public void setMotorReadbackResolution(double motorReadbackResolution) {
this.motorReadbackResolution = motorReadbackResolution;
}
/**
* @return the motorEncoderResolution
*/
public double getMotorEncoderResolution() {
return motorEncoderResolution;
}
/**
* @param motorEncoderResolution the motorEncoderResolution to set
*/
public void setMotorEncoderResolution(double motorEncoderResolution) {
this.motorEncoderResolution = motorEncoderResolution;
}
/**
* @return the encoderOffset
*/
public double getEncoderOffset() {
return encoderOffset;
}
/**
* @param encoderOffset the encoderOffset to set
*/
public void setEncoderOffset(double encoderOffset) {
this.encoderOffset = encoderOffset;
}
/**
* @return the encoderResolution
*/
public double getEncoderResolution() {
return encoderResolution;
}
/**
* @param encoderResolution the encoderResolution to set
*/
public void setEncoderResolution(double encoderResolution) {
this.encoderResolution = encoderResolution;
}
/**
* @return the encoderDirection
*/
public int getEncoderDirection() {
return encoderDirection;
}
/**
* @param encoderDirection the encoderDirection to set
*/
public void setEncoderDirection(int encoderDirection) {
this.encoderDirection = encoderDirection;
}
/**
* @return the start
*/
public double getStart() {
return start;
}
/**
* @param start the start to set
*/
public void setStart(double start) {
this.start = start;
if(start<=end){
positive=true;
}
else{
positive=false;
}
}
/**
* @return the end
*/
public double getEnd() {
return end;
}
/**
* @param end the end to set
*/
public void setEnd(double end) {
this.end = end;
if(end>=start){
positive=true;
}
else{
positive=false;
}
}
/**
* Calculate real position
* @param raw
* @return
*/
public double calculatePositionMotor(double raw){
return(((raw * motorResolution * motorReadbackResolution)/motorDirection)+motorOffset);
}
/**
* Calculate real motor position using the readback link
* @param raw
* @return
*/
public double calculatePositionMotorUseReadback(double raw){
return((((raw - encoderOffset) * encoderResolution * encoderDirection * motorReadbackResolution) / motorDirection) + motorOffset);
}
/**
* Calculate real motor position using encoder
* @param raw
* @return
*/
public double calculatePositionMotorUseEncoder(double raw){
return(raw * motorEncoderResolution * motorReadbackResolution/motorDirection + motorOffset);
}
/**
* Filter whether value is with the range
* @param value
* @return
*/
public boolean filter(Double value){
if(positive){
if(start<=value && value<=end){
// If motor is very accurete and user backlash==null it might be that value is exactly
// the end value. To prevent that unnecessary data is captured execute this check
if(wasEqualBefore){
wasEqualBefore=false; // Reset flag
return false;
}
// Check whether was equal
if(value==end){
wasEqualBefore=true;
}
return true;
}
else{
return false;
}
}
else{
if(end<=value && value <=start){
if(wasEqualBefore){
wasEqualBefore=false; // Reset flag
return false;
}
// Check whether was equal
if(value==start){
wasEqualBefore=true;
}
return true;
}
else{
return false;
}
}
}
}

View File

@@ -1,73 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.loops.cr;
import ch.psi.jcae.ChannelBean;
import ch.psi.jcae.annotation.CaChannel;
/**
* @author ebner
*
*/
public class EncoderChannelsTemplate {
/**
* Resolution - $(P)$(E)_SCL
*/
@CaChannel(type=Double.class, name="_SCL")
private ChannelBean<Double> resolution;
/**
* Offset - $(P)$(E)_OFF
*/
@CaChannel(type=Double.class, name ="_OFF")
private ChannelBean<Double> offset;
/**
* Direction - $(P)$(E)_DIR
*/
public enum Direction {Negative, Positive};
@CaChannel(type=Integer.class, name ="_DIR")
private ChannelBean<Integer> direction;
/**
* @return the resolution
*/
public ChannelBean<Double> getResolution() {
return resolution;
}
/**
* @return the offset
*/
public ChannelBean<Double> getOffset() {
return offset;
}
/**
* @return the direction
*/
public ChannelBean<Integer> getDirection() {
return direction;
}
}

View File

@@ -1,652 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.loops.cr;
import ch.psi.jcae.ChannelBean;
import ch.psi.jcae.annotation.CaChannel;
/**
* @author ebner
*
*/
public class MotorChannelsTemplate {
public enum Type {SOFT_CHANNEL, MOTOR_SIMULATION, OMS_VME58, OMS_MAXv};
/**
* ## Drive section ##
* # User coordinates #
*/
/**
* .HLM High limit - double
*/
@CaChannel(type=Double.class, name =".HLM")
private ChannelBean<Double> highLimit;
/**
* .LLM Low limit - double
*/
@CaChannel(type=Double.class, name =".LLM")
private ChannelBean<Double> lowLimit;
/**
* .RBV Readback value - double
*/
@CaChannel(type=Double.class, name =".RBV", monitor=true)
private ChannelBean<Double> readbackValue;
/**
* .VAL Set value - double
*/
@CaChannel(type=Double.class, name =".VAL", monitor=true)
private ChannelBean<Double> setValue;
/**
* .RLV Relative move value - double
*/
@CaChannel(type=Double.class, name =".RLV")
private ChannelBean<Double> relativeMoveValue;
/**
* .TWV Teak value - double
*/
@CaChannel(type=Double.class, name =".TWV")
private ChannelBean<Double> tweakValue;
/**
* .TWR Tweak reverse - move left - int
*/
@CaChannel(type=Integer.class, name =".TWR")
private ChannelBean<Integer> tweakReverse;
/**
* .TWF Tweak forward - move right - int
*/
@CaChannel(type=Integer.class, name =".TWF")
private ChannelBean<Integer> tweakForward;
/**
* .JOGR Jog reverse - int
*/
@CaChannel(type=Integer.class, name =".JOGR")
private ChannelBean<Integer> jogReverse;
/**
* .JOGF Jog forward - int
*/
@CaChannel(type=Integer.class, name =".JOGF")
private ChannelBean<Integer> jogForward;
/**
* .HOMR Home reverse - int
*/
@CaChannel(type=Integer.class, name =".HOMR")
private ChannelBean<Integer> homeReverse;
/**
* .HOMF Home forward - int
*/
@CaChannel(type=Integer.class, name =".HOMF")
private ChannelBean<Integer> homeForward;
/**
* .EGU Engineering unit - String
*/
@CaChannel(type=String.class, name =".EGU")
private ChannelBean<String> engineeringUnit;
/**
* .DTYP Type - String (e.g. "OMS MAXv") see enum Type
*/
@CaChannel(type=Integer.class, name =".DTYP")
private ChannelBean<Integer> type;
/**
* .DESC Description - String
*/
@CaChannel(type=String.class, name =".DESC")
private ChannelBean<String> description;
/**
* # Dial coordinates #
*/
/**
* .DHLM Dial high limit - double
*/
@CaChannel(type=Double.class, name =".DHLM")
private ChannelBean<Double> dialHighLimit;
/**
* .DLLM Dial low limit - double
*/
@CaChannel(type=Double.class, name =".DLLM")
private ChannelBean<Double> dialLowLimit;
/**
* .DRBV Dial readback value - double
*/
@CaChannel(type=Double.class, name =".DRBV", monitor=true)
private ChannelBean<Double> dialReadbackValue;
/**
* .DVAL Dial set value - double
*/
@CaChannel(type=Double.class, name =".DVAL", monitor=true)
private ChannelBean<Double> dialSetValue;
/**
* .RVAL Raw value - int
*/
@CaChannel(type=Integer.class, name =".RVAL", monitor=true)
private ChannelBean<Integer> rawValue;
/**
* .RRBV Raw readback value - int
*/
@CaChannel(type=Integer.class, name =".RRBV", monitor=true)
private ChannelBean<Integer> rawReadbackValue;
/**
* .SPMG Stop/Pause/Move/Go - (0:"Stop", 1:"Pause", 2:"Move", 3:"Go") - 3
*/
public enum Commands { Stop, Pause, Move, Go };
@CaChannel(type=Integer.class, name =".SPMG")
private ChannelBean<Integer> command;
/**
* ## Calibration section ##
*/
/**
* .SET Set/Use Switch - (0:"Use", 1:"Set") - 0
*/
public enum Calibration {Use, Set};
@CaChannel(type=Integer.class, name =".SET")
private ChannelBean<Integer> calibration;
/**
* .OFF User offset (EGU) - double
*/
@CaChannel(type=Double.class, name =".OFF")
private ChannelBean<Double> offset;
/**
* .FOFF Offset-Freeze Switch - (0:"Variable", 1:"Frozen") - 1
*/
public enum OffsetMode {Variable, Frozen};
@CaChannel(type=Integer.class, name =".FOFF")
private ChannelBean<Integer> offsetMode;
/**
* .DIR User direction - (0:"Pos", 1:"Neg")
*/
public enum Direction {Positive, Negative};
@CaChannel(type=Integer.class, name =".DIR")
private ChannelBean<Integer> direction;
/**
* ## Dynamics ##
*/
/**
* .VELO Velocity (EGU/s) - double
*/
@CaChannel(type=Double.class, name =".VELO")
private ChannelBean<Double> velocity;
/**
* .BVEL Backlash velocity (EGU/s) - double
*/
@CaChannel(type=Double.class, name =".BVEL")
private ChannelBean<Double> backlashVelocity;
/**
* .VBAS Base speed (EGU/s) - double
*/
@CaChannel(type=Double.class, name =".VBAS")
private ChannelBean<Double> baseSpeed;
/**
* .ACCL Acceleration time / seconds to velocity - double
*/
@CaChannel(type=Double.class, name =".ACCL")
private ChannelBean<Double> accelerationTime;
/**
* .BACC Backlash acceleration time / seconds to velocity - double
*/
@CaChannel(type=Double.class, name =".BACC")
private ChannelBean<Double> backlashAccelerationTime;
/**
* .BDST Backlash distance (EGU) - double
*/
@CaChannel(type=Double.class, name =".BDST")
private ChannelBean<Double> backlashDistance;
/**
* .FRAC Move fraction - double
*/
@CaChannel(type=Double.class, name =".FRAC")
private ChannelBean<Double> moveFracion;
/**
* ## Resolution ##
*/
/**
* .MRES Motor resolution - double
*/
@CaChannel(type=Double.class, name =".MRES")
private ChannelBean<Double> motorResolution;
/**
* .ERES Encoder resolution - double
*/
@CaChannel(type=Double.class, name =".ERES")
private ChannelBean<Double> encoderResolution;
/**
* .RRES Readback resolution - double
*/
@CaChannel(type=Double.class, name =".RRES")
private ChannelBean<Double> readbackResolution;
/**
* .RDBD Retry deadband (EGU) - double
*/
@CaChannel(type=Double.class, name =".RDBD")
private ChannelBean<Double> retryDeadband;
/**
* .RTRY Max retry count - int
*/
@CaChannel(type=Integer.class, name =".RTRY")
private ChannelBean<Integer> maxRetryCount;
/**
* .RCNT Retry count - int
*/
@CaChannel(type=Integer.class, name =".RCNT", monitor=true)
private ChannelBean<Integer> retryCount;
/**
* .UEIP Use encoder (if present) - (0:"No", 1:"Yes")
*/
@CaChannel(type=Boolean.class, name =".UEIP")
private ChannelBean<Boolean> useEncoder;
/**
* .URIP Use readback link (if present) - (0:"No", 1:"Yes")
*/
@CaChannel(type=Boolean.class, name =".URIP")
private ChannelBean<Boolean> useReadback;
/**
* .DLY Readback delay (s) - double
*/
@CaChannel(type=Double.class, name =".DLY")
private ChannelBean<Double> readbackDelay;
/**
* .RDBL Readback link - String
*/
@CaChannel(type=String.class, name =".RDBL")
private ChannelBean<String> readbackLink;
/**
* .OMSL Output mode select - (0:"supervisory", 1:"closed_loop")
*/
public enum OutputMode {Supervisory, Closed_Loop};
@CaChannel(type=Integer.class, name =".OMSL")
private ChannelBean<Integer> outputMode;
/**
* ## Status ##
*/
/**
* .DMOV Done move - int
*/
@CaChannel(type=Boolean.class, name =".DMOV", monitor=true)
private ChannelBean<Boolean> moveDone;
/**
* @return the highLimit
*/
public ChannelBean<Double> getHighLimit() {
return highLimit;
}
/**
* @return the lowLimit
*/
public ChannelBean<Double> getLowLimit() {
return lowLimit;
}
/**
* @return the readbackValue
*/
public ChannelBean<Double> getReadbackValue() {
return readbackValue;
}
/**
* @return the setValue
*/
public ChannelBean<Double> getSetValue() {
return setValue;
}
/**
* @return the relativeMoveValue
*/
public ChannelBean<Double> getRelativeMoveValue() {
return relativeMoveValue;
}
/**
* @return the tweakValue
*/
public ChannelBean<Double> getTweakValue() {
return tweakValue;
}
/**
* @return the tweakReverse
*/
public ChannelBean<Integer> getTweakReverse() {
return tweakReverse;
}
/**
* @return the tweakForward
*/
public ChannelBean<Integer> getTweakForward() {
return tweakForward;
}
/**
* @return the jogReverse
*/
public ChannelBean<Integer> getJogReverse() {
return jogReverse;
}
/**
* @return the jogForward
*/
public ChannelBean<Integer> getJogForward() {
return jogForward;
}
/**
* @return the homeReverse
*/
public ChannelBean<Integer> getHomeReverse() {
return homeReverse;
}
/**
* @return the homeForward
*/
public ChannelBean<Integer> getHomeForward() {
return homeForward;
}
/**
* @return the engineeringUnit
*/
public ChannelBean<String> getEngineeringUnit() {
return engineeringUnit;
}
/**
* @return the type
*/
public ChannelBean<Integer> getType() {
return type;
}
/**
* @return the description
*/
public ChannelBean<String> getDescription() {
return description;
}
/**
* @return the dialHighLimit
*/
public ChannelBean<Double> getDialHighLimit() {
return dialHighLimit;
}
/**
* @return the dialLowLimit
*/
public ChannelBean<Double> getDialLowLimit() {
return dialLowLimit;
}
/**
* @return the dialReadbackValue
*/
public ChannelBean<Double> getDialReadbackValue() {
return dialReadbackValue;
}
/**
* @return the dialSetValue
*/
public ChannelBean<Double> getDialSetValue() {
return dialSetValue;
}
/**
* @return the rawValue
*/
public ChannelBean<Integer> getRawValue() {
return rawValue;
}
/**
* @return the rawReadbackValue
*/
public ChannelBean<Integer> getRawReadbackValue() {
return rawReadbackValue;
}
/**
* @return the command
*/
public ChannelBean<Integer> getCommand() {
return command;
}
/**
* @return the calibration
*/
public ChannelBean<Integer> getCalibration() {
return calibration;
}
/**
* @return the userOffset
*/
public ChannelBean<Double> getOffset() {
return offset;
}
/**
* @return the offsetMode
*/
public ChannelBean<Integer> getOffsetMode() {
return offsetMode;
}
/**
* @return the direction
*/
public ChannelBean<Integer> getDirection() {
return direction;
}
/**
* @return the velocity
*/
public ChannelBean<Double> getVelocity() {
return velocity;
}
/**
* @return the backlashVelocity
*/
public ChannelBean<Double> getBacklashVelocity() {
return backlashVelocity;
}
/**
* @return the baseSpeed
*/
public ChannelBean<Double> getBaseSpeed() {
return baseSpeed;
}
/**
* @return the accelerationTime
*/
public ChannelBean<Double> getAccelerationTime() {
return accelerationTime;
}
/**
* @return the backlashAccelerationTime
*/
public ChannelBean<Double> getBacklashAccelerationTime() {
return backlashAccelerationTime;
}
/**
* @return the backlashDistance
*/
public ChannelBean<Double> getBacklashDistance() {
return backlashDistance;
}
/**
* @return the moveFracion
*/
public ChannelBean<Double> getMoveFracion() {
return moveFracion;
}
/**
* @return the motorResolution
*/
public ChannelBean<Double> getMotorResolution() {
return motorResolution;
}
/**
* @return the encoderResolution
*/
public ChannelBean<Double> getEncoderResolution() {
return encoderResolution;
}
/**
* @return the readbackResolution
*/
public ChannelBean<Double> getReadbackResolution() {
return readbackResolution;
}
/**
* @return the retryDeadband
*/
public ChannelBean<Double> getRetryDeadband() {
return retryDeadband;
}
/**
* @return the maxRetryCount
*/
public ChannelBean<Integer> getMaxRetryCount() {
return maxRetryCount;
}
/**
* @return the retryCount
*/
public ChannelBean<Integer> getRetryCount() {
return retryCount;
}
/**
* @return the useEncoder
*/
public ChannelBean<Boolean> getUseEncoder() {
return useEncoder;
}
/**
* @return the useReadback
*/
public ChannelBean<Boolean> getUseReadback() {
return useReadback;
}
/**
* @return the readbackDelay
*/
public ChannelBean<Double> getReadbackDelay() {
return readbackDelay;
}
/**
* @return the readbackLink
*/
public ChannelBean<String> getReadbackLink() {
return readbackLink;
}
/**
* @return the outputMode
*/
public ChannelBean<Integer> getOutputMode() {
return outputMode;
}
/**
* @return the moveDone
*/
public ChannelBean<Boolean> getMoveDone() {
return moveDone;
}
}

View File

@@ -1,268 +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.Callable;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import ch.psi.fda.core.Action;
import ch.psi.fda.core.ActionLoop;
import ch.psi.fda.core.messages.DataQueue;
import ch.psi.fda.core.sensors.MillisecondTimestampSensor;
/**
* @author ebner
*
*/
public class ParallelCrlogic implements ActionLoop {
// Get Logger
private static final Logger logger = Logger.getLogger(ParallelCrlogic.class.getName());
/**
* Flag to indicate whether the data of this loop will be grouped
* According to this flag the dataGroup flag in EndOfStream will be set.
*/
private boolean dataGroup = false;
private CrlogicLoop crlogic;
private ScrlogicLoop scrlogic;
/**
* List of actions that are executed at the beginning of the loop.
*/
private List<Action> preActions;
/**
* List of actions that are executed at the end of the loop.
*/
private List<Action> postActions;
private ParallelCrlogicStreamMerge merger;
public ParallelCrlogic(CrlogicLoop crlogic, ScrlogicLoop scrlogic){
if(crlogic==null){
throw new IllegalArgumentException("No Crloop specified");
}
if(scrlogic==null){
throw new IllegalArgumentException("No Scrloop specified");
}
this.crlogic = crlogic;
// Add timestamp to sensor at the beginning of the sensor list as this is required for merging the data
// Timestamp will be at the second position of a message in the queue!
this.crlogic.getSensors().add(0, new MillisecondTimestampSensor("tmp_timestamp"));
this.scrlogic = scrlogic;
// Initialize lists used by the loop
this.preActions = new ArrayList<Action>();
this.postActions = new ArrayList<Action>();
this.merger = new ParallelCrlogicStreamMerge(crlogic.getDataQueue(), scrlogic.getDataQueue());
}
/* (non-Javadoc)
* @see ch.psi.fda.logic.Logic#prepare()
*/
@Override
public void prepare() {
// TODO Auto-generated method stub
}
/* (non-Javadoc)
* @see ch.psi.fda.logic.Logic#execute()
*/
@Override
public void execute() throws InterruptedException {
// Execute pre actions
for(Action action: preActions){
action.execute();
}
ExecutorService service = Executors.newFixedThreadPool(3); // 2 for the parallel data acquisition and 1 for the merger thread
final CyclicBarrier b = new CyclicBarrier(2);
List<Future<Boolean>> list = new ArrayList<Future<Boolean>>();
// Start a thread for each logic
logger.info("Submit logic");
Future<Boolean> f = service.submit(new Callable<Boolean>(){
@Override
public Boolean call() throws Exception {
// Prepare logic
crlogic.prepare();
// Ensure that really all parallel logics start in parallel
b.await();
// Execute the logic of this path
crlogic.execute();
// Need to stop the scrlogic logic (otherwise it would keep going to take data)
scrlogic.abort();
return true;
}});
list.add(f);
//Start a thread for the scrlogic
logger.info("Submit logic");
f = service.submit(new Callable<Boolean>(){
@Override
public Boolean call() throws Exception {
// Prepare logic
scrlogic.prepare();
// Ensure that really all parallel logics start in parallel
b.await();
// Execute the logic of this path
scrlogic.execute(); // This actually just starts the collection ...
return true;
}});
list.add(f);
// // Start data merge thread
// logger.info("Start data merge");
// f = service.submit(new Callable<Boolean>(){
// @Override
// public Boolean call() throws Exception {
//
// merger.merge();
// return true;
// }});
// list.add(f);
for(Future<Boolean> bf: list){
// Wait for completion of the thread
try {
bf.get();
} catch (ExecutionException e) {
logger.log(Level.WARNING, "Something went wrong while waiting for crthreads to finish");
throw new RuntimeException(e);
}
}
merger.merge();
// Wait until all threads have finished
service.shutdown();
service.awaitTermination(1, TimeUnit.MINUTES);
// Execute post actions
for(Action action: postActions){
action.execute();
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Action#abort()
*/
@Override
public void abort() {
// TODO Auto-generated method stub
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Action#destroy()
*/
@Override
public void destroy() {
crlogic.destroy();
scrlogic.destroy();
}
/* (non-Javadoc)
* @see ch.psi.fda.core.ActionLoop#cleanup()
*/
@Override
public void cleanup() {
// TODO Auto-generated method stub
}
/* (non-Javadoc)
* @see ch.psi.fda.core.ActionLoop#getPreActions()
*/
@Override
public List<Action> getPreActions() {
return preActions;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.ActionLoop#getPostActions()
*/
@Override
public List<Action> getPostActions() {
return postActions;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.ActionLoop#isDataGroup()
*/
@Override
public boolean isDataGroup() {
return dataGroup;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.ActionLoop#setDataGroup(boolean)
*/
@Override
public void setDataGroup(boolean dataGroup) {
this.dataGroup = dataGroup;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.ActionLoop#getDataQueue()
*/
@Override
public DataQueue getDataQueue() {
return(merger.getDataQueue());
}
}

View File

@@ -1,169 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.loops.cr;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import ch.psi.fda.core.messages.DataMessage;
import ch.psi.fda.core.messages.DataMessageMetadata;
import ch.psi.fda.core.messages.DataQueue;
import ch.psi.fda.core.messages.EndOfStreamMessage;
import ch.psi.fda.core.messages.Message;
/**
* @author ebner
*
*/
public class ParallelCrlogicStreamMerge {
private BlockingQueue<Message> dataQueue;
private DataQueue primaryQueue;
private DataQueue secondaryQueue;
/**
* Class to merge two data streams into one. The secondary queues data is added to the primary queues data.
* The resulting queue therefor will hold the same amount of elements as the primary queue does.
* The datagroup flag set in the end of stream message will be set according to the flag set in the primary queue.
*
* @param pqueue Primary/master queue
* @param squeue Secondary queue
*/
public ParallelCrlogicStreamMerge(DataQueue pqueue, DataQueue squeue){
this.primaryQueue = pqueue;
this.secondaryQueue = squeue;
this.dataQueue = new LinkedBlockingQueue<Message>();
}
/**
* Merge the streams based on the timestamp
* @throws InterruptedException
*/
public void merge() throws InterruptedException{
// Actual data of the secondary queue
List<Object> currData = null;
// Take first element of the primary queue (wait until message is available)
Message m = primaryQueue.getQueue().take();
while(! (m instanceof EndOfStreamMessage)){
if(m instanceof DataMessage){
DataMessage dm = (DataMessage) m;
// Get and remove merge timestamp from the data of the message
Double timestamp = (Double) dm.getData().remove(1);
long milliseconds = (long) (timestamp*1000);
long nanoOffset = (long)((timestamp*1000-milliseconds)*1000000);
// System.out.println("timestamp: "+new Date(milliseconds)+" "+milliseconds+" ."+nanoOffset);
while(true){
// Assumption: the secondary Queue holds at least the data up to the
// timestamp of the primary queue
Message mess = secondaryQueue.getQueue().peek();
// Message mess = secondaryQueue.getQueue().take();
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;
// System.out.println("Mess: "+mess);
long currMilliCheck = ((Double) msCheck.getData().get(0)).longValue();
long currNanoCheck = ((Double) msCheck.getData().get(1)).longValue();
// Check
if(currMilliCheck>milliseconds || (currMilliCheck==milliseconds && currNanoCheck>nanoOffset)){
break;
}
DataMessage ms = (DataMessage) secondaryQueue.getQueue().take();
// System.out.println("Ms: "+ms);
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);
dataQueue.add(dm);
}
m = primaryQueue.getQueue().take();
}
// Add the end of stream message of the primary queue
dataQueue.add(m);
// Clear all remaining messages in secondary queue
secondaryQueue.getQueue().clear();
}
/**
* The structure of the data message depends on the sensors registered at this loop
* at the time this method is called.
* @return the data queue and the metadata of the data messages
*/
public DataQueue getDataQueue() {
DataMessageMetadata m = new DataMessageMetadata();
DataMessageMetadata pqm = primaryQueue.getDataMessageMetadata();
m.getComponents().add(pqm.getComponents().get(0)); // add first component (this is the actuator)
// Skip the next component as this is the timestamp used to merge the data
for(int i=2;i<pqm.getComponents().size();i++){
m.getComponents().add(pqm.getComponents().get(i));
}
DataMessageMetadata sqm = secondaryQueue.getDataMessageMetadata();
// Skip first two components of the message as this is the timestamp
for(int i=2;i<sqm.getComponents().size();i++){
m.getComponents().add(sqm.getComponents().get(i));
}
return new DataQueue(dataQueue, m);
}
}

View File

@@ -1,397 +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 gov.aps.jca.CAException;
import gov.aps.jca.Monitor;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.logging.Level;
import java.util.logging.Logger;
import ch.psi.fda.core.Action;
import ch.psi.fda.core.ActionLoop;
import ch.psi.fda.core.Sensor;
import ch.psi.fda.core.messages.ComponentMetadata;
import ch.psi.fda.core.messages.DataMessage;
import ch.psi.fda.core.messages.DataMessageMetadata;
import ch.psi.fda.core.messages.DataQueue;
import ch.psi.fda.core.messages.EndOfStreamMessage;
import ch.psi.fda.core.messages.Message;
import ch.psi.fda.core.sensors.ChannelAccessDoubleSensor;
import ch.psi.jcae.ChannelBean;
import ch.psi.jcae.MonitorListenerDoubleTimestamp;
/**
* @author ebner
*
* Assumptions: - The delay between the monitor writing the value to the
* monitor queue and the readout of all the queues is sufficient to
* prevent the situation that some monitors of events close to each
* 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>();
/**
* Sensors to read out
*/
private List<Sensor> sensors;
/**
* List of monitors that were attached to the sensor channels (i.e
* workaround)
*/
private final List<Monitor> monitors = new ArrayList<Monitor>();
/**
* 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;
public ScrlogicLoop(List<Sensor> sensors) {
this.sensors = sensors;
}
/*
* (non-Javadoc)
*
* @see ch.psi.fda.core.Action#execute()
*/
@Override
public void execute() throws InterruptedException {
// Clear all queues
queues.clear();
latch = new CountDownLatch(1);
try {
// Attach monitors to the channels (this is actually a workaround)
for (Sensor sensor : sensors) {
if (sensor instanceof ChannelAccessDoubleSensor) {
ChannelAccessDoubleSensor s = (ChannelAccessDoubleSensor) sensor;
ChannelBean<Double> b = s.getChannel();
// Create data queue for the channel
final BlockingQueue<TimestampedValue> q = new LinkedBlockingQueue<TimestampedValue>();
queues.add(q);
Monitor m = b
.attachMonitor(new MonitorListenerDoubleTimestamp() {
@Override
public void valueChanged(Double value, Date timestamp, long nanosecondsOffset) {
// Add values to channel queue
q.add(new TimestampedValue(value, timestamp.getTime(), nanosecondsOffset));
}
});
monitors.add(m);
}
}
} catch (CAException e) {
new RuntimeException("Unable to create monitor for channels", e);
}
logger.info("Start data acquisition");
latch.await();
// Remove monitors
try {
for (int i = 0; i < sensors.size(); i++) {
Sensor sensor = sensors.get(i);
if (sensor instanceof ChannelAccessDoubleSensor) {
ChannelAccessDoubleSensor s = (ChannelAccessDoubleSensor) sensor;
ChannelBean<Double> b = s.getChannel();
try{
b.removeMonitor(monitors.get(i));
}
catch(IllegalArgumentException e){
logger.log(Level.SEVERE, "Unable to detach monitor", e);
}
}
}
} catch (CAException e) {
new RuntimeException(e);
}
finally{
// Clear all monitors in the list
monitors.clear();
}
// Merge data
merge();
// Clear data queues
for (BlockingQueue<TimestampedValue> q : queues) {
q.clear();
}
queues.clear();
// Put end of stream to the queue
dataQueue.add(new EndOfStreamMessage(dataGroup));
}
/*
* (non-Javadoc)
*
* @see ch.psi.fda.core.Action#abort()
*/
@Override
public void abort() {
latch.countDown();
}
/*
* (non-Javadoc)
*
* @see ch.psi.fda.core.Action#destroy()
*/
@Override
public void destroy() {
// Destroy all sensors
for (Sensor s : sensors) {
s.destroy();
}
sensors.clear();
}
/*
* (non-Javadoc)
*
* @see ch.psi.fda.core.ActionLoop#prepare()
*/
@Override
public void prepare() {
// do nothing
}
/*
* (non-Javadoc)
*
* @see ch.psi.fda.core.ActionLoop#cleanup()
*/
@Override
public void cleanup() {
// Do nothing
}
/*
* (non-Javadoc)
*
* @see ch.psi.fda.core.ActionLoop#getPreActions()
*/
@Override
public List<Action> getPreActions() {
return preActions;
}
/*
* (non-Javadoc)
*
* @see ch.psi.fda.core.ActionLoop#getPostActions()
*/
@Override
public List<Action> getPostActions() {
return postActions;
}
/*
* (non-Javadoc)
*
* @see ch.psi.fda.core.ActionLoop#isDataGroup()
*/
@Override
public boolean isDataGroup() {
return dataGroup;
}
/*
* (non-Javadoc)
*
* @see ch.psi.fda.core.ActionLoop#setDataGroup(boolean)
*/
@Override
public void setDataGroup(boolean dataGroup) {
this.dataGroup = dataGroup;
}
/**
* The structure of the data message depends on the sensors registered at
* this loop at the time this method is called.
*
* @return the data queue and the metadata of the data messages
*/
public DataQueue getDataQueue() {
DataMessageMetadata m = new DataMessageMetadata();
// Build up data message metadata based on the channels registered.
m.getComponents().add(new ComponentMetadata(ID_TIMESTAMP_MILLISECONDS));
m.getComponents().add(
new ComponentMetadata(ID_TIMESTAMP_OFFSET_NANOSECONDS));
for (Sensor s : sensors) {
m.getComponents().add(new ComponentMetadata(s.getId()));
}
return new DataQueue(dataQueue, m);
}
private boolean hasNext(){
for (int i = 0; i < queues.size(); i++) {
if(!queues.get(i).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()) {
// semaphore.acquire();
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();
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);
dataQueue.add(message);
}
}
}
}

View File

@@ -1,81 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.loops.cr;
/**
* @author ebner
*
*/
public class TimestampedValue {
private Double value;
private long timestamp;
private long nanosecondsOffset;
public TimestampedValue(Double value, long timestamp, long nanosecondsOffset){
this.value = value;
this.timestamp = timestamp;
this.nanosecondsOffset = nanosecondsOffset;
}
/**
* @return the value
*/
public Double getValue() {
return value;
}
/**
* @param value the value to set
*/
public void setValue(Double value) {
this.value = value;
}
/**
* @return the timestamp
*/
public long getTimestamp() {
return timestamp;
}
/**
* @param timestamp the timestamp to set
*/
public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}
/**
* @return the nanosecondsOffset
*/
public long getNanosecondsOffset() {
return nanosecondsOffset;
}
/**
* @param nanosecondsOffset the nanosecondsOffset to set
*/
public void setNanosecondsOffset(long nanosecondsOffset) {
this.nanosecondsOffset = nanosecondsOffset;
}
}

View File

@@ -1,45 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.loops.cr;
import java.util.Comparator;
/**
* @author ebner
*
*/
public class TimestampedValueComparator implements Comparator<TimestampedValue> {
@Override
public int compare(TimestampedValue o1, TimestampedValue o2) {
if (o1.getTimestamp() < o2.getTimestamp()) {
return -1;
} else if (o1.getTimestamp() > o2.getTimestamp()) {
return 1;
} else if (o1.getTimestamp() == o2.getTimestamp()) {
if (o1.getNanosecondsOffset() < o2.getNanosecondsOffset()) {
return -1;
} else if (o1.getNanosecondsOffset() > o2.getNanosecondsOffset()) {
return 1;
}
}
return 0;
}
}

View File

@@ -1,103 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.loops.cr;
import java.util.List;
import ch.psi.jcae.ChannelBean;
import ch.psi.jcae.annotation.CaChannel;
/**
* @author ebner
*
*/
public class VSC16ScalerChannelsTemplate {
public enum Command {Done, Count};
/**
* Command
*/
@CaChannel(type=Integer.class, name =".CNT")
private ChannelBean<Integer> command;
public enum Mode {OneShot, AutoCount};
/**
* Count mode
*/
@CaChannel(type=Integer.class, name =".CONT")
private ChannelBean<Integer> mode;
/**
* Channel description
*/
@CaChannel(type=Boolean.class, name={".NM1", ".NM2", ".NM3", ".NM4", ".NM5", ".NM6", ".NM7", ".NM8", ".NM9", ".NM10", ".NM11", ".NM12", ".NM13", ".NM14", ".NM15", ".NM16"})
private List<ChannelBean<Boolean>> channelDescription;
/**
* Channel gate
*/
@CaChannel(type=Boolean.class, name={".G1", ".G2", ".G3", ".G4", ".G5", ".G6", ".G7", ".G8", ".G9", ".G10", ".G11", ".G12", ".G13", ".G14", ".G15", ".G16"})
private List<ChannelBean<Boolean>> channelGate;
/**
* Channel preset count
* If gate is on scaler will only count until this value
*/
@CaChannel(type=Integer.class, name={".PR1", ".PR2", ".PR3", ".PR4", ".PR5", ".PR6", ".PR7", ".PR8", ".PR9", ".PR10", ".PR11", ".PR12", ".PR13", ".PR14", ".PR15", ".PR16"})
private List<ChannelBean<Integer>> channelPresetCount;
/**
* @return the command
*/
public ChannelBean<Integer> getCommand() {
return command;
}
/**
* @return the mode
*/
public ChannelBean<Integer> getMode() {
return mode;
}
/**
* @return the channelDescription
*/
public List<ChannelBean<Boolean>> getChannelDescription() {
return channelDescription;
}
/**
* @return the channelGate
*/
public List<ChannelBean<Boolean>> getChannelGate() {
return channelGate;
}
/**
* @return the channelPresetCount
*/
public List<ChannelBean<Integer>> getChannelPresetCount() {
return channelPresetCount;
}
}

View File

@@ -1,296 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.manipulator;
import gov.aps.jca.CAException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import ch.psi.fda.core.messages.DataMessage;
import ch.psi.fda.core.messages.DataMessageMetadata;
import ch.psi.fda.core.scripting.JythonParameterMapping;
import ch.psi.fda.core.scripting.JythonParameterMappingChannel;
import ch.psi.fda.core.scripting.JythonParameterMappingGlobalVariable;
import ch.psi.fda.core.scripting.JythonParameterMappingID;
import ch.psi.jcae.ChannelBean;
import ch.psi.jcae.ChannelBeanFactory;
/**
* Manipulation
* @author ebner
*/
public class JythonManipulation implements Manipulation{
// Get Logger
private static Logger logger = Logger.getLogger(JythonManipulation.class.getName());
/**
* Pattern of the entry function of the jython script
*/
private static final String entryFunction = "process";
private static final String entryFunctionPattern = "def "+entryFunction+"\\((.*)\\):";
/**
* Code of the manipulation. The script need to implement a function of the type:
* <code>
* def process():
* # ... your code
* return value
* </code>
*
* The number of parameters of the script are not limited. So <code>process(a)</code> is valid
* as well as <code>process(a,b,c,d,e,f)</code>.
* However for each parameter there need to be a mapping inside the mapping list! If there is no
* mapping inside the Manipulator evaluating this Manipulation will throw an Exception.
*/
private final String script;
/**
* Id of the resulting component
*/
private final String id;
/**
* Mapping of components to manipulation code variables
*/
private final List<JythonParameterMapping> mapping;
private final boolean returnArray;
/**
* Script engine of the manipulator
*/
private ScriptEngine engine;
/**
* Component index of the script parameter. The sequence of the indexes in this array correspond to the script
* parameter position, i.e. the first index corresponds to the first parameter.
*/
private Integer[] parameterIndex;
/**
* Parameter array of the entry function
*/
private String[] parameter;
/**
* Jython entry call
*/
private String jythonCall;
private Map<String,Object> gvariables = new HashMap<String,Object>();
public JythonManipulation(String id, String script, List<JythonParameterMapping> mapping){
this(id, script, mapping, false);
}
/**
* Constructor
* @param id
* @param script
* @param mapping
*/
public JythonManipulation(String id, String script, List<JythonParameterMapping> mapping, boolean returnArray){
this.id = id;
this.script = script;
this.mapping = mapping;
this.returnArray = returnArray;
}
/**
* @return the script
*/
public String getScript() {
return script;
}
/**
* @return the mapping
*/
public List<JythonParameterMapping> getMapping() {
return mapping;
}
@Override
public String getId() {
return id;
}
@Override
public void initialize(DataMessageMetadata metadata){
// Workaround for Jython memory leak
// http://blog.hillbrecht.de/2009/07/11/jython-memory-leakout-of-memory-problem/
System.setProperty("python.options.internalTablesImpl","weak");
// Create new script engine
this.engine = new ScriptEngineManager().getEngineByName("python");
// Determine script entry function and the function parameters
Pattern pattern = Pattern.compile(entryFunctionPattern);
Matcher matcher = pattern.matcher(this.script);
if(matcher.find() && matcher.groupCount()==1){
if(!matcher.group(1).trim().equals("")){
logger.finest("Entry function '"+entryFunctionPattern+"' found - Identified parameters: "+matcher.group(1));
parameter = matcher.group(1).split(" *, *");
}
else{
parameter = new String[0];
}
}
else{
throw new IllegalArgumentException("Cannot determine entry function: "+entryFunctionPattern);
}
// Load manipulation script
try {
engine.eval(this.script);
} catch (ScriptException e) {
throw new RuntimeException("Unable to load manipulation script", e);
}
// Determine component index of the needed parameters
// If the component index of the parameter cannot be determined an IllegalArgumentException is thrown
parameterIndex = new Integer[parameter.length];
for(int i=0;i<parameter.length; i++){
String p = parameter[i];
p = p.trim();
boolean found = false;
for(JythonParameterMapping jpm: this.mapping){
if(jpm.getVariable().equals(p)){
if(jpm instanceof JythonParameterMappingID){
JythonParameterMappingID pm = (JythonParameterMappingID)jpm;
// Mapping for parameter found, determine index of the corresponding component
parameterIndex[i] = metadata.getIndex(pm.getRefid());
}
else if (jpm instanceof JythonParameterMappingChannel){
JythonParameterMappingChannel pm = (JythonParameterMappingChannel)jpm;
parameterIndex[i] = null;
ChannelBean<?> cb;
try {
cb = ChannelBeanFactory.getFactory().createChannelBean(pm.getType(), pm.getChannel(), true);
} catch (CAException e) {
throw new IllegalArgumentException("Unable to establish channel: "+pm.getChannel(), e);
} catch (InterruptedException e) {
throw new RuntimeException("Unable to establish channel: "+pm.getChannel(), e);
}
engine.put(pm.getVariable(), cb);
}
else if (jpm instanceof JythonParameterMappingGlobalVariable){
JythonParameterMappingGlobalVariable pm = (JythonParameterMappingGlobalVariable)jpm;
parameterIndex[i] = null;
engine.put(pm.getVariable(), pm.getGlobalVariable());
}
found=true;
break;
}
}
// If there is no mapping nothing can be found
// If there are mappings everything need to be found
if(!found){
throw new IllegalArgumentException("No mapping compontent found for parameter "+p);
}
}
StringBuffer buffer = new StringBuffer();
buffer.append(entryFunction);
buffer.append("(");
for(String p: parameter){
buffer.append(p);
buffer.append(",");
}
buffer.setCharAt(buffer.length()-1, ')');
jythonCall = buffer.toString();
}
@Override
public Object execute(DataMessage message){
// Set global variables - WORKAROUND gvariables
// This block is not in initialization as we want to assure that all invocations
// of this manipulation will get the same value (i.e. to prevent inconsistent behaviour
// if variable was changed during an execution of the manipulation)
for(String k: gvariables.keySet()){
engine.put(k, gvariables.get(k));
}
// Manipulate data
for(int i=0;i<parameterIndex.length;i++){
if(parameterIndex[i] != null){
engine.put(parameter[i], message.getData().get(parameterIndex[i]));
}
}
try {
if(returnArray){
return((double[]) engine.eval(jythonCall));
}
else{
// Due to the typeless nature of Python an Integer of Float/Double might be returned from the
// Python code (e.g. depending on the factors in a calculation)
// Always return the return value to a double. If this cannot be done return NaN
Object r = engine.eval(jythonCall);
if(r instanceof Double){
return((Double) r);
}
else if( r instanceof Integer){
return(((Integer)r).doubleValue());
}
else{
// return Double.NaN;
return r;
}
}
} catch (ScriptException e) {
// throw new RuntimeException("Data manipulaton [id: "+id+"] failed while executing the manipulation script",e);
logger.log(Level.WARNING, "Data manipulaton [id: "+id+"] failed while executing the manipulation script");
return Double.NaN;
}
}
/**
* Workaround to put variables into the jython engine.
* @param name
* @param value
*/
public void setVariable(String name, Object value){
gvariables.put(name, value);
}
}

View File

@@ -1,49 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.manipulator;
import ch.psi.fda.core.messages.DataMessage;
import ch.psi.fda.core.messages.DataMessageMetadata;
/**
* @author ebner
*
*/
public interface Manipulation {
/**
* Get the id of the manipulation
* @return id of manipulation
*/
public String getId();
/**
* Initialize the manipulation
* @param metadata Metadata of the incomming data message
*/
public void initialize(DataMessageMetadata metadata);
/**
* Execute the manipulation on the passed data message
* @param message Message to manipulate
* @return Result of the manipulation
*/
public Object execute(DataMessage message);
}

View File

@@ -1,74 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.manipulator;
import java.util.List;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import ch.psi.fda.core.messages.ComponentMetadata;
import ch.psi.fda.core.messages.DataMessage;
import ch.psi.fda.core.messages.DataMessageMetadata;
import ch.psi.fda.core.messages.Message;
/**
* Applies manipulations to the data stream
*/
public class Manipulator {
private EventBus bus;
private DataMessageMetadata metadata;
private final List<Manipulation> manipulations;
public Manipulator(EventBus b, DataMessageMetadata meta, List<Manipulation> manipulations){
this.bus = b;
this.manipulations = manipulations;
// Create outgoing data metadata
this.metadata = meta.clone();
// Initialize manipulations and create outgoing metadata
for(Manipulation manipulation: this.manipulations){
manipulation.initialize(this.metadata);
// Add manipulation id to metadata
this.metadata.getComponents().add(new ComponentMetadata(manipulation.getId(),0)); // Calculated component always belongs to lowes dimension
}
}
@Subscribe
public void onMessage(Message message){
if(message instanceof DataMessage){
DataMessage dm = (DataMessage) message;
for(Manipulation manipulation: manipulations){
dm.getData().add(manipulation.execute(dm));
}
}
bus.post(message);
}
public DataMessageMetadata getMetadata() {
return metadata;
}
}

View File

@@ -1,87 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.messages;
import java.io.Serializable;
/**
* Metadata of a component of a message. Each component has a global id.
* Optionally the component can also belong to a dimension. However, depending on the
* view the number of the dimension might vary. Therefore the dimension number
* might change during the lifetime of a message (component).
*
* @author ebner
*
*/
public class ComponentMetadata implements Serializable{
private static final long serialVersionUID = 1L;
/**
* Global id of the component
*/
private final String id;
/**
* Dimension of the component (optional)
*/
private final int dimension;
/**
* Default constructor - Create component metadata
* @param id Global id of the component
*/
public ComponentMetadata(String id){
this.id = id;
this.dimension = 0;
}
/**
* Constructor that initializes id and the dimension number
* @param id
* @param dimension
*/
public ComponentMetadata(String id, int dimension){
this.id = id;
this.dimension = dimension;
}
/**
* @return the dimension
*/
public int getDimension() {
return dimension;
}
/**
* @return the id
*/
public String getId() {
return id;
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "Component Metadata[id="+id+" dimension="+dimension+"]";
}
}

View File

@@ -1,31 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.messages;
/**
* A control message that is not holding any data but
* control information (like end of loop, etc.)
* @author ebner
*
*/
public abstract class ControlMessage extends Message{
private static final long serialVersionUID = 1L;
}

View File

@@ -1,85 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.messages;
import java.util.ArrayList;
import java.util.List;
/**
* Message holding data
* @author ebner
*
*/
public class DataMessage extends Message{
private static final long serialVersionUID = 1L;
/**
* Data payload of the message
*/
private List<Object> data;
/**
* Constructor - Create message object with data payload
*/
public DataMessage(){
this.data = new ArrayList<Object>();
}
/**
* Get data object of the message
* @return Data object of the message
*/
public List<Object> getData(){
return(data);
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
StringBuffer b = new StringBuffer();
b.append("Message [ ");
for (Object o : data) {
if (o.getClass().isArray()) {
// If the array object is of type double[] display its content
if (o instanceof double[]) {
double[] oa = (double[]) o;
b.append("[ ");
for (double o1 : oa) {
b.append(o1);
b.append(" ");
}
b.append("]");
} else {
b.append(o.toString());
}
} else {
b.append(o);
}
b.append(" ");
}
b.append("]");
return b.toString();
}
}

View File

@@ -1,83 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.messages;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
* Structure to hold the metadata of a component of a message.
* @author ebner
*
*/
public class DataMessageMetadata implements Serializable {
private static final long serialVersionUID = 1L;
/**
* List of the metadata of the message components
*/
private List<ComponentMetadata> components;
/**
* Default constructor
*/
public DataMessageMetadata(){
components = new ArrayList<ComponentMetadata>();
}
/**
* @return the list of component metadata of a message described by this object.
*/
public List<ComponentMetadata> getComponents() {
return components;
}
/**
* Get the index of the component with the specified Id
* @param componentId Id of the component to look for
* @return Index of the component
* @throws IllegalArgumentException There is no component with the specified Id
*/
public int getIndex(String componentId) throws IllegalArgumentException {
for(int i=0;i<components.size();i++){
ComponentMetadata c =components.get(i);
if(c.getId().equals(componentId)){
return(i);
}
}
throw new IllegalArgumentException("There is no message component with Id "+ componentId);
}
/**
* Clone data structure
* @return Cloned data structure
*/
public DataMessageMetadata clone(){
DataMessageMetadata metadata = new DataMessageMetadata();
for(int i=0;i<components.size();i++){
ComponentMetadata c =components.get(i);
metadata.getComponents().add(new ComponentMetadata(c.getId(), c.getDimension()));
}
return(metadata);
}
}

View File

@@ -1,66 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.messages;
import java.util.concurrent.BlockingQueue;
/**
* Container holding for holding a queue and the metadata of the
* data messages of that queue.
* @author ebner
*
*/
public class DataQueue {
/**
* Queue serving the messages
*/
private final BlockingQueue<Message> queue;
/**
* Metadata of the data messages of the queue
*/
private final DataMessageMetadata dataMessageMetadata;
/**
* Constructor
* @param queue Data queue
* @param dataMessageMetadata Metadata of the data messages of the queue
*/
public DataQueue(BlockingQueue<Message> queue, DataMessageMetadata dataMessageMetadata){
this.queue = queue;
this.dataMessageMetadata = dataMessageMetadata;
}
/**
* @return the queue
*/
public BlockingQueue<Message> getQueue() {
return queue;
}
/**
* @return the metadata
*/
public DataMessageMetadata getDataMessageMetadata() {
return dataMessageMetadata;
}
}

View File

@@ -1,60 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.messages;
/**
* Message that is send at the end of the action loop inside an ActionLoop implementation
* of just to indicate that a particular stream has finished
* @author ebner
*
*/
public class EndOfStreamMessage extends ControlMessage {
private static final long serialVersionUID = 1L;
/**
* Intersect flag - flag to indicate that stream should be intersected
* after this message.
*/
private final boolean iflag;
public EndOfStreamMessage(){
this(false);
}
public EndOfStreamMessage(boolean iflag){
this.iflag = iflag;
}
/**
* @return the iflag
*/
public boolean isIflag(){
return(iflag);
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "Message[ c message: end of stream ]";
}
}

View File

@@ -1,31 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.messages;
import java.io.Serializable;
/**
* Message that can be put to the data queue
* @author ebner
*
*/
public abstract class Message implements Serializable{
private static final long serialVersionUID = 1L;
}

View File

@@ -1,80 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.messages;
/**
* Message that is send at the end of the action loop inside an ActionLoop implementation
* @author ebner
*
*/
public class StreamDelimiterMessage extends ControlMessage{
private static final long serialVersionUID = 1L;
/**
* Number of the dimension this delimiter belongs to.
*/
private final int number;
/**
* Intersect flag - flag to indicate that stream should be intersected
* after this message.
*/
private final boolean iflag;
/**
* Constructor
* @param number Number of the dimension this delimiter belongs to
*/
public StreamDelimiterMessage(int number){
this(number, false);
}
/**
* Constructor
* @param number
* @param iflag Flag to indicate that data is grouped
*/
public StreamDelimiterMessage(int number, boolean iflag){
this.number = number;
this.iflag = iflag;
}
/**
* @return the number
*/
public int getNumber() {
return number;
}
/**
* @return the iflag
*/
public boolean isIflag(){
return iflag;
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
// TODO Auto-generated method stub
return "Message [ c message: delimiter dimension "+number+" ]";
}
}

View File

@@ -1,55 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.scripting;
/**
* @author ebner
*
*/
public class JythonGlobalVariable {
private String name;
private double value;
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the value
*/
public double getValue() {
return value;
}
/**
* @param value the value to set
*/
public void setValue(double value) {
this.value = value;
}
}

View File

@@ -1,75 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.scripting;
import java.util.HashMap;
/**
* Singleton dictionary class
*
* @author ebner
*
*/
public class JythonGlobalVariableDictionary {
private static JythonGlobalVariableDictionary instance = new JythonGlobalVariableDictionary();
private HashMap<String, JythonGlobalVariable> dictionary = new HashMap<String, JythonGlobalVariable>();
/**
* Private constructor
*/
private JythonGlobalVariableDictionary(){
}
/**
* Get singleton instance of the dictionary
* @return
*/
public static JythonGlobalVariableDictionary getInstance(){
return instance;
}
/**
* Get variable from dictionary. If the variable does not exist it will be created.
* @param name
* @return
*/
public JythonGlobalVariable getVariable(String name){
JythonGlobalVariable variable;
if(dictionary.containsKey(name)){
variable = dictionary.get(name);
}
else{
variable = new JythonGlobalVariable();
variable.setName(name);
dictionary.put(name, variable);
}
return variable;
}
/**
* Clear variable dictionary
*/
public void clear(){
dictionary.clear();
}
}

View File

@@ -1,55 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.scripting;
/**
* Mapping of a parameter to something
* @author ebner
*
*/
public abstract class JythonParameterMapping {
/**
* Variable name inside the script
*/
private String variable;
/**
* Constructor
* @param variable
*/
public JythonParameterMapping(String variable){
this.variable = variable;
}
/**
* @return the variable
*/
public String getVariable() {
return variable;
}
/**
* @param variable the variable to set
*/
public void setVariable(String variable) {
this.variable = variable;
}
}

View File

@@ -1,75 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.scripting;
/**
* Mapping of a script parameter to a channel bean.
* @author ebner
*
*/
public class JythonParameterMappingChannel extends JythonParameterMapping {
/**
* Id of the component to map to this variable
*/
private String channel;
private Class<?> type;
/**
* Constructor accepting varible/id pair
* @param variable
* @param channel
* @param type
*/
public JythonParameterMappingChannel(String variable, String channel, Class<?> type){
super(variable);
this.channel = channel;
this.type = type;
}
/**
* @return the channel
*/
public String getChannel() {
return channel;
}
/**
* @param channel
*/
public void setChannel(String channel) {
this.channel = channel;
}
/**
* @return the type
*/
public Class<?> getType() {
return type;
}
/**
* @param type the type to set
*/
public void setType(Class<?> type) {
this.type = type;
}
}

View File

@@ -1,56 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.scripting;
/**
* Mapping of a script parameter to a component via the Id.
* @author ebner
*
*/
public class JythonParameterMappingGlobalVariable extends JythonParameterMapping {
private JythonGlobalVariable globalVariable;
/**
* Constuctor
* @param variable
* @param globalVariable
*/
public JythonParameterMappingGlobalVariable(String variable, JythonGlobalVariable globalVariable){
super(variable);
this.globalVariable = globalVariable;
}
/**
* @return the globalVariable
*/
public JythonGlobalVariable getGlobalVariable() {
return globalVariable;
}
/**
* @param globalVariable the globalVariable to set
*/
public void setGlobalVariable(JythonGlobalVariable globalVariable) {
this.globalVariable = globalVariable;
}
}

View File

@@ -1,58 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.scripting;
/**
* Mapping of a script parameter to a component via the Id.
* @author ebner
*
*/
public class JythonParameterMappingID extends JythonParameterMapping {
/**
* Id of the component to map to this variable
*/
private String refid;
/**
* Constructor accepting varible/id pair
* @param variable
* @param refid
*/
public JythonParameterMappingID(String variable, String refid){
super(variable);
this.refid = refid;
}
/**
* @return the refid
*/
public String getRefid() {
return refid;
}
/**
* @param refid the refid to set
*/
public void setRefid(String refid) {
this.refid = refid;
}
}

View File

@@ -1,144 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.sensors;
import java.util.logging.Logger;
import gov.aps.jca.CAException;
import ch.psi.fda.core.EngineConfiguration;
import ch.psi.fda.core.Sensor;
import ch.psi.jcae.ChannelBeanFactory;
import ch.psi.jcae.ChannelBean;
/**
* Scalar sensor that reads a double form a Channel Access channel
* @author ebner
*
*/
public class ChannelAccessDoubleArraySensor implements Sensor {
// Get Logger
private static Logger logger = Logger.getLogger(ChannelAccessDoubleArraySensor.class.getName());
/**
* Channel Access channel of this sensor
*/
private final ChannelBean<double[]> channel;
/**
* Number of elements to read from the waveform
*/
private final int numberOfElements;
/**
* Global id of the sensor
*/
private final String id;
/**
* Constructor
* @param id Global id of the sensor
* @param channelName Name of the Channel Access channel of this sensor
* @param numberOfElements Number of elements to read out of the waveform
*/
public ChannelAccessDoubleArraySensor(String id, String channelName, int numberOfElements){
try {
this.channel = ChannelBeanFactory.getFactory().createChannelBean(double[].class, channelName, false);
this.numberOfElements = numberOfElements;
this.id = id;
} catch (CAException e) {
// Convert Exception into unchecked RuntimeException
throw new IllegalArgumentException("Unable to initialize sensor channel [name:"+channelName+"]",e);
} catch (InterruptedException e) {
throw new RuntimeException("Unable to initialize sensor channel [name:"+channelName+"]",e);
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Sensor#readout()
*/
@Override
public Object read() throws InterruptedException {
logger.finest("Read sensor "+channel.getName());
double[] v;
try {
v = channel.getValue(numberOfElements);
} catch (IllegalStateException e) {
// Only fail during data acquisition if fail on error sensor flag is on true. Otherwise
// return NaN (Not a Number)
if(EngineConfiguration.getInstance().isFailOnSensorError()){
throw e;
}
v = new double[numberOfElements];
for(int i =0;i<v.length;i++){
v[i] = Double.NaN;
}
} catch (CAException e) {
// Only fail during data acquisition if fail on error sensor flag is on true. Otherwise
// return NaN (Not a Number)
if(EngineConfiguration.getInstance().isFailOnSensorError()){
// Convert Exception into unchecked RuntimeException
throw new RuntimeException("Unable to get value from channel [name:"+channel.getName()+"]",e);
}
v = new double[numberOfElements];
for(int i =0;i<v.length;i++){
v[i] = Double.NaN;
}
// } catch (InterruptedException e) {
// // Only fail during data acquisition if fail on error sensor flag is on true. Otherwise
// // return NaN (Not a Number)
// if(EngineConfiguration.getInstance().isFailOnSensorError()){
// throw new RuntimeException("Unable to get value from channel [name:"+channel.getName()+"]",e);
// }
//
// v = new double[numberOfElements];
// for(int i =0;i<v.length;i++){
// v[i] = Double.NaN;
// }
}
return(v);
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Sensor#getId()
*/
@Override
public String getId() {
return id;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Sensor#destroy()
*/
@Override
public void destroy() {
// Destroy channel
try {
logger.finest("Destroy sensor channel: "+channel.getName());
channel.destroy();
} catch (CAException e) {
throw new RuntimeException("Unable to destroy channel ["+channel.getName()+"]",e);
}
}
}

View File

@@ -1,132 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.sensors;
import java.util.logging.Logger;
import gov.aps.jca.CAException;
import ch.psi.fda.core.EngineConfiguration;
import ch.psi.fda.core.Sensor;
import ch.psi.jcae.ChannelBeanFactory;
import ch.psi.jcae.ChannelBean;
/**
* Scalar sensor that reads a double form a Channel Access channel
* @author ebner
*
*/
public class ChannelAccessDoubleSensor implements Sensor {
// Get Logger
private static Logger logger = Logger.getLogger(ChannelAccessDoubleSensor.class.getName());
/**
* Channel Access channel of this sensor
*/
private ChannelBean<Double> channel;
/**
* Global id of the sensor
*/
private final String id;
/**
* Constructor
* @param id Global id of the sensor
* @param channelName Name of the Channel Access channel of this sensor
*/
public ChannelAccessDoubleSensor(String id, String channelName){
try {
channel = ChannelBeanFactory.getFactory().createChannelBean(Double.class, channelName, false);
this.id = id;
} catch (CAException e) {
// Convert Exception into unchecked RuntimeException
throw new IllegalArgumentException("Unable to initialize sensor channel [name:"+channelName+"]",e);
} catch (InterruptedException e) {
throw new RuntimeException("Unable to initialize sensor channel [name:"+channelName+"]",e);
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Sensor#readout()
*/
@Override
public Object read() throws InterruptedException {
logger.finest("Read sensor "+channel.getName());
Double v;
try {
v = channel.getValue();
} catch (IllegalStateException e) {
// Only fail during data acquisition if fail on error sensor flag is on true. Otherwise
// return NaN (Not a Number)
if(EngineConfiguration.getInstance().isFailOnSensorError()){
throw e;
}
v = Double.NaN;
} catch (CAException e) {
// Only fail during data acquisition if fail on error sensor flag is on true. Otherwise
// return NaN (Not a Number)
if(EngineConfiguration.getInstance().isFailOnSensorError()){
// Convert Exception into unchecked RuntimeException
throw new RuntimeException("Unable to get value from channel [name:"+channel.getName()+"]",e);
}
v = Double.NaN;
// } catch (InterruptedException e) {
// if(EngineConfiguration.getInstance().isFailOnSensorError()){
// throw new RuntimeException("Unable to get value from channel [name:"+channel.getName()+"]",e);
// }
// v = Double.NaN;
}
return(v);
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Sensor#getId()
*/
@Override
public String getId() {
return id;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Sensor#destroy()
*/
@Override
public void destroy() {
// Destroy channel
try {
logger.finest("Destroy sensor channel: "+channel.getName());
channel.destroy();
} catch (CAException e) {
throw new RuntimeException("Unable to destroy channel ["+channel.getName()+"]",e);
}
}
/**
* Get channel object of sensor
* @return
*/
public ChannelBean<Double> getChannel(){
return channel;
}
}

View File

@@ -1,124 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.sensors;
import java.util.logging.Logger;
import gov.aps.jca.CAException;
import ch.psi.fda.core.EngineConfiguration;
import ch.psi.fda.core.Sensor;
import ch.psi.jcae.ChannelBeanFactory;
import ch.psi.jcae.ChannelBean;
/**
* Scalar sensor that reads a double form a Channel Access channel
* @author ebner
*
*/
public class ChannelAccessStringSensor implements Sensor {
// Get Logger
private static Logger logger = Logger.getLogger(ChannelAccessStringSensor.class.getName());
/**
* Channel Access channel of this sensor
*/
private ChannelBean<String> channel;
/**
* Global id of the sensor
*/
private final String id;
/**
* Constructor
* @param id Global id of the sensor
* @param channelName Name of the Channel Access channel of this sensor
*/
public ChannelAccessStringSensor(String id, String channelName){
try {
channel = ChannelBeanFactory.getFactory().createChannelBean(String.class, channelName, false);
this.id = id;
} catch (CAException e) {
// Convert Exception into unchecked RuntimeException
throw new IllegalArgumentException("Unable to initialize sensor channel [name:"+channelName+"]",e);
} catch (InterruptedException e) {
throw new RuntimeException("Unable to initialize sensor channel [name:"+channelName+"]",e);
}
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Sensor#readout()
*/
@Override
public Object read() throws InterruptedException {
logger.finest("Read sensor "+channel.getName());
String v;
try {
v = channel.getValue();
} catch (IllegalStateException e) {
// Only fail during data acquisition if fail on error sensor flag is on true. Otherwise
// return NaN (Not a Number)
if(EngineConfiguration.getInstance().isFailOnSensorError()){
throw e;
}
v = null;
} catch (CAException e) {
// Only fail during data acquisition if fail on error sensor flag is on true. Otherwise
// return NaN (Not a Number)
if(EngineConfiguration.getInstance().isFailOnSensorError()){
// Convert Exception into unchecked RuntimeException
throw new RuntimeException("Unable to get value from channel [name:"+channel.getName()+"]",e);
}
v = null;
// } catch (InterruptedException e) {
// if(EngineConfiguration.getInstance().isFailOnSensorError()){
// throw new RuntimeException("Unable to get value from channel [name:"+channel.getName()+"]",e);
// }
// v = null;
}
return(v);
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Sensor#getId()
*/
@Override
public String getId() {
return id;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Sensor#destroy()
*/
@Override
public void destroy() {
// Destroy channel
try {
logger.finest("Destroy sensor channel: "+channel.getName());
channel.destroy();
} catch (CAException e) {
throw new RuntimeException("Unable to destroy channel ["+channel.getName()+"]",e);
}
}
}

View File

@@ -1,136 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.fda.core.sensors;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
import ch.psi.fda.core.Action;
import ch.psi.fda.core.Sensor;
/**
* Complex sensor that complements an other sensor with pre and post actions.
* Before reading out the complemented sensor the pre actions are executed. After the
* readout the post actions.
*
* @author ebner
*
*/
public class ComplexSensor implements Sensor {
// Get Logger
private static Logger logger = Logger.getLogger(ComplexSensor.class.getName());
/**
* Id of the sensor
*/
private String id;
/**
* Sensor to complement
*/
private final Sensor sensor;
/**
* Actions that are executed directly before the first step of this actor
*/
private final List<Action> preActions;
/**
* Actions that are executed directly after the last step of this actor
*/
private final List<Action> postActions;
/**
* Constructor
*/
public ComplexSensor(String id, Sensor sensor){
this.id = id;
this.sensor = sensor;
this.preActions = new ArrayList<Action>();
this.postActions = new ArrayList<Action>();
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Sensor#read()
*/
@Override
public Object read() throws InterruptedException {
// Execute pre actions
logger.finest("Execute pre actions");
for(Action action: preActions){
action.execute();
}
// Readout sensor
Object value = sensor.read();
// Execute post actions
logger.finest("Execute post actions");
for(Action action: postActions){
action.execute();
}
return value;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Sensor#getId()
*/
@Override
public String getId() {
return id;
}
/* (non-Javadoc)
* @see ch.psi.fda.core.Sensor#destroy()
*/
@Override
public void destroy() {
// Destroy preActions
for(Action a: preActions){
a.destroy();
}
sensor.destroy();
// Destroy postActions
for(Action a: postActions){
a.destroy();
}
}
/**
* @return the preActions
*/
public List<Action> getPreActions() {
return preActions;
}
/**
* @return the postActions
*/
public List<Action> getPostActions() {
return postActions;
}
}

View File

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

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