mirror of
https://git.psi.ch/fda/ch.psi.fda.xscan.git
synced 2026-05-12 01:35:36 +02:00
removed legacy code for continuous scans
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>ch.psi.fda</groupId>
|
||||
<artifactId>ch.psi.fda.xscan</artifactId>
|
||||
<version>2.4.2_zmq</version>
|
||||
<version>2.4.7_zmq</version>
|
||||
|
||||
<dependencies>
|
||||
|
||||
@@ -30,11 +30,6 @@
|
||||
<artifactId>jcae</artifactId>
|
||||
<version>2.4.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jcifs</groupId>
|
||||
<artifactId>jcifs</artifactId>
|
||||
<version>1.3.17</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.python</groupId>
|
||||
<artifactId>jython</artifactId>
|
||||
|
||||
@@ -55,15 +55,10 @@ import ch.psi.fda.core.actors.PseudoActuatorSensor;
|
||||
import ch.psi.fda.core.guard.ChannelAccessGuard;
|
||||
import ch.psi.fda.core.guard.ChannelAccessGuardCondition;
|
||||
import ch.psi.fda.core.loops.ActorSensorLoop;
|
||||
import ch.psi.fda.core.loops.cr.CrlogicLoop;
|
||||
import ch.psi.fda.core.loops.cr.CrlogicLoopStream;
|
||||
import ch.psi.fda.core.loops.cr.CrlogicResource;
|
||||
import ch.psi.fda.core.loops.cr.ParallelCrlogic;
|
||||
import ch.psi.fda.core.loops.cr.ScrlogicLoop;
|
||||
import ch.psi.fda.core.loops.otf.OTFLoop;
|
||||
import ch.psi.fda.core.loops.otf.OTFNamedChannelSensor;
|
||||
import ch.psi.fda.core.loops.otf.OTFScalerChannelSensor;
|
||||
import ch.psi.fda.core.loops.otf.TemplateOTF;
|
||||
import ch.psi.fda.core.manipulator.JythonManipulation;
|
||||
import ch.psi.fda.core.scripting.JythonGlobalVariable;
|
||||
import ch.psi.fda.core.scripting.JythonParameterMapping;
|
||||
@@ -963,148 +958,77 @@ public class Acquisition {
|
||||
* @param dimension
|
||||
* @return
|
||||
*/
|
||||
private ActionLoop mapContinuousDimension(ContinuousDimension dimension){
|
||||
|
||||
ActionLoop aLoop = null;
|
||||
|
||||
if(!configuration.isOtfUseCrlogic()){
|
||||
|
||||
// USE OTFLOGIC FOR CONTINUOUS "SCANS"
|
||||
|
||||
// Create loop
|
||||
boolean zigZag = dimension.isZigzag(); // default value is false
|
||||
|
||||
Map<String,String> macros = new HashMap<>();
|
||||
macros.put("PREFIX", configuration.getOtfChannelPrefix());
|
||||
TemplateOTF template = new TemplateOTF();
|
||||
createTemplateChannels(template, macros);
|
||||
OTFLoop actionLoop = new OTFLoop(template, configuration.getOtfNfsServer(), configuration.getOtfNfsShare(), configuration.getOtfSmbShare(), zigZag);
|
||||
|
||||
actionLoop.getPreActions().addAll(mapActions(dimension.getPreAction()));
|
||||
|
||||
// Map positioner
|
||||
ContinuousPositioner p = dimension.getPositioner();
|
||||
double backlash = 0;
|
||||
if(p.getAdditionalBacklash()!=null){
|
||||
backlash = p.getAdditionalBacklash();
|
||||
}
|
||||
actionLoop.setActuator(p.getId(), p.getName(), p.getReadback(), p.getStart(), p.getEnd(), p.getStepSize(), p.getIntegrationTime(), backlash);
|
||||
|
||||
// Map sensors
|
||||
// ATTENTION: the sequence of the mapping depends on the sequence in the schema file !
|
||||
int cnt = 0;
|
||||
for(SimpleScalarDetector detector: dimension.getDetector()){
|
||||
if(cnt<8){ // Only up to 8 additional channels supported
|
||||
actionLoop.getSensors().add(new OTFNamedChannelSensor(detector.getId(), detector.getName()));
|
||||
}
|
||||
cnt++;
|
||||
}
|
||||
|
||||
cnt = 0;
|
||||
for(ScalerChannel detector: dimension.getScaler()){
|
||||
if(cnt<16){ // Only up to 16 scaler channels supported
|
||||
actionLoop.getSensors().add(new OTFScalerChannelSensor(detector.getId(), detector.getChannel()));
|
||||
}
|
||||
cnt++;
|
||||
}
|
||||
|
||||
Timestamp detector = dimension.getTimestamp();
|
||||
if(detector != null){
|
||||
actionLoop.getSensors().add(new TimestampSensor(detector.getId()));
|
||||
}
|
||||
|
||||
actionLoop.getPostActions().addAll(mapActions(dimension.getPostAction()));
|
||||
|
||||
aLoop = actionLoop;
|
||||
}
|
||||
else{
|
||||
// USE CRLOGIC FOR CONTINUOUS "SCANS"
|
||||
|
||||
boolean hcrOnly = true;
|
||||
for(SimpleScalarDetector detector: dimension.getDetector()){
|
||||
if(detector.isScr()){
|
||||
hcrOnly=false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// BEGIN configure HCRLOGIC
|
||||
|
||||
// Create loop
|
||||
boolean zigZag = dimension.isZigzag(); // default value is false
|
||||
|
||||
CrlogicLoop actionLoop;
|
||||
|
||||
if(configuration.isUseStream()){
|
||||
actionLoop = new CrlogicLoopStream(cservice, configuration.getOtfCrlogicPrefix(), configuration.getStreamIoc(), zigZag);
|
||||
}
|
||||
else{
|
||||
actionLoop = new CrlogicLoop(cservice, configuration.getOtfCrlogicPrefix(), configuration.getOtfNfsServer(), configuration.getOtfNfsShare(), configuration.getOtfSmbShare(), zigZag);
|
||||
}
|
||||
|
||||
|
||||
actionLoop.setKeepTmpFiles(configuration.isOtfCrlogicKeepTmpFiles());
|
||||
|
||||
actionLoop.getPreActions().addAll(mapActions(dimension.getPreAction()));
|
||||
|
||||
// Map positioner
|
||||
ContinuousPositioner p = dimension.getPositioner();
|
||||
double backlash = 0;
|
||||
if(p.getAdditionalBacklash()!=null){
|
||||
backlash = p.getAdditionalBacklash();
|
||||
}
|
||||
actionLoop.setActuator(p.getId(), p.getName(), p.getReadback(), p.getStart(), p.getEnd(), p.getStepSize(), p.getIntegrationTime(), backlash);
|
||||
|
||||
// Map sensors
|
||||
// ATTENTION: the sequence of the mapping depends on the sequence in the schema file !
|
||||
for(SimpleScalarDetector detector: dimension.getDetector()){
|
||||
if(!detector.isScr()){
|
||||
actionLoop.getSensors().add(new CrlogicResource(detector.getId(), detector.getName()));
|
||||
}
|
||||
}
|
||||
|
||||
for(ScalerChannel detector: dimension.getScaler()){
|
||||
actionLoop.getSensors().add(new CrlogicResource(detector.getId(), "SCALER"+detector.getChannel(), true));
|
||||
}
|
||||
|
||||
Timestamp tdetector = dimension.getTimestamp();
|
||||
if(tdetector != null){
|
||||
actionLoop.getSensors().add(new CrlogicResource(tdetector.getId(), "TIMESTAMP"));
|
||||
}
|
||||
|
||||
actionLoop.getPostActions().addAll(mapActions(dimension.getPostAction()));
|
||||
|
||||
// END Configure HCRLOGIC
|
||||
|
||||
|
||||
if(hcrOnly){
|
||||
// There are no additional channels to be read out while taking data via hcrlogic
|
||||
// Therefore we just register the hcr loop as action loop
|
||||
private ActionLoop mapContinuousDimension(ContinuousDimension dimension) {
|
||||
|
||||
aLoop = actionLoop;
|
||||
ActionLoop aLoop = null;
|
||||
|
||||
boolean hcrOnly = true;
|
||||
for (SimpleScalarDetector detector : dimension.getDetector()) {
|
||||
if (detector.isScr()) {
|
||||
hcrOnly = false;
|
||||
break;
|
||||
}
|
||||
else{
|
||||
List<Channel<DoubleTimestamp>> sensors = new ArrayList<>();
|
||||
List<String> ids = new ArrayList<>();
|
||||
|
||||
for(SimpleScalarDetector detector: dimension.getDetector()){
|
||||
if(detector.isScr()){
|
||||
ids.add(detector.getId());
|
||||
sensors.add(createChannel(DoubleTimestamp.class, detector.getName()));
|
||||
}
|
||||
}
|
||||
// Create soft(ware) based crlogic
|
||||
ScrlogicLoop scrlogic = new ScrlogicLoop(ids, sensors);
|
||||
|
||||
// Create parallel logic
|
||||
ParallelCrlogic pcrlogic = new ParallelCrlogic(actionLoop, scrlogic);
|
||||
|
||||
aLoop = pcrlogic;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Create loop
|
||||
boolean zigZag = dimension.isZigzag(); // default value is false
|
||||
|
||||
CrlogicLoopStream actionLoop = new CrlogicLoopStream(cservice, configuration.getOtfCrlogicPrefix(), configuration.getStreamIoc(), zigZag);
|
||||
|
||||
actionLoop.getPreActions().addAll(mapActions(dimension.getPreAction()));
|
||||
|
||||
// Map positioner
|
||||
ContinuousPositioner p = dimension.getPositioner();
|
||||
double backlash = 0;
|
||||
if (p.getAdditionalBacklash() != null) {
|
||||
backlash = p.getAdditionalBacklash();
|
||||
}
|
||||
actionLoop.setActuator(p.getId(), p.getName(), p.getReadback(), p.getStart(), p.getEnd(), p.getStepSize(), p.getIntegrationTime(), backlash);
|
||||
|
||||
// Map sensors
|
||||
// ATTENTION: the sequence of the mapping depends on the sequence in the
|
||||
// schema file !
|
||||
for (SimpleScalarDetector detector : dimension.getDetector()) {
|
||||
if (!detector.isScr()) {
|
||||
actionLoop.getSensors().add(new CrlogicResource(detector.getId(), detector.getName()));
|
||||
}
|
||||
}
|
||||
|
||||
for (ScalerChannel detector : dimension.getScaler()) {
|
||||
actionLoop.getSensors().add(new CrlogicResource(detector.getId(), "SCALER" + detector.getChannel(), true));
|
||||
}
|
||||
|
||||
Timestamp tdetector = dimension.getTimestamp();
|
||||
if (tdetector != null) {
|
||||
actionLoop.getSensors().add(new CrlogicResource(tdetector.getId(), "TIMESTAMP"));
|
||||
}
|
||||
|
||||
actionLoop.getPostActions().addAll(mapActions(dimension.getPostAction()));
|
||||
|
||||
if (hcrOnly) {
|
||||
// There are no additional channels to be read out while taking data
|
||||
// via hcrlogic
|
||||
// Therefore we just register the hcr loop as action loop
|
||||
|
||||
aLoop = actionLoop;
|
||||
} else {
|
||||
List<Channel<DoubleTimestamp>> sensors = new ArrayList<>();
|
||||
List<String> ids = new ArrayList<>();
|
||||
|
||||
for (SimpleScalarDetector detector : dimension.getDetector()) {
|
||||
if (detector.isScr()) {
|
||||
ids.add(detector.getId());
|
||||
sensors.add(createChannel(DoubleTimestamp.class, detector.getName()));
|
||||
}
|
||||
}
|
||||
// Create soft(ware) based crlogic
|
||||
ScrlogicLoop scrlogic = new ScrlogicLoop(ids, sensors);
|
||||
|
||||
// Create parallel logic
|
||||
ParallelCrlogic pcrlogic = new ParallelCrlogic(actionLoop, scrlogic);
|
||||
|
||||
aLoop = pcrlogic;
|
||||
}
|
||||
return aLoop;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,9 +24,7 @@ public class TestConfiguration {
|
||||
private final String otfPrefix = "MTEST-HW3-OTFX";
|
||||
private final String crlogicPrefix = "MTEST-HW3-CRL";
|
||||
private final String prefixScaler = "MTEST-HW3:JS";
|
||||
private final String server = "yoke.psi.ch";
|
||||
private final String share = "/usr/nfs";
|
||||
private final String smbShare = "smb://test:test@"+server+"/nfs/"; // It is important to have the last slash / !
|
||||
private final String server = "MTEST-VME-HW3";
|
||||
|
||||
private final String motor1 = "MTEST-HW3:MOT1";
|
||||
private final String analogIn1 = "MTEST-HW3-AI1:AI_01";
|
||||
@@ -61,20 +59,6 @@ public class TestConfiguration {
|
||||
return server;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the share
|
||||
*/
|
||||
public String getShare() {
|
||||
return share;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the smbShare
|
||||
*/
|
||||
public String getSmbShare() {
|
||||
return smbShare;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the motor1
|
||||
*/
|
||||
|
||||
@@ -1,847 +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.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.Semaphore;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.google.common.eventbus.EventBus;
|
||||
|
||||
import jcifs.smb.SmbFile;
|
||||
import ch.psi.fda.core.Action;
|
||||
import ch.psi.fda.core.ActionLoop;
|
||||
import ch.psi.fda.messages.DataMessage;
|
||||
import ch.psi.fda.messages.EndOfStreamMessage;
|
||||
import ch.psi.fda.messages.Metadata;
|
||||
import ch.psi.jcae.ChannelException;
|
||||
import ch.psi.jcae.ChannelService;
|
||||
|
||||
/**
|
||||
* While using Crlogic the IOC system clock rate should/must be set to 1000 (default 60)
|
||||
*
|
||||
* sysClkRateSet 1000
|
||||
*
|
||||
*/
|
||||
public class CrlogicLoop implements ActionLoop {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(CrlogicLoop.class.getName());
|
||||
|
||||
/**
|
||||
* Flag to indicate whether the data of this loop will be grouped
|
||||
* According to this flag the dataGroup flag in EndOfStream will be set.
|
||||
*/
|
||||
private boolean dataGroup = false;
|
||||
|
||||
private boolean keepTmpFiles = false;
|
||||
|
||||
private BlockingQueue<String> readQueue = new LinkedBlockingQueue<String>();
|
||||
private volatile boolean stopReadoutThread = false;
|
||||
private Thread readoutThread;
|
||||
|
||||
/**
|
||||
* Default timeout (in milliseconds) for wait operations
|
||||
*/
|
||||
private long startStopTimeout = 8000;
|
||||
|
||||
/**
|
||||
* Name of the NFS server to place the data of the OTF logic
|
||||
*/
|
||||
private final String server;
|
||||
/**
|
||||
* Share on the NFS server to put the OTF data on to
|
||||
*/
|
||||
private final String share;
|
||||
/**
|
||||
* SMB share to access the data written by the OTF C logic
|
||||
*/
|
||||
private final String smbShare;
|
||||
|
||||
/**
|
||||
* Flag whether the actor of this loop should move in zig zag mode
|
||||
*/
|
||||
private final boolean zigZag;
|
||||
|
||||
boolean useReadback;
|
||||
boolean useEncoder;
|
||||
|
||||
/**
|
||||
* List of actions that are executed at the beginning of the loop.
|
||||
*/
|
||||
private List<Action> preActions;
|
||||
/**
|
||||
* List of actions that are executed at the end of the loop.
|
||||
*/
|
||||
private List<Action> postActions;
|
||||
|
||||
/**
|
||||
* Prefix for the CRLOGIC channels
|
||||
*/
|
||||
private String prefix;
|
||||
|
||||
private TemplateCrlogic template;
|
||||
private TemplateMotor motortemplate;
|
||||
|
||||
/**
|
||||
* Semaphore to ensure that data is read in correct sequence
|
||||
*/
|
||||
private Semaphore semaphore = new Semaphore(1);
|
||||
|
||||
/**
|
||||
* List of sensors of this loop
|
||||
*/
|
||||
private List<CrlogicResource> sensors;
|
||||
|
||||
private List<String> readoutResources;
|
||||
private Map<Integer, CrlogicDeltaDataFilter> scalerIndices;
|
||||
private CrlogicRangeDataFilter crlogicDataFilter;
|
||||
|
||||
|
||||
/**
|
||||
* Abort status
|
||||
*/
|
||||
private boolean abort = false;
|
||||
private boolean abortForce = false;
|
||||
private Thread executionThread = null;
|
||||
|
||||
private final ChannelService cservice;
|
||||
|
||||
|
||||
private String id;
|
||||
private String name; // name of the motor channel
|
||||
private String readback; // name of the encoder channel
|
||||
private double start;
|
||||
private double end;
|
||||
private double stepSize;
|
||||
private double integrationTime;
|
||||
private double additionalBacklash;
|
||||
|
||||
|
||||
private final EventBus eventbus;
|
||||
private List<Metadata> metadata;
|
||||
|
||||
public CrlogicLoop(ChannelService cservice, String prefix, String server, String share, String smbShare, boolean zigZag){
|
||||
eventbus = new EventBus();
|
||||
this.cservice = cservice;
|
||||
this.prefix = prefix;
|
||||
this.server = server;
|
||||
this.share = share;
|
||||
this.smbShare = smbShare;
|
||||
this.zigZag = zigZag;
|
||||
|
||||
// Initialize lists used by the loop
|
||||
this.preActions = new ArrayList<Action>();
|
||||
this.postActions = new ArrayList<Action>();
|
||||
this.sensors = new ArrayList<>();
|
||||
this.readoutResources = new ArrayList<String>();
|
||||
this.scalerIndices = new HashMap<Integer, CrlogicDeltaDataFilter>();
|
||||
|
||||
this.crlogicDataFilter = new CrlogicRangeDataFilter();
|
||||
}
|
||||
|
||||
public void setActuator(String id, String name, String readback, double start, double end, double stepSize, double integrationTime, double additionalBacklash){
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.readback = readback;
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
this.stepSize = stepSize;
|
||||
this.integrationTime = integrationTime;
|
||||
this.additionalBacklash = additionalBacklash;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Collect data from share
|
||||
* @param tmpFileName Name of the temporary file
|
||||
* @throws InterruptedException
|
||||
* @throws IOException
|
||||
*/
|
||||
private void collectData(String tmpDir, String tmpFileName) throws InterruptedException, IOException {
|
||||
semaphore.acquire();
|
||||
|
||||
InputStreamReader inreader;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
inreader = new InputStreamReader(tmpFile.getInputStream());
|
||||
readData(inreader);
|
||||
|
||||
// Remove temporary file
|
||||
if(!keepTmpFiles){
|
||||
tmpFile.delete();
|
||||
}
|
||||
}
|
||||
else{
|
||||
File tmpFile = new File(tmpDir, tmpFileName);
|
||||
logger.info("Collect data from " + tmpFile.getCanonicalPath());
|
||||
|
||||
File lockfile = new File(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;
|
||||
}
|
||||
}
|
||||
|
||||
inreader = new InputStreamReader(new FileInputStream(tmpFile));
|
||||
readData(inreader);
|
||||
|
||||
// Remove temporary file
|
||||
if(!keepTmpFiles){
|
||||
tmpFile.delete();
|
||||
}
|
||||
}
|
||||
|
||||
// Issue end of loop control message
|
||||
eventbus.post(new EndOfStreamMessage(dataGroup));
|
||||
semaphore.release();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param inreader
|
||||
* @throws IOException
|
||||
*/
|
||||
private void readData(InputStreamReader inreader) throws IOException {
|
||||
BufferedReader in = new BufferedReader(inreader);
|
||||
String line;
|
||||
boolean firstline = true;
|
||||
int linecount=0;
|
||||
int mcounter=0;
|
||||
|
||||
// boolean wasInRangeBefore = false;
|
||||
boolean discardAnyway = false;
|
||||
|
||||
while (true) {
|
||||
line = in.readLine();
|
||||
linecount++;
|
||||
if (line == null) {
|
||||
break;
|
||||
} else {
|
||||
// if(line.matches("^\\[.*")){
|
||||
if (line.matches("^ *#.*")) {
|
||||
// Skip header/comment lines
|
||||
// logger.info("HEADER: " + line);
|
||||
} else {
|
||||
if (firstline) {
|
||||
firstline = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
// logger.info(line);
|
||||
|
||||
// Write into queue
|
||||
DataMessage message = new DataMessage(metadata);
|
||||
String[] tokens = line.split("\t");
|
||||
boolean use = true;
|
||||
|
||||
for(int i=0;i<tokens.length;i++){
|
||||
String t = tokens[i];
|
||||
Double val;
|
||||
|
||||
if(i==0){
|
||||
Double raw = new Double(t);
|
||||
|
||||
if(useEncoder){
|
||||
val = crlogicDataFilter.calculatePositionMotorUseEncoder(raw);
|
||||
}
|
||||
else if(useReadback){
|
||||
val = crlogicDataFilter.calculatePositionMotorUseReadback(raw);
|
||||
}
|
||||
else{
|
||||
val = crlogicDataFilter.calculatePositionMotor(raw);
|
||||
}
|
||||
|
||||
// Check whether data is within the configured range - otherwise drop data
|
||||
use = crlogicDataFilter.filter(val);
|
||||
// if(!use){
|
||||
// break;
|
||||
// }
|
||||
}
|
||||
else if(scalerIndices.containsKey(i)){
|
||||
CrlogicDeltaDataFilter f = scalerIndices.get(i);
|
||||
val = f.delta(new Double(t));
|
||||
}
|
||||
else{
|
||||
val = new Double(t);
|
||||
}
|
||||
|
||||
|
||||
message.getData().add(val);
|
||||
}
|
||||
|
||||
// Does not work if zigzag, ...
|
||||
// // Use this to filter out motor retry movements at the end of the scan
|
||||
// wasInRangeBefore = wasInRangeBefore | use;
|
||||
// if(!use && wasInRangeBefore){
|
||||
// discardAnyway=true;
|
||||
// // Optimization - terminate read loop once range is left
|
||||
// logger.info("Terminate read loop because point is outside range");
|
||||
// break;
|
||||
// }
|
||||
|
||||
// Filter data
|
||||
if(use && !discardAnyway){
|
||||
eventbus.post(message);
|
||||
mcounter++;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
in.close();
|
||||
inreader.close();
|
||||
|
||||
logger.info("Lines read: "+linecount+" Messages generated (after filtering): "+mcounter);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ch.psi.fda.core.Action#execute()
|
||||
*/
|
||||
@Override
|
||||
public void execute() throws InterruptedException {
|
||||
try{
|
||||
|
||||
// Set values for the datafilter
|
||||
crlogicDataFilter.setStart(start);
|
||||
crlogicDataFilter.setEnd(end);
|
||||
|
||||
// Reset data filter
|
||||
for(Integer k: scalerIndices.keySet()){
|
||||
scalerIndices.get(k).reset();
|
||||
}
|
||||
|
||||
synchronized(this){
|
||||
// Set abort state to false
|
||||
abort = false;
|
||||
abortForce = false;
|
||||
|
||||
// Set execution thread to current thread
|
||||
executionThread = Thread.currentThread();
|
||||
}
|
||||
|
||||
|
||||
// TODO each actuator will result in an additional sensor (at the beginning)
|
||||
// Dependent on actuator settings (readback use encoder, ...)
|
||||
|
||||
|
||||
// TODO filename generation?
|
||||
final String tmpFileName = "tmp-"+System.currentTimeMillis()+".txt";
|
||||
|
||||
Long timeout = 600000l; // 10 minutes move timeout
|
||||
|
||||
// Check if logic is inactive, otherwise return early
|
||||
if(!template.getStatus().getValue().equals(TemplateCrlogic.Status.INACTIVE.toString())){
|
||||
logger.info("CRLOGIC is not inactive!");
|
||||
// TODO Decide what to do in this situation
|
||||
|
||||
if(template.getStatus().getValue().equals(TemplateCrlogic.Status.FAULT.toString())){
|
||||
// If in fault show message and recover
|
||||
logger.info("CRLOGIC in FAULT state");
|
||||
logger.info("Error message: "+template.getMessage().getValue());
|
||||
logger.info("Recover logic and set it to INACTIVE");
|
||||
template.getStatus().setValue(TemplateCrlogic.Status.INACTIVE.toString());
|
||||
}
|
||||
else if(template.getStatus().getValue().equals(TemplateCrlogic.Status.ACTIVE.toString())){
|
||||
template.getStatus().setValue(TemplateCrlogic.Status.STOP.toString());
|
||||
template.getStatus().waitForValue(TemplateCrlogic.Status.INACTIVE.toString(), startStopTimeout);
|
||||
}
|
||||
else{
|
||||
throw new RuntimeException("CRLOGIC is not inactive");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
logger.info("Set parameters");
|
||||
template.getNfsServer().setValue(server);
|
||||
template.getNfsShare().setValue(share);
|
||||
template.getDataFile().setValue(tmpFileName);
|
||||
|
||||
int tps = template.getTicksPerSecond().getValue();
|
||||
logger.info("Ticks per second: "+tps);
|
||||
|
||||
logger.info("Set readout resources");
|
||||
|
||||
template.getReadoutResources().setValue(readoutResources.toArray(new String[readoutResources.size()]));
|
||||
|
||||
|
||||
|
||||
// Set ticks between interrupt to integration time
|
||||
int ticks = (int)(tps*integrationTime);
|
||||
template.getTicksBetweenInterrupts().setValue(ticks);
|
||||
|
||||
// Prepare motor
|
||||
double totalTimeSeconds = Math.abs((end-start)/stepSize*integrationTime);
|
||||
int hours = (int) Math.floor(totalTimeSeconds/60/60);
|
||||
int minutes = (int) Math.floor(totalTimeSeconds/60-hours*60);
|
||||
int seconds = (int) Math.floor(totalTimeSeconds-hours*60*60-minutes*60);
|
||||
|
||||
logger.info("Estimated time: "+hours+":"+minutes+":"+seconds);
|
||||
|
||||
int direction = 1;
|
||||
if(end-start<0){
|
||||
direction = -1;
|
||||
}
|
||||
|
||||
double motorBaseSpeed = motortemplate.getBaseSpeed().getValue();
|
||||
double motorHighLimit = motortemplate.getHighLimit().getValue();
|
||||
double motorLowLimit = motortemplate.getLowLimit().getValue();
|
||||
double motorBacklash = motortemplate.getBacklashDistance().getValue();
|
||||
|
||||
boolean respectMotorMinSpeed = false; // if false set min speed to 0
|
||||
double motorMinSpeed = 0;
|
||||
if(respectMotorMinSpeed){
|
||||
motorMinSpeed = motorBaseSpeed;
|
||||
}
|
||||
|
||||
// Check user parameters
|
||||
// TODO start and end values must be between the motor high and low value - otherwise fail
|
||||
if(start>motorHighLimit || start<motorLowLimit){
|
||||
// Start value is outside motor high and/or low value
|
||||
logger.info("Start value is outside motor high and/or low value");
|
||||
throw new IllegalArgumentException("Start value is outside motor high and/or low value");
|
||||
}
|
||||
if(end>motorHighLimit || end<motorLowLimit){
|
||||
// End value is outside motor high and/or low value
|
||||
logger.info("End value is outside motor high and/or low value");
|
||||
throw new IllegalArgumentException("End value is outside motor high and/or low value");
|
||||
}
|
||||
// TODO Check minimum step size
|
||||
int minimumTicks = 10;
|
||||
double minStepSize = motorMinSpeed*(minimumTicks/tps);
|
||||
if(stepSize<minStepSize){
|
||||
// Step size is too small
|
||||
logger.info("Step size is too small");
|
||||
throw new IllegalArgumentException("Step size is too small");
|
||||
}
|
||||
// TODO Check integration time
|
||||
if(motorMinSpeed>0){
|
||||
double maxIntegrationTime = stepSize/motorMinSpeed;
|
||||
if(integrationTime>maxIntegrationTime){
|
||||
logger.info("Integration time is too big");
|
||||
// Integration time is too big
|
||||
throw new IllegalArgumentException("Integration time is too big");
|
||||
}
|
||||
}
|
||||
double motorMaxSpeed = motortemplate.getVelocity().getValue();
|
||||
double minIntegrationTime = Math.min( (stepSize/motorMaxSpeed), ((double)minimumTicks/(double)tps) );
|
||||
if(integrationTime<minIntegrationTime){
|
||||
// Integration time is too small
|
||||
logger.info("Integration time is too small [min integration time: "+minIntegrationTime+"]");
|
||||
throw new IllegalArgumentException("Integration time is too small [min integration time: "+minIntegrationTime+"]");
|
||||
}
|
||||
|
||||
|
||||
// TODO Calculate and set motor speed, backlash, etc.
|
||||
double motorSpeed = stepSize/integrationTime;
|
||||
double backlash = (0.5*motorSpeed*motortemplate.getAccelerationTime().getValue())+motorBacklash+additionalBacklash;
|
||||
double realEnd = end+(backlash*direction);
|
||||
double realStart = start-(backlash*direction);
|
||||
|
||||
|
||||
// Move to start
|
||||
logger.info("Move motor to start ["+realStart+"]");
|
||||
motortemplate.getSetValue().setValueAsync(realStart).get(timeout, TimeUnit.MILLISECONDS); // Will block until move is done
|
||||
|
||||
|
||||
// Set motor paramters
|
||||
// Backup settings
|
||||
logger.info("Backup motor settings");
|
||||
double backupSpeed = motortemplate.getVelocity().getValue();
|
||||
double backupBacklash = motorBacklash;
|
||||
double backupMinSpeed = motorBaseSpeed;
|
||||
|
||||
try{
|
||||
// Set motor settings
|
||||
logger.info("Update motor settings");
|
||||
// if(!respectMotorMinSpeed){
|
||||
// motortemplate.getBaseSpeed().setValue(0d);
|
||||
// }
|
||||
// Set base speed as fast as possible but not faster than the original base speed.
|
||||
double base = motorBaseSpeed;
|
||||
if(motorSpeed<base){
|
||||
base = motorSpeed;
|
||||
}
|
||||
motortemplate.getBaseSpeed().setValue(base);
|
||||
motortemplate.getVelocity().setValue(motorSpeed);
|
||||
motortemplate.getBacklashDistance().setValue(0d);
|
||||
|
||||
|
||||
// Execute pre actions
|
||||
for(Action action: preActions){
|
||||
action.execute();
|
||||
}
|
||||
|
||||
|
||||
// Start crlogic logic
|
||||
logger.info("Start CRLOGIC");
|
||||
template.getStatus().setValue(TemplateCrlogic.Status.INITIALIZE.toString());
|
||||
try{
|
||||
template.getStatus().waitForValue(TemplateCrlogic.Status.ACTIVE.toString(), startStopTimeout);
|
||||
}
|
||||
catch(ChannelException | ExecutionException | TimeoutException e){
|
||||
logger.info( "Failed to start CRLOGIC. Logic in status: "+template.getStatus().getValue() );
|
||||
if(template.getStatus().getValue().equals(TemplateCrlogic.Status.FAULT.toString())){
|
||||
logger.info("Error message: "+template.getMessage().getValue());
|
||||
}
|
||||
// Recover to inactive
|
||||
template.getStatus().setValue(TemplateCrlogic.Status.INACTIVE.toString());
|
||||
// TODO Improve error handling
|
||||
throw new RuntimeException("Failed to start CRLOGIC. Logic in status: "+template.getStatus().getValue()+ " Error message: "+template.getMessage().getValue(), e);
|
||||
|
||||
}
|
||||
|
||||
// Move motor(s) to end / wait until motor is stopped
|
||||
logger.info("Move motor to end ["+realEnd+"]");
|
||||
try{
|
||||
motortemplate.getSetValue().setValueAsync(realEnd).get(timeout, TimeUnit.MILLISECONDS); // Will block until move is done
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
if(abort & (!abortForce)){
|
||||
// Abort motor move
|
||||
motortemplate.getCommand().setValue(TemplateMotor.Commands.Stop.ordinal());
|
||||
motortemplate.getCommand().setValue(TemplateMotor.Commands.Go.ordinal());
|
||||
}
|
||||
else{
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
logger.info("Motor reached end position");
|
||||
|
||||
// Stop crlogic logic
|
||||
logger.info("Stop CRLOGIC");
|
||||
template.getStatus().setValue(TemplateCrlogic.Status.STOP.toString());
|
||||
// Wait until stopped
|
||||
logger.info("Wait until stopped");
|
||||
try{
|
||||
template.getStatus().waitForValue(TemplateCrlogic.Status.INACTIVE.toString(), startStopTimeout);
|
||||
}
|
||||
catch(ChannelException | ExecutionException | TimeoutException e){
|
||||
logger.info( "Failed to stop CRLOGIC. Logic in status: "+template.getStatus().getValue() );
|
||||
// TODO Improve error handling
|
||||
throw new RuntimeException("Failed to stop CRLOGIC. Logic in status: "+template.getStatus().getValue(), e);
|
||||
}
|
||||
logger.info("CRLOGIC is now stopped");
|
||||
|
||||
|
||||
// Execute post actions
|
||||
for(Action action: postActions){
|
||||
action.execute();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
finally{
|
||||
logger.info("Restore motor settings");
|
||||
motortemplate.getBaseSpeed().setValue(backupMinSpeed);
|
||||
motortemplate.getVelocity().setValue(backupSpeed);
|
||||
motortemplate.getBacklashDistance().setValue(backupBacklash);
|
||||
}
|
||||
|
||||
// Request read of data file
|
||||
readQueue.put(tmpFileName);
|
||||
|
||||
if(zigZag){
|
||||
// reverse start/end
|
||||
double aend = end;
|
||||
end=start;
|
||||
start=aend;
|
||||
}
|
||||
|
||||
synchronized(this){
|
||||
executionThread = null;
|
||||
}
|
||||
}
|
||||
catch(ChannelException | ExecutionException | TimeoutException e){
|
||||
throw new RuntimeException("Unable to execute crloop", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void abort() {
|
||||
abort(false);
|
||||
}
|
||||
|
||||
public synchronized void abort(boolean force){
|
||||
abort = true;
|
||||
abortForce = force;
|
||||
|
||||
// executionThread variable guarded by "this"
|
||||
if(executionThread != null){
|
||||
executionThread.interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepare() {
|
||||
|
||||
metadata = new ArrayList<>();
|
||||
|
||||
// Build up metadata
|
||||
metadata.add(new Metadata(this.id));
|
||||
for(CrlogicResource s: sensors){
|
||||
metadata.add(new Metadata(s.getId()));
|
||||
}
|
||||
|
||||
|
||||
stopReadoutThread = false;
|
||||
// Start readout Thread
|
||||
readoutThread = new Thread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
while(!stopReadoutThread){
|
||||
String file;
|
||||
try {
|
||||
file = readQueue.take();
|
||||
} catch (InterruptedException e) {
|
||||
break;
|
||||
}
|
||||
// TODO Read file and
|
||||
try {
|
||||
collectData(smbShare, file);
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException("Unable to read CRLOGIC raw data file",e);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Unable to read CRLOGIC raw data file",e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
readoutThread.start();
|
||||
|
||||
try{
|
||||
// Connect crlogic channels
|
||||
template = new TemplateCrlogic();
|
||||
logger.info("Connect channels");
|
||||
Map<String,String> map = new HashMap<>();
|
||||
map.put("PREFIX", prefix);
|
||||
cservice.createAnnotatedChannels(template, map);
|
||||
|
||||
// Connect motor channels
|
||||
motortemplate = new TemplateMotor();
|
||||
map = new HashMap<>();
|
||||
map.put("PREFIX", this.name);
|
||||
cservice.createAnnotatedChannels(motortemplate, map);
|
||||
|
||||
useReadback = motortemplate.getUseReadback().getValue();
|
||||
useEncoder = motortemplate.getUseEncoder().getValue();
|
||||
|
||||
logger.info("Motor type: "+ TemplateMotor.Type.values()[motortemplate.getType().getValue()]);
|
||||
logger.info("Motor use readback: "+useReadback);
|
||||
logger.info("Motor use encoder: "+useEncoder);
|
||||
|
||||
// TODO build up list of readout resources (based on sensors)
|
||||
readoutResources.clear();
|
||||
// first sensor is the actuator
|
||||
|
||||
// Determine mode of motor
|
||||
if((!useReadback) && (!useEncoder)){
|
||||
// Open loop
|
||||
if(this.readback!=null){
|
||||
throw new IllegalArgumentException("Readback not supported if motor is configured in open loop");
|
||||
}
|
||||
else{
|
||||
readoutResources.add(this.name);
|
||||
}
|
||||
|
||||
}
|
||||
else if(useReadback && (!useEncoder)){
|
||||
String readback;
|
||||
// use readback link
|
||||
if(this.readback!=null){
|
||||
// Use specified readback
|
||||
readback = this.readback;
|
||||
}
|
||||
else{
|
||||
// Set resouce to readback link
|
||||
readback = (motortemplate.getReadbackLink().getValue());
|
||||
readback = readback.replaceAll(" +.*", ""); // remove NPP etc at the end
|
||||
}
|
||||
|
||||
readoutResources.add(readback);
|
||||
|
||||
// Fill readback encoder settings
|
||||
// Connect to encoder
|
||||
TemplateEncoder encodertemplate = new TemplateEncoder();
|
||||
map = new HashMap<>();
|
||||
map.put("PREFIX", readback);
|
||||
cservice.createAnnotatedChannels(encodertemplate, map);
|
||||
|
||||
// Read encoder settings
|
||||
if(encodertemplate.getDirection().getValue()==TemplateEncoder.Direction.Positive.ordinal()){
|
||||
crlogicDataFilter.setEncoderDirection(1);
|
||||
}
|
||||
else{
|
||||
crlogicDataFilter.setEncoderDirection(-1);
|
||||
}
|
||||
crlogicDataFilter.setEncoderOffset(encodertemplate.getOffset().getValue());
|
||||
crlogicDataFilter.setEncoderResolution(encodertemplate.getResolution().getValue());
|
||||
|
||||
// Disconnect from encoder
|
||||
cservice.destroyAnnotatedChannels(encodertemplate);
|
||||
|
||||
}
|
||||
else if (useEncoder && (!useReadback)){
|
||||
// use readback link
|
||||
if(this.readback!=null){
|
||||
throw new IllegalArgumentException("Readback not supported if motor is configured to use encoder");
|
||||
}
|
||||
else{
|
||||
// Set resouce to readback link
|
||||
readoutResources.add(this.name+"_ENC");
|
||||
}
|
||||
}
|
||||
else{
|
||||
throw new IllegalArgumentException("Motor configuration not supportet: use readback - "+useReadback+" use encoder - "+useEncoder);
|
||||
}
|
||||
|
||||
// Fill Motor specific settings
|
||||
if(motortemplate.getDirection().getValue()==TemplateMotor.Direction.Positive.ordinal()){
|
||||
crlogicDataFilter.setMotorDirection(1);
|
||||
}
|
||||
else{
|
||||
crlogicDataFilter.setMotorDirection(-1);
|
||||
}
|
||||
crlogicDataFilter.setMotorEncoderResolution(motortemplate.getEncoderResolution().getValue());
|
||||
crlogicDataFilter.setMotorOffset(motortemplate.getOffset().getValue());
|
||||
crlogicDataFilter.setMotorReadbackResolution(motortemplate.getReadbackResolution().getValue());
|
||||
crlogicDataFilter.setMotorResolution(motortemplate.getMotorResolution().getValue());
|
||||
|
||||
// Clear all indices
|
||||
scalerIndices.clear();
|
||||
|
||||
int c = 1; // We start at 1 because the actuator right now is an implicit sensor
|
||||
for(CrlogicResource s: sensors){
|
||||
readoutResources.add(s.getKey());
|
||||
if(s.isDelta()){
|
||||
scalerIndices.put(c, new CrlogicDeltaDataFilter());
|
||||
}
|
||||
c++;
|
||||
}
|
||||
|
||||
// Workaround - somehow one has to add an empty thing to the value otherwise the c logic
|
||||
// does not pick up the end
|
||||
readoutResources.add("");
|
||||
}
|
||||
catch(Exception e){
|
||||
throw new RuntimeException("Unable to prepare crloop: ",e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanup() {
|
||||
stopReadoutThread = true;
|
||||
readoutThread.interrupt();
|
||||
|
||||
try {
|
||||
cservice.destroyAnnotatedChannels(template);
|
||||
cservice.destroyAnnotatedChannels(motortemplate);
|
||||
template = null;
|
||||
motortemplate = null;
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Unable to destroy CrlogicLoop", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Action> getPreActions() {
|
||||
return preActions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Action> getPostActions() {
|
||||
return postActions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDataGroup() {
|
||||
return dataGroup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDataGroup(boolean dataGroup) {
|
||||
this.dataGroup = dataGroup;
|
||||
}
|
||||
|
||||
public List<CrlogicResource> getSensors() {
|
||||
return sensors;
|
||||
}
|
||||
|
||||
public boolean isKeepTmpFiles() {
|
||||
return keepTmpFiles;
|
||||
}
|
||||
|
||||
public void setKeepTmpFiles(boolean keepTmpFiles) {
|
||||
this.keepTmpFiles = keepTmpFiles;
|
||||
}
|
||||
|
||||
public EventBus getEventBus(){
|
||||
return eventbus;
|
||||
}
|
||||
}
|
||||
@@ -33,7 +33,6 @@ import java.util.logging.Logger;
|
||||
import org.zeromq.ZMQ;
|
||||
import org.zeromq.ZMQ.Context;
|
||||
import org.zeromq.ZMQ.Socket;
|
||||
import org.zeromq.ZMQException;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.common.eventbus.EventBus;
|
||||
@@ -52,7 +51,7 @@ import ch.psi.jcae.ChannelService;
|
||||
* sysClkRateSet 1000
|
||||
*
|
||||
*/
|
||||
public class CrlogicLoopStream extends CrlogicLoop implements ActionLoop {
|
||||
public class CrlogicLoopStream implements ActionLoop {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(CrlogicLoopStream.class.getName());
|
||||
|
||||
@@ -127,7 +126,6 @@ public class CrlogicLoopStream extends CrlogicLoop implements ActionLoop {
|
||||
private List<Metadata> metadata;
|
||||
|
||||
public CrlogicLoopStream(ChannelService cservice, String prefix, String ioc, boolean zigZag){
|
||||
super(cservice, prefix, "", "", "", zigZag);
|
||||
eventbus = new EventBus();
|
||||
this.cservice = cservice;
|
||||
this.prefix = prefix;
|
||||
@@ -476,6 +474,11 @@ public class CrlogicLoopStream extends CrlogicLoop implements ActionLoop {
|
||||
catch(ChannelException | ExecutionException | TimeoutException e){
|
||||
throw new RuntimeException("Unable to execute crloop", e);
|
||||
}
|
||||
finally{
|
||||
// Send end of stream message
|
||||
System.out.println("end of line - "+dataGroup);
|
||||
eventbus.post(new EndOfStreamMessage(dataGroup));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -491,6 +494,9 @@ public class CrlogicLoopStream extends CrlogicLoop implements ActionLoop {
|
||||
if(executionThread != null){
|
||||
executionThread.interrupt();
|
||||
}
|
||||
|
||||
// Close ZMQ stream to read data from
|
||||
close();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -513,6 +519,9 @@ public class CrlogicLoopStream extends CrlogicLoop implements ActionLoop {
|
||||
@Override
|
||||
public void run() {
|
||||
connect(ioc);
|
||||
// Clean start of messages - no hanging submessages - although this drops the first message ...
|
||||
drainHangingSubmessages();
|
||||
|
||||
while(!stopReadoutThread){
|
||||
receive();
|
||||
}
|
||||
@@ -641,7 +650,8 @@ public class CrlogicLoopStream extends CrlogicLoop implements ActionLoop {
|
||||
}
|
||||
}
|
||||
|
||||
public void connect(String address) {
|
||||
|
||||
private void connect(String address) {
|
||||
// Clear interrupted state
|
||||
Thread.interrupted();
|
||||
|
||||
@@ -652,7 +662,9 @@ public class CrlogicLoopStream extends CrlogicLoop implements ActionLoop {
|
||||
socket.connect("tcp://"+address+":9999");
|
||||
}
|
||||
|
||||
public void close() {
|
||||
|
||||
|
||||
private void close() {
|
||||
logger.info("Closing stream from IOC "+ioc);
|
||||
|
||||
// Send end of stream message
|
||||
@@ -719,12 +731,6 @@ public class CrlogicLoopStream extends CrlogicLoop implements ActionLoop {
|
||||
return sensors;
|
||||
}
|
||||
|
||||
public boolean isKeepTmpFiles() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setKeepTmpFiles(boolean keepTmpFiles) {
|
||||
}
|
||||
|
||||
public EventBus getEventBus(){
|
||||
return eventbus;
|
||||
|
||||
@@ -50,7 +50,7 @@ public class ParallelCrlogic implements ActionLoop {
|
||||
*/
|
||||
private boolean dataGroup = false;
|
||||
|
||||
private CrlogicLoop crlogic;
|
||||
private CrlogicLoopStream crlogic;
|
||||
private ScrlogicLoop scrlogic;
|
||||
|
||||
/**
|
||||
@@ -67,7 +67,7 @@ public class ParallelCrlogic implements ActionLoop {
|
||||
|
||||
private final EventBus eventbus;
|
||||
|
||||
public ParallelCrlogic(CrlogicLoop crlogic, ScrlogicLoop scrlogic){
|
||||
public ParallelCrlogic(CrlogicLoopStream crlogic, ScrlogicLoop scrlogic){
|
||||
|
||||
if(crlogic==null){
|
||||
throw new IllegalArgumentException("No Crloop specified");
|
||||
@@ -165,19 +165,6 @@ public class ParallelCrlogic implements ActionLoop {
|
||||
}});
|
||||
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 {
|
||||
|
||||
@@ -1,158 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* Copyright 2012 Paul Scherrer Institute. All rights reserved.
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Foundation, either version 3 of the License, or (at your option) any
|
||||
* later version.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but without any
|
||||
* warranty; without even the implied warranty of merchantability or fitness for
|
||||
* a particular purpose. See the GNU Lesser General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this code. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package ch.psi.fda.core.loops.otf;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.MalformedURLException;
|
||||
|
||||
import jcifs.smb.SmbFile;
|
||||
|
||||
public class DistributedFile {
|
||||
|
||||
private SmbFile smbfile = null;
|
||||
private File file = null;
|
||||
|
||||
public DistributedFile(SmbFile file){
|
||||
this.smbfile = file;
|
||||
}
|
||||
|
||||
public DistributedFile(File file){
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
public DistributedFile(String url) throws MalformedURLException{
|
||||
if(url.startsWith("smb://")){
|
||||
smbfile = new SmbFile(url);
|
||||
}
|
||||
else {
|
||||
file = new File(url);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public String getCanonicalPath() throws IOException{
|
||||
if(smbfile!=null){
|
||||
return(smbfile.getCanonicalPath());
|
||||
}
|
||||
else{
|
||||
return file.getCanonicalPath();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
public boolean exists() throws IOException {
|
||||
if(smbfile!=null){
|
||||
return(smbfile.exists());
|
||||
}
|
||||
else{
|
||||
return file.exists();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public boolean isDirectory() throws IOException {
|
||||
if(smbfile!=null){
|
||||
return(smbfile.isDirectory());
|
||||
}
|
||||
else{
|
||||
return file.isDirectory();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public DistributedFile[] listFiles() throws IOException {
|
||||
if(smbfile!=null){
|
||||
SmbFile[] files = smbfile.listFiles();
|
||||
DistributedFile[] dfiles = new DistributedFile[files.length];
|
||||
for(int i=0;i<files.length;i++){
|
||||
dfiles[i] = new DistributedFile(files[i]);
|
||||
}
|
||||
return(dfiles);
|
||||
}
|
||||
else{
|
||||
File[] files = file.listFiles();
|
||||
DistributedFile[] dfiles = new DistributedFile[files.length];
|
||||
for(int i=0;i<files.length;i++){
|
||||
dfiles[i] = new DistributedFile(files[i]);
|
||||
}
|
||||
return(dfiles);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public String getName() {
|
||||
if(smbfile!=null){
|
||||
return(smbfile.getName());
|
||||
}
|
||||
else{
|
||||
return file.getName();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public boolean isFile() throws IOException {
|
||||
if(smbfile!=null){
|
||||
return(smbfile.isFile());
|
||||
}
|
||||
else{
|
||||
return file.isFile();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public void delete() throws IOException {
|
||||
if(smbfile!=null){
|
||||
smbfile.delete();
|
||||
}
|
||||
else{
|
||||
file.delete();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public InputStreamReader getInputStream() throws IOException {
|
||||
if(smbfile!=null){
|
||||
return(new InputStreamReader(smbfile.getInputStream()));
|
||||
}
|
||||
else{
|
||||
return new FileReader(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,439 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful,
|
||||
* but without any warranty; without even the implied warranty of
|
||||
* merchantability or fitness for a particular purpose. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this code. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.psi.fda.core.loops.otf;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.MalformedURLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.google.common.eventbus.EventBus;
|
||||
|
||||
import ch.psi.fda.core.Action;
|
||||
import ch.psi.fda.core.ActionLoop;
|
||||
import ch.psi.fda.core.Sensor;
|
||||
import ch.psi.fda.core.sensors.TimestampSensor;
|
||||
import ch.psi.fda.messages.DataMessage;
|
||||
import ch.psi.fda.messages.EndOfStreamMessage;
|
||||
import ch.psi.fda.messages.Metadata;
|
||||
|
||||
/**
|
||||
* ActionLoop that is implementing the OTF Scan logic.
|
||||
* While executing the loop a full OTF scan procedure is executed.
|
||||
*/
|
||||
public class OTFLoop implements ActionLoop {
|
||||
|
||||
private static Logger logger = Logger.getLogger(OTFLoop.class.getName());
|
||||
|
||||
/**
|
||||
* Flag to indicate whether the data of this loop will be grouped
|
||||
* According to this flag the dataGroup flag in EndOfStream will be set.
|
||||
*/
|
||||
private boolean dataGroup = false;
|
||||
|
||||
/**
|
||||
* Maximum number of monitored channels
|
||||
*/
|
||||
private static final int numberOfMonitoredChannels = 8;
|
||||
/**
|
||||
* Maximum number of Scaler channels
|
||||
*/
|
||||
private static final int numberOfScalerChannels = 16;
|
||||
|
||||
/**
|
||||
* Default timeout (in milliseconds) for wait operations
|
||||
*/
|
||||
private long timeout = 8000;
|
||||
|
||||
/**
|
||||
* Name of the NFS server to place the data of the OTF logic
|
||||
*/
|
||||
private final String server;
|
||||
/**
|
||||
* Share on the NFS server to put the OTF data on to
|
||||
*/
|
||||
private final String share;
|
||||
/**
|
||||
* SMB share to access the data written by the OTF C logic
|
||||
*/
|
||||
private final String smbShare;
|
||||
|
||||
/**
|
||||
* Flag whether the actor of this loop should move in zig zag mode
|
||||
*/
|
||||
private final boolean zigZag;
|
||||
|
||||
/**
|
||||
* Bean holding all OTF channels and functionality.
|
||||
*/
|
||||
private TemplateOTF obean;
|
||||
|
||||
/**
|
||||
* List of actions that are executed at the beginning of the loop.
|
||||
*/
|
||||
private List<Action> preActions;
|
||||
/**
|
||||
* List of actions that are executed at the end of the loop.
|
||||
*/
|
||||
private List<Action> postActions;
|
||||
|
||||
/**
|
||||
* List of sensors of this loop
|
||||
*/
|
||||
private List<Sensor> sensors;
|
||||
|
||||
|
||||
private List<Integer> dataIndexes;
|
||||
|
||||
/**
|
||||
* Execution count of this loop. This count is used to determine the
|
||||
* file name of the OTF file.
|
||||
*/
|
||||
private int executionCount;
|
||||
|
||||
/**
|
||||
* Flag that indicates that the loop was requested to abort.
|
||||
*/
|
||||
private volatile boolean abort = false;
|
||||
|
||||
|
||||
private String id;
|
||||
private String name; // name of the motor channel
|
||||
private String readback; // name of the encoder channel
|
||||
private double start;
|
||||
private double end;
|
||||
private double stepSize;
|
||||
private double integrationTime;
|
||||
private double additionalBacklash;
|
||||
|
||||
private final EventBus eventbus;
|
||||
private List<Metadata> metadata;
|
||||
|
||||
/**
|
||||
* @param channelPrefix Prefix of the OTF related records, e.g. MTEST-HW3-OTF
|
||||
* @param server NFS server the OTF C Logic should put its data to
|
||||
* @param share Share on NFS server to put the OTF C Logic data
|
||||
* @param smbShare SMB share to get the data written by the OTF C Logic
|
||||
* @param zigZag Operate loop in zig zag mode
|
||||
*/
|
||||
public OTFLoop(TemplateOTF obean, String server, String share, String smbShare, boolean zigZag){
|
||||
|
||||
this.eventbus = new EventBus();
|
||||
|
||||
this.obean = obean;
|
||||
|
||||
// Store loop configuration
|
||||
this.server = server;
|
||||
this.share = share;
|
||||
this.smbShare = smbShare;
|
||||
this.zigZag = zigZag;
|
||||
|
||||
// Initialize lists used by the loop
|
||||
this.preActions = new ArrayList<Action>();
|
||||
this.postActions = new ArrayList<Action>();
|
||||
this.sensors = new ArrayList<Sensor>();
|
||||
}
|
||||
|
||||
public void setActuator(String id, String name, String readback, double start, double end, double stepSize, double integrationTime, double additionalBacklash){
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.readback = readback;
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
this.stepSize = stepSize;
|
||||
this.integrationTime = integrationTime;
|
||||
this.additionalBacklash = additionalBacklash;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void execute() throws InterruptedException {
|
||||
|
||||
// Execute pre actions
|
||||
for(Action action: preActions){
|
||||
action.execute();
|
||||
}
|
||||
|
||||
// Start scan
|
||||
obean.start();
|
||||
|
||||
// Wait for end of scan
|
||||
obean.waitUntilStopped();
|
||||
|
||||
// Read data from file
|
||||
collectData();
|
||||
|
||||
// Execute post actions
|
||||
for(Action action: postActions){
|
||||
action.execute();
|
||||
}
|
||||
|
||||
|
||||
// Issue end of loop control message
|
||||
eventbus.post(new EndOfStreamMessage(dataGroup));
|
||||
|
||||
// Increase execution count
|
||||
executionCount++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void abort() {
|
||||
// Abort otf scan logic
|
||||
obean.abort();
|
||||
|
||||
abort=true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepare() {
|
||||
executionCount = 0;
|
||||
|
||||
// Set abort flag to false
|
||||
abort=false;
|
||||
|
||||
// list with all monitored channels
|
||||
List<String> monitoredChannels = new ArrayList<String>();
|
||||
dataIndexes = new ArrayList<Integer>();
|
||||
dataIndexes.add(1); // The first one is always the readback of the motor
|
||||
int channelCount =0;
|
||||
for(Sensor s: sensors){
|
||||
if(s instanceof OTFNamedChannelSensor){
|
||||
// Monitored channel
|
||||
OTFNamedChannelSensor so = (OTFNamedChannelSensor) s;
|
||||
if(channelCount>=numberOfMonitoredChannels){
|
||||
throw new IllegalArgumentException("Only up to "+numberOfMonitoredChannels+" channels can be monitored by OTF");
|
||||
}
|
||||
|
||||
monitoredChannels.add(so.getName());
|
||||
dataIndexes.add(2+numberOfScalerChannels+channelCount);
|
||||
|
||||
|
||||
channelCount++;
|
||||
}
|
||||
else if (s instanceof OTFScalerChannelSensor){
|
||||
OTFScalerChannelSensor so = (OTFScalerChannelSensor) s;
|
||||
if(so.getIndex()>=numberOfScalerChannels){
|
||||
throw new IllegalArgumentException("Scaler index must be between 0<=index<"+numberOfScalerChannels);
|
||||
}
|
||||
dataIndexes.add(2+so.getIndex()); // scalers follow directly after the readback
|
||||
}
|
||||
else if (s instanceof TimestampSensor){
|
||||
dataIndexes.add(2+numberOfScalerChannels+numberOfMonitoredChannels);
|
||||
}
|
||||
// else if (s instanceof OTFReadbackSensor){
|
||||
// dataIndexes.add(1);
|
||||
// }
|
||||
else{
|
||||
throw new IllegalArgumentException("Sensor type "+s.getClass()+" is not supported by this loop");
|
||||
}
|
||||
}
|
||||
|
||||
// Set OTF parameters
|
||||
try{
|
||||
obean.resetToDefaults();
|
||||
|
||||
// Set actor properties
|
||||
obean.setMotor(this.name);
|
||||
obean.waitUntilMotorOk(timeout);
|
||||
|
||||
obean.setBegin(this.start);
|
||||
obean.setEnd(this.end);
|
||||
obean.setStepSize(this.stepSize);
|
||||
obean.setIntegrationTime(this.integrationTime);
|
||||
|
||||
// Override encoder if specified
|
||||
if(this.readback!=null){
|
||||
obean.setUseEncoder(true);
|
||||
obean.setEncoder(this.readback);
|
||||
obean.waitUntilEncoderOk(timeout);
|
||||
}
|
||||
|
||||
// Set user backlash
|
||||
obean.setUserBacklash(this.additionalBacklash);
|
||||
|
||||
|
||||
// NFS settings
|
||||
obean.setNfsServer(server);
|
||||
obean.setNfsShare(share);
|
||||
|
||||
obean.setFileNameGeneration(true);
|
||||
obean.setAppendFile(false);
|
||||
obean.setZigZag(zigZag); // Set ZigZag because there might be iterations
|
||||
obean.setFileNameFormat("%06d"); // Force an update of the filename/counter by setting file format twice with different values
|
||||
obean.setFileNameFormat("%06d.txt");
|
||||
|
||||
|
||||
|
||||
// Set monitored channels
|
||||
obean.setMonitoredChannels(monitoredChannels.toArray(new String[monitoredChannels.size()]));
|
||||
}
|
||||
catch(Exception e){
|
||||
throw new RuntimeException("Unable to set OTF configuration parameters",e);
|
||||
}
|
||||
|
||||
|
||||
// Cleanup temporary directory
|
||||
try{
|
||||
DistributedFile tmpDir = new DistributedFile(smbShare);
|
||||
if( !tmpDir.exists() || !tmpDir.isDirectory() ){
|
||||
throw new RuntimeException("Cannot access OTF temporary directory "+tmpDir.getCanonicalPath());
|
||||
}
|
||||
DistributedFile[] files = tmpDir.listFiles();
|
||||
|
||||
for(int i=0;i<files.length;i++){
|
||||
// Only delete item if it is not a directory and if it matches the given pattern.
|
||||
if(files[i].isFile() && files[i].getName().matches("[0-9]+.txt")){
|
||||
files[i].delete();
|
||||
logger.fine("Delete file: "+files[i].getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(MalformedURLException e){
|
||||
throw new RuntimeException(e);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Unable to access share (temporary files)",e);
|
||||
}
|
||||
|
||||
metadata = new ArrayList<>();
|
||||
metadata.add(new Metadata(id)); // Id of the readback of the motor
|
||||
|
||||
// Build up data message metadata based on the sensors currently registered.
|
||||
for(Sensor s: sensors){
|
||||
metadata.add(new Metadata(s.getId()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanup() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Action> getPreActions() {
|
||||
return preActions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Action> getPostActions() {
|
||||
return postActions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect data written by the OTFScan logic
|
||||
* @param dataSet
|
||||
* @param tmpFile
|
||||
*/
|
||||
private void collectData() {
|
||||
try{
|
||||
final int timestampIndex = 2+numberOfScalerChannels+numberOfMonitoredChannels;
|
||||
|
||||
DistributedFile tmpFile = new DistributedFile(smbShare +"/"+ String.format("%06d.txt", executionCount));
|
||||
logger.fine("Collect data from "+tmpFile.getCanonicalPath());
|
||||
|
||||
DistributedFile lockfile = new DistributedFile(tmpFile.getCanonicalPath() + ".lock");
|
||||
|
||||
logger.fine("Wait until file is written [lock file: "+lockfile.getCanonicalPath()+"]");
|
||||
// Wait until file is created
|
||||
while ((!tmpFile.exists()) || lockfile.exists()) {
|
||||
Thread.sleep(500);
|
||||
if(abort){
|
||||
// If abort is issued while waiting for data immediately return without
|
||||
// trying to read the data
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
logger.fine("Read file " + tmpFile.getCanonicalPath());
|
||||
InputStreamReader inreader = tmpFile.getInputStream();
|
||||
BufferedReader in = new BufferedReader(inreader);
|
||||
String line;
|
||||
boolean firstline = true;
|
||||
while (true) {
|
||||
line = in.readLine();
|
||||
if (line == null) {
|
||||
break;
|
||||
} else {
|
||||
if(line.matches("^\\[.*")){
|
||||
// Skip header lines
|
||||
}
|
||||
else{
|
||||
if(firstline){
|
||||
firstline=false;
|
||||
continue;
|
||||
}
|
||||
|
||||
DataMessage message = new DataMessage(metadata);
|
||||
// Add data to dataset
|
||||
String[] tokens = line.split("\t");
|
||||
|
||||
for(Integer i: dataIndexes){
|
||||
try{
|
||||
if(i == timestampIndex) {
|
||||
// Calculate time in milliseconds
|
||||
Double seconds = new Double(tokens[i]);
|
||||
Double nanoseconds = new Double(tokens[i+1]);
|
||||
|
||||
Double v = seconds*1000+Math.floor(nanoseconds*0.000001);
|
||||
message.getData().add(v);
|
||||
}
|
||||
else {
|
||||
|
||||
message.getData().add(new Double(tokens[i]));
|
||||
}
|
||||
}
|
||||
catch(NumberFormatException e){
|
||||
logger.warning("Cannot parse component ["+tokens[i]+"] from source file - will add 0 for this component");
|
||||
message.getData().add(new Double(0));
|
||||
}
|
||||
}
|
||||
eventbus.post(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
in.close();
|
||||
inreader.close();
|
||||
} catch(InterruptedException e){
|
||||
throw new RuntimeException("An interrupt occured while waiting for the file to show up",e);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("An IO Exception occured while reading the OTF data file",e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public List<Sensor> getSensors() {
|
||||
return sensors;
|
||||
}
|
||||
public boolean isDataGroup() {
|
||||
return dataGroup;
|
||||
}
|
||||
public void setDataGroup(boolean dataGroup) {
|
||||
this.dataGroup = dataGroup;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ch.psi.fda.core.ActionLoop#getEventBus()
|
||||
*/
|
||||
@Override
|
||||
public EventBus getEventBus() {
|
||||
return eventbus;
|
||||
}
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful,
|
||||
* but without any warranty; without even the implied warranty of
|
||||
* merchantability or fitness for a particular purpose. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this code. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.psi.fda.core.loops.otf;
|
||||
|
||||
import ch.psi.fda.core.Sensor;
|
||||
|
||||
/**
|
||||
* Sensor to read out a named (Epics) channel. This sensor can only be used within the
|
||||
* OTFLoop. If it is used in other loops, the read value will always be 0.
|
||||
*/
|
||||
public class OTFNamedChannelSensor implements Sensor {
|
||||
|
||||
/**
|
||||
* Name of the channel
|
||||
*/
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* Global id of the sensor
|
||||
*/
|
||||
private final String id;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param id Global id of the sensor
|
||||
* @param name Name of the (Epics) channel
|
||||
*/
|
||||
public OTFNamedChannelSensor(String id, String name){
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object read() {
|
||||
// Always return 0 if read() method is called.
|
||||
return 0d;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the name of the channel
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful,
|
||||
* but without any warranty; without even the implied warranty of
|
||||
* merchantability or fitness for a particular purpose. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this code. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.psi.fda.core.loops.otf;
|
||||
|
||||
import ch.psi.fda.core.Sensor;
|
||||
|
||||
/**
|
||||
* Sensor to read out a scaler channel. This sensor can only be used within the
|
||||
* OTFLoop. If it is used in other loops, the read value will always be 0.
|
||||
*
|
||||
*/
|
||||
public class OTFScalerChannelSensor implements Sensor {
|
||||
|
||||
/**
|
||||
* Index of the scaler channel. The index starts at 0;
|
||||
*/
|
||||
private final int index;
|
||||
|
||||
/**
|
||||
* Global id of the sensor
|
||||
*/
|
||||
private final String id;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param id Global id of the sensor
|
||||
* @param index Index of the scaler channel. Index starts at 0.
|
||||
*/
|
||||
public OTFScalerChannelSensor(String id, int index){
|
||||
this.id = id;
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object read() {
|
||||
return 0d;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the index of the scaler channel
|
||||
*/
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
@@ -1,962 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful,
|
||||
* but without any warranty; without even the implied warranty of
|
||||
* merchantability or fitness for a particular purpose. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this code. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.psi.fda.core.loops.otf;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import ch.psi.jcae.annotation.CaChannel;
|
||||
import ch.psi.jcae.Channel;
|
||||
import ch.psi.jcae.ChannelException;
|
||||
|
||||
/**
|
||||
* Bean holding all OTF channels and functionality
|
||||
*/
|
||||
public class TemplateOTF {
|
||||
|
||||
public enum Status { SETUP, INACTIVE, INITIALIZE, ACTIVE, STOP, FAULT, ERROR };
|
||||
public enum Command { NONE, START, STOP };
|
||||
|
||||
private long timeoutMotorOk = 8000;
|
||||
private long commandTimeout = 20000; // Maximum time until a command should take effect
|
||||
|
||||
@CaChannel(type=String.class, name ="${PREFIX}:UMOT")
|
||||
private Channel<String> motor;
|
||||
|
||||
@CaChannel(type=String.class, name="${PREFIX}:MENC")
|
||||
private Channel<String> encoder;
|
||||
|
||||
@CaChannel(type=Double.class, name="${PREFIX}:UBEG")
|
||||
private Channel<Double> begin;
|
||||
|
||||
@CaChannel(type=Double.class, name="${PREFIX}:UBEG.DRVL")
|
||||
private Channel<Double> beginMin;
|
||||
|
||||
@CaChannel(type=Double.class, name="${PREFIX}:UBEG.DRVH")
|
||||
private Channel<Double> beginMax;
|
||||
|
||||
@CaChannel(type=Double.class, name="${PREFIX}:UEND")
|
||||
private Channel<Double> end;
|
||||
|
||||
@CaChannel(type=Double.class, name="${PREFIX}:UEND.DRVL")
|
||||
private Channel<Double> endMin;
|
||||
|
||||
@CaChannel(type=Double.class, name="${PREFIX}:UEND.DRVH")
|
||||
private Channel<Double> endMax;
|
||||
|
||||
@CaChannel(type=Double.class, name="${PREFIX}:USSIZ")
|
||||
private Channel<Double> stepSize;
|
||||
|
||||
@CaChannel(type=Double.class, name="${PREFIX}:USSIZ.DRVL")
|
||||
private Channel<Double> stepSizeMin;
|
||||
|
||||
@CaChannel(type=Double.class, name="${PREFIX}:UITIM")
|
||||
private Channel<Double> integrationTime;
|
||||
|
||||
@CaChannel(type=Double.class, name="${PREFIX}:UITIM.DRVL")
|
||||
private Channel<Double> integrationTimeMin;
|
||||
|
||||
@CaChannel(type=Double.class, name="${PREFIX}:UITIM.DRVH")
|
||||
private Channel<Double> integrationTimeMax;
|
||||
|
||||
@CaChannel(type=Double.class, name="${PREFIX}:UBCL")
|
||||
private Channel<Double> userBacklash;
|
||||
|
||||
@CaChannel(type=String.class, name="${PREFIX}:NFSSE")
|
||||
private Channel<String> nfsServer;
|
||||
|
||||
@CaChannel(type=String.class, name="${PREFIX}:NFSSH")
|
||||
private Channel<String> nfsShare;
|
||||
|
||||
@CaChannel(type=String.class, name="${PREFIX}:DFNAM")
|
||||
private Channel<String> fileName;
|
||||
|
||||
@CaChannel(type=String.class, name="${PREFIX}:FFORM")
|
||||
private Channel<String> fileNameFormat;
|
||||
|
||||
@CaChannel(type=Integer.class, name="${PREFIX}:FCNT")
|
||||
private Channel<Integer> fileCount;
|
||||
|
||||
@CaChannel(type=Integer.class, name="${PREFIX}:FCNT.B")
|
||||
private Channel<Integer> resetFileCounter;
|
||||
|
||||
@CaChannel(type=Boolean.class, name="${PREFIX}:FAPPE")
|
||||
private Channel<Boolean> appendFile;
|
||||
|
||||
@CaChannel(type=Boolean.class, name="${PREFIX}:FUSE")
|
||||
private Channel<Boolean> fileNameGeneration;
|
||||
|
||||
@CaChannel(type=Boolean.class, name="${PREFIX}:UZIGZ")
|
||||
private Channel<Boolean> zigZag;
|
||||
|
||||
@CaChannel(type=Integer.class, name="${PREFIX}:UCOM")
|
||||
private Channel<Integer> command;
|
||||
|
||||
@CaChannel(type=Boolean.class, name="${PREFIX}:SCRU", monitor=true)
|
||||
private Channel<Boolean> scanRunning;
|
||||
|
||||
@CaChannel(type=Boolean.class, name="${PREFIX}:MUENC")
|
||||
private Channel<Boolean> useEncoder;
|
||||
|
||||
@CaChannel(type=String.class, name={"${PREFIX}:CTM0","${PREFIX}:CTM1","${PREFIX}:CTM2","${PREFIX}:CTM3","${PREFIX}:CTM4","${PREFIX}:CTM5","${PREFIX}:CTM6","${PREFIX}:CTM7"})
|
||||
private List<Channel<String>> monitoredChannels;
|
||||
|
||||
@CaChannel(type=Boolean.class, name="${PREFIX}:OTF", monitor=true)
|
||||
private Channel<Boolean> running;
|
||||
|
||||
@CaChannel(type=Integer.class, name="${PREFIX}:USTAT", monitor=true)
|
||||
private Channel<Integer> status;
|
||||
|
||||
@CaChannel(type=Boolean.class, name="${PREFIX}:MOK", monitor=true)
|
||||
private Channel<Boolean> motorOk;
|
||||
|
||||
@CaChannel(type=Boolean.class, name="${PREFIX}:EOK", monitor=true)
|
||||
private Channel<Boolean> encoderOk;
|
||||
|
||||
@CaChannel(type=String.class, name="${PREFIX}:MSG")
|
||||
private Channel<String> message;
|
||||
|
||||
/**
|
||||
* Get the trigger name that can be used by the sscan record to trigger an OTFScan
|
||||
* @return Name of the trigger that can be used by sscan record
|
||||
*/
|
||||
public String getSScanTriggerName(){
|
||||
return(running.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Start OTF scan
|
||||
*/
|
||||
public void start() {
|
||||
try{
|
||||
if(getStatus().equals(Status.INACTIVE)){
|
||||
|
||||
// Send START command
|
||||
this.command.setValue(Command.START.ordinal());
|
||||
|
||||
// Wait until OtF logic is active
|
||||
this.scanRunning.waitForValue(true, commandTimeout);
|
||||
}
|
||||
else{
|
||||
throw new RuntimeException("Cannot start scan, status is not INACTIVE.\nThe current status is: "+getStatus()+" . The OTF logic need to be recovered manually [Message: "+getMessage()+"]");
|
||||
}
|
||||
}
|
||||
catch(Exception e){
|
||||
throw new RuntimeException("Unable to start OTF scan.",e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Abort scan
|
||||
*/
|
||||
public void abort() {
|
||||
try{
|
||||
// Send STOP command
|
||||
this.command.setValue(Command.STOP.ordinal());
|
||||
|
||||
// Do not wait for put to return
|
||||
this.running.setValueNoWait(false);
|
||||
}
|
||||
catch(Exception e){
|
||||
throw new RuntimeException("Unable to abort OTF logic" ,e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop OTF scan
|
||||
* @throws Exception
|
||||
*/
|
||||
public void stop() throws Exception{
|
||||
if(!getStatus().equals(Status.INACTIVE) || !getStatus().equals(Status.FAULT)){
|
||||
|
||||
// Send STOP command
|
||||
this.command.setValue(Command.STOP.ordinal());
|
||||
|
||||
// Wait until logic is stopped
|
||||
status.waitForValue(Status.INACTIVE.ordinal(), commandTimeout);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait until scan has stopped
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public void waitUntilStopped() throws InterruptedException {
|
||||
try {
|
||||
scanRunning.waitForValue(false); // Use of default wait timeout
|
||||
|
||||
// Check whether the status is INACTIVE otherwise get messge from OTF and throw an exception
|
||||
if(status.getValue() != Status.INACTIVE.ordinal()){
|
||||
throw new RuntimeException("OTFSCAN failed with message: "+message.getValue());
|
||||
}
|
||||
|
||||
} catch (ExecutionException | ChannelException | TimeoutException e) {
|
||||
throw new RuntimeException("An error occurred while waiting for the OTF logic to finish.", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait until scan has stopped
|
||||
* @param waitTimeout
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public void waitUntilStopped(Long waitTimeout) throws InterruptedException {
|
||||
try {
|
||||
scanRunning.waitForValue(false, waitTimeout);
|
||||
|
||||
// Check whether the status is INACTIVE otherwise get messge from OTF and throw an exception
|
||||
if(status.getValue() != Status.INACTIVE.ordinal()){
|
||||
throw new RuntimeException("OTFSCAN failed with message: "+message.getValue());
|
||||
}
|
||||
|
||||
} catch (ExecutionException | ChannelException | TimeoutException e) {
|
||||
throw new RuntimeException("An error occurred while waiting for the OTF logic to finish.", e);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset OTFScan records to defaults
|
||||
* @throws CAException
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public void resetToDefaults() throws InterruptedException{
|
||||
try{
|
||||
setMonitoredChannels(new String[]{});
|
||||
setMotor("");
|
||||
begin.setValue(0d);
|
||||
end.setValue(0d);
|
||||
stepSize.setValue(0d);
|
||||
integrationTime.setValue(0d);
|
||||
zigZag.setValue(false);
|
||||
setAppendFile(false);
|
||||
setFileNameGeneration(true);
|
||||
setFileName("");
|
||||
setFileNameFormat("%06d.txt");
|
||||
resetFileCounter();
|
||||
|
||||
setUserBacklash(0d);
|
||||
|
||||
// setNfsServer("");
|
||||
// setNfsShare("");
|
||||
|
||||
waitUntilMotorNotOk(timeoutMotorOk);
|
||||
}
|
||||
catch(ExecutionException | ChannelException e){
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get motor of the OTFScan axis
|
||||
* @return Name of the OTF motor
|
||||
* @throws CAException
|
||||
*/
|
||||
public String getMotor() throws InterruptedException {
|
||||
try {
|
||||
return(this.motor.getValue());
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set motor of the OTFScan axis
|
||||
* @param motor
|
||||
* @throws CAException
|
||||
*/
|
||||
public void setMotor(String motor) throws InterruptedException {
|
||||
try{
|
||||
this.motor.setValue(motor);
|
||||
} catch (ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get encoder of the OTFScan axis
|
||||
* @return Name of the used encoder
|
||||
* @throws CAException
|
||||
*/
|
||||
public String getEncoder() throws InterruptedException {
|
||||
try{
|
||||
return(this.encoder.getValue());
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set encoder to use of the OTFScan axis
|
||||
* @param encoder
|
||||
* @throws CAException
|
||||
*/
|
||||
public void setEncoder(String encoder) throws InterruptedException {
|
||||
try{
|
||||
this.encoder.setValue(encoder);
|
||||
} catch (ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get begin position of the scan
|
||||
* @return Begin position scan
|
||||
* @throws CAException
|
||||
*/
|
||||
public Double getBegin() throws InterruptedException {
|
||||
try{
|
||||
return(this.begin.getValue());
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set begin position of scan
|
||||
* @param begin
|
||||
* @throws Exception
|
||||
*/
|
||||
public void setBegin(Double begin) throws InterruptedException {
|
||||
try{
|
||||
if(begin==null){
|
||||
throw new IllegalArgumentException("Begin position must not be null");
|
||||
}
|
||||
|
||||
if(begin < beginMin.getValue() || begin > beginMax.getValue()){
|
||||
throw new IllegalArgumentException("Cannot set begin value to "+begin+ ". Value is outside range [min: "+beginMin.getValue()+" max: "+beginMax.getValue()+"]");
|
||||
}
|
||||
|
||||
this.begin.setValue(begin);
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get minimum value of the begin position
|
||||
* @return Min value for begin
|
||||
* @throws CAException
|
||||
*/
|
||||
public Double getMinBegin() throws InterruptedException {
|
||||
try{
|
||||
return(this.beginMin.getValue());
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get maximum value of the begin position
|
||||
* @return Max value for begin
|
||||
* @throws CAException
|
||||
*/
|
||||
public Double getMaxBegin() throws InterruptedException {
|
||||
try{
|
||||
return(this.beginMax.getValue());
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get end position of the scan
|
||||
* @return End position scan
|
||||
* @throws CAException
|
||||
*/
|
||||
public Double getEnd() throws InterruptedException {
|
||||
try{
|
||||
return(this.end.getValue());
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set end positon of scan
|
||||
* @param end
|
||||
* @throws CAException
|
||||
*/
|
||||
public void setEnd(Double end) throws InterruptedException {
|
||||
try{
|
||||
if(end==null){
|
||||
throw new IllegalArgumentException("End position must not be null");
|
||||
}
|
||||
|
||||
if(end < endMin.getValue() || end > endMax.getValue()){
|
||||
throw new IllegalArgumentException("Cannot set end value to "+end+ ". Value is outside range [min: "+endMin.getValue()+" max: "+endMax.getValue()+"]");
|
||||
}
|
||||
|
||||
this.end.setValue(end);
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get minimum value of end position
|
||||
* @return Min value for end
|
||||
* @throws CAException
|
||||
*/
|
||||
public Double getMinEnd() throws InterruptedException {
|
||||
try{
|
||||
return(this.endMin.getValue());
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Get maximum value of end position
|
||||
* @return Max value for end
|
||||
* @throws CAException
|
||||
*/
|
||||
public Double getMaxEnd() throws InterruptedException {
|
||||
try{
|
||||
return(this.endMax.getValue());
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get scan step size
|
||||
* @return Step size
|
||||
* @throws CAException
|
||||
*/
|
||||
public Double getStepSize() throws InterruptedException {
|
||||
try{
|
||||
return(this.stepSize.getValue());
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set step size of scan
|
||||
* @param stepSize
|
||||
* @throws CAException
|
||||
*/
|
||||
public void setStepSize(Double stepSize) throws InterruptedException {
|
||||
try{
|
||||
if(integrationTime==null){
|
||||
throw new IllegalArgumentException("Step size must not be null");
|
||||
}
|
||||
|
||||
// Check if step size is greater than min step size
|
||||
if(stepSizeMin.getValue() != 0 && stepSize < stepSizeMin.getValue()){
|
||||
throw new IllegalArgumentException("Step size value ["+stepSize+"] is less than minimum step size ["+stepSizeMin.getValue()+"]!");
|
||||
}
|
||||
|
||||
this.stepSize.setValue(stepSize);
|
||||
|
||||
// TODO WORKAROUND - Wait to "ensure" that step size related fields are updated (i.e. min/max integration time)
|
||||
Thread.sleep(1);
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get minimum integration time
|
||||
* @return Min value for step size
|
||||
* @throws CAException
|
||||
*/
|
||||
public double getMinStepSize() throws InterruptedException {
|
||||
try{
|
||||
return(this.stepSizeMin.getValue());
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get scan integration time (time that is spend in one step)
|
||||
* @return Integration time
|
||||
* @throws CAException
|
||||
*/
|
||||
public Double getIntegrationTime() throws InterruptedException {
|
||||
try{
|
||||
return(this.integrationTime.getValue());
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set integration time of scan
|
||||
* @param integrationTime
|
||||
* @throws CAException
|
||||
*/
|
||||
public void setIntegrationTime(Double integrationTime) throws InterruptedException {
|
||||
try{
|
||||
if(integrationTime==null){
|
||||
throw new IllegalArgumentException("Integration time must not be null");
|
||||
}
|
||||
|
||||
// Check range (if limit is set to 0 then limit is not set)
|
||||
double min = integrationTimeMin.getValue();
|
||||
double max = integrationTimeMax.getValue();
|
||||
if(min!= 0 && max!= 0){
|
||||
if(integrationTime < min || integrationTime > max){
|
||||
throw new IllegalArgumentException("Integration time ["+integrationTime+"] is outside range [min: "+min+" max: "+max+"]");
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(min!= 0 && integrationTime<min){
|
||||
throw new IllegalArgumentException("Integration time ["+integrationTime+"] is outside range [min: "+min+" max: - ]");
|
||||
}
|
||||
else if(max!= 0 && integrationTime>max){
|
||||
throw new IllegalArgumentException("Integration time ["+integrationTime+"] is outside range [min: - max: "+max+"]");
|
||||
}
|
||||
}
|
||||
|
||||
this.integrationTime.setValue(integrationTime);
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get minimum integration time
|
||||
* @return Min value for integration time
|
||||
* @throws CAException
|
||||
*/
|
||||
public Double getMinIntegrationTime() throws InterruptedException {
|
||||
try{
|
||||
return(this.integrationTimeMin.getValue());
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Get maximum integration time
|
||||
* @return Max value for integration time
|
||||
* @throws CAException
|
||||
*/
|
||||
public Double getMaxIntegrationTime() throws InterruptedException {
|
||||
try{
|
||||
return(this.integrationTimeMax.getValue());
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get additional user defined backlash
|
||||
* @return User backlash
|
||||
* @throws CAException
|
||||
*/
|
||||
public Double getUserBacklash() throws InterruptedException {
|
||||
try{
|
||||
return(this.userBacklash.getValue());
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set additional user defined backlash
|
||||
* @param userBacklash
|
||||
* @throws CAException
|
||||
*/
|
||||
public void setUserBacklash(Double userBacklash) throws InterruptedException {
|
||||
try{
|
||||
if(userBacklash==null){
|
||||
throw new IllegalArgumentException("User backlash must not be null");
|
||||
}
|
||||
|
||||
this.userBacklash.setValue(userBacklash);
|
||||
} catch (ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current NFS server the data is written to
|
||||
* @return Name of NFS server
|
||||
* @throws CAException
|
||||
*/
|
||||
public String getNfsServer() throws InterruptedException {
|
||||
try{
|
||||
return(this.nfsServer.getValue());
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set name of the NFS server the data is written to
|
||||
* @param nfsServer
|
||||
* @throws CAException
|
||||
*/
|
||||
public void setNfsServer(String nfsServer) throws InterruptedException {
|
||||
try{
|
||||
this.nfsServer.setValue(nfsServer);
|
||||
} catch (ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the NFS share the data is written to
|
||||
* @return Name of NFS share
|
||||
* @throws CAException
|
||||
*/
|
||||
public String getNfsShare() throws InterruptedException {
|
||||
try{
|
||||
return(this.nfsShare.getValue());
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set name of the NFS share the data is written to
|
||||
* @param nfsShare
|
||||
* @throws CAException
|
||||
*/
|
||||
public void setNfsShare(String nfsShare) throws InterruptedException {
|
||||
try{
|
||||
this.nfsShare.setValue(nfsShare);
|
||||
} catch (ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the data file
|
||||
* @return Name of data file name
|
||||
* @throws CAException
|
||||
*/
|
||||
public String getFileName() throws InterruptedException {
|
||||
try{
|
||||
return(this.fileName.getValue());
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set name of the data file
|
||||
* @param filename
|
||||
* @throws CAException
|
||||
*/
|
||||
public void setFileName(String filename) throws InterruptedException {
|
||||
try{
|
||||
this.fileName.setValue(filename);
|
||||
} catch (ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get File name formate
|
||||
* @return Get format for file name
|
||||
* @throws CAException
|
||||
*/
|
||||
public String getFileNameFormat() throws InterruptedException {
|
||||
try{
|
||||
return(this.fileNameFormat.getValue());
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set file name formate of the data file
|
||||
* @param fileNameFormat
|
||||
* @throws Exception
|
||||
*/
|
||||
public void setFileNameFormat(String fileNameFormat) throws InterruptedException {
|
||||
try{
|
||||
this.fileNameFormat.setValue(fileNameFormat);
|
||||
} catch (ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get value of the IOC based file name counter
|
||||
* @return File counter
|
||||
* @throws CAException
|
||||
*/
|
||||
public int getFileCounter() throws InterruptedException {
|
||||
try{
|
||||
return(this.fileCount.getValue());
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the IOC based file counter
|
||||
* @throws CAException
|
||||
*/
|
||||
public void resetFileCounter() throws InterruptedException {
|
||||
try{
|
||||
this.resetFileCounter.setValue(1);
|
||||
} catch (ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get if append file option is activated
|
||||
* @return Append file flag
|
||||
* @throws CAException
|
||||
*/
|
||||
public boolean isAppendFile() throws InterruptedException {
|
||||
try{
|
||||
return(this.appendFile.getValue());
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to append the specified file if the file exists
|
||||
* @param append
|
||||
* @throws CAException
|
||||
*/
|
||||
public void setAppendFile(boolean append) throws InterruptedException {
|
||||
try{
|
||||
this.appendFile.setValue(append);
|
||||
} catch (ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get if file name generation is on or off
|
||||
* @return File name generation flag
|
||||
* @throws CAException
|
||||
*/
|
||||
public boolean isFileNameGeneration() throws InterruptedException {
|
||||
try{
|
||||
return(this.fileNameGeneration.getValue());
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Whether the file name should be generated out of the file name format and the file counter
|
||||
* @param generation
|
||||
* @throws CAException
|
||||
*/
|
||||
public void setFileNameGeneration(boolean generation) throws InterruptedException {
|
||||
try{
|
||||
this.fileNameGeneration.setValue(generation);
|
||||
} catch (ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get if ZigZag scan option is on or off
|
||||
* @return ZigZag flag
|
||||
* @throws CAException
|
||||
*/
|
||||
public boolean isZigZag() throws InterruptedException {
|
||||
try{
|
||||
return(this.zigZag.getValue());
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set ZigZag scan mode on/off
|
||||
* @param zigZag ZigZag mode on = true, ZigZag mode off = false
|
||||
* @throws CAException
|
||||
*/
|
||||
public void setZigZag(boolean zigZag) throws InterruptedException {
|
||||
try{
|
||||
this.zigZag.setValue(zigZag);
|
||||
} catch (ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether encoder is used
|
||||
*/
|
||||
public boolean isUseEncoder() throws InterruptedException {
|
||||
try{
|
||||
return(this.useEncoder.getValue());
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set flag to use encoder
|
||||
* @throws CAException
|
||||
*/
|
||||
public void setUseEncoder(boolean flag) throws InterruptedException {
|
||||
try{
|
||||
this.useEncoder.setValue(flag);
|
||||
} catch (ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the channels that are currently monitored by the OTFScan logic
|
||||
* @return Names of the monitored channels
|
||||
* @throws CAException
|
||||
*/
|
||||
public String[] getMonitoredChannels() throws InterruptedException {
|
||||
try{
|
||||
String[] values = new String[this.monitoredChannels.size()];
|
||||
|
||||
for(int i=0; i<this.monitoredChannels.size();i++){
|
||||
values[i] = monitoredChannels.get(i).getValue();
|
||||
}
|
||||
|
||||
return(values);
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the channels that need to be monitored.
|
||||
* Note: As OTF only supports 8 channels to be monitored, only the first 8
|
||||
* values of the passed channelNames are considered.
|
||||
* @param values Array of channel names to be monitored
|
||||
* @throws CAException
|
||||
*/
|
||||
public void setMonitoredChannels(String[] values) throws InterruptedException {
|
||||
|
||||
try{
|
||||
if(values.length>monitoredChannels.size()){
|
||||
throw new IllegalArgumentException("Only up to "+monitoredChannels.size()+" monitored channels are supported by OTF");
|
||||
}
|
||||
|
||||
for(int i=0; i<this.monitoredChannels.size(); i++){
|
||||
if(values != null && i<values.length){
|
||||
this.monitoredChannels.get(i).setValue(values[i]);
|
||||
}
|
||||
else{
|
||||
this.monitoredChannels.get(i).setValue("");
|
||||
}
|
||||
}
|
||||
} catch (ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether an scan is running
|
||||
* @return Running flag
|
||||
* @throws CAException
|
||||
*/
|
||||
public boolean isRunning() throws InterruptedException {
|
||||
try{
|
||||
return(running.getValue());
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get status of the scan
|
||||
* @return Status of the scan
|
||||
* @throws CAException
|
||||
*/
|
||||
public Status getStatus() throws InterruptedException {
|
||||
try{
|
||||
return(Status.values()[this.status.getValue()]);
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the (error) message from the OTF records
|
||||
* @return Message from OTF C logic
|
||||
* @throws CAException
|
||||
*/
|
||||
public String getMessage() throws InterruptedException {
|
||||
try{
|
||||
return(message.getValue());
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the specified motor is recognized as ok (i.e. it is registered as OTFScan motor)
|
||||
* @return Flag whether motor is ok
|
||||
* @throws CAException
|
||||
*/
|
||||
public boolean isMotorOk() throws InterruptedException {
|
||||
try{
|
||||
return(motorOk.getValue());
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait until the motor flag goes to ok
|
||||
* @param timeout Timout in milliseconds
|
||||
*
|
||||
* @throws CAException If motor ok flag does not switch to ok within the specified timeout
|
||||
*/
|
||||
public void waitUntilMotorOk(long timeout) throws InterruptedException {
|
||||
try{
|
||||
motorOk.waitForValue(true, timeout);
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait until the motor flag goes to not ok
|
||||
* @param timeout Timout in milliseconds
|
||||
*
|
||||
* @throws CAException If motor ok flag does not switch to ok within the specified timeout
|
||||
*/
|
||||
public void waitUntilMotorNotOk(long timeout) throws InterruptedException {
|
||||
try{
|
||||
motorOk.waitForValue(false, timeout);
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void waitUntilEncoderOk(long timeout) throws InterruptedException {
|
||||
try{
|
||||
if(!useEncoder.getValue()){
|
||||
return;
|
||||
}
|
||||
encoderOk.waitForValue(true, timeout);
|
||||
} catch (TimeoutException | ChannelException | ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,142 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* Copyright 2012 Paul Scherrer Institute. All rights reserved.
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Foundation, either version 3 of the License, or (at your option) any
|
||||
* later version.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but without any
|
||||
* warranty; without even the implied warranty of merchantability or fitness for
|
||||
* a particular purpose. See the GNU Lesser General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this code. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package ch.psi.fda.core.loops;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import ch.psi.fda.core.TestConfiguration;
|
||||
import ch.psi.fda.core.loops.otf.DistributedFile;
|
||||
|
||||
public class DistributedFileTest {
|
||||
|
||||
|
||||
private static final Logger logger = Logger.getLogger(DistributedFileTest.class.getName());
|
||||
|
||||
DistributedFile file;
|
||||
DistributedFile smbfile;
|
||||
|
||||
/**
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
file = new DistributedFile("src/test/resources");
|
||||
smbfile = new DistributedFile(TestConfiguration.getInstance().getSmbShare());
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.loops.otf.DistributedFile#getCanonicalPath()}.
|
||||
* @throws IOException
|
||||
*/
|
||||
@Test
|
||||
public void testGetCanonicalPath() throws IOException {
|
||||
logger.info(file.getCanonicalPath());
|
||||
logger.info(smbfile.getCanonicalPath());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.loops.otf.DistributedFile#exists()}.
|
||||
* @throws IOException
|
||||
*/
|
||||
@Test
|
||||
public void testExists() throws IOException {
|
||||
if(!file.exists()){
|
||||
fail("Indicating wrong file status (file actually exists)");
|
||||
}
|
||||
if(!smbfile.exists()){
|
||||
fail("Indicating wrong file status (file actually exists)");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.loops.otf.DistributedFile#isDirectory()}.
|
||||
* @throws IOException
|
||||
*/
|
||||
@Test
|
||||
public void testIsDirectory() throws IOException {
|
||||
if(!file.isDirectory()){
|
||||
fail("Indicating wrong file type (file is directory)");
|
||||
}
|
||||
if(!smbfile.isDirectory()){
|
||||
fail("Indicating wrong file type (file is directory)");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.loops.otf.DistributedFile#listFiles()}.
|
||||
*/
|
||||
@Test
|
||||
public void testListFiles() {
|
||||
// fail("Not yet implemented");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.loops.otf.DistributedFile#getName()}.
|
||||
*/
|
||||
@Test
|
||||
public void testGetName() {
|
||||
logger.info(file.getName());
|
||||
logger.info(smbfile.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.loops.otf.DistributedFile#isFile()}.
|
||||
* @throws IOException
|
||||
*/
|
||||
@Test
|
||||
public void testIsFile() throws IOException {
|
||||
if(file.isFile()){
|
||||
fail("Indicating wrong file type (file is directory)");
|
||||
}
|
||||
if(smbfile.isFile()){
|
||||
fail("Indicating wrong file type (file is directory)");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.loops.otf.DistributedFile#delete()}.
|
||||
*/
|
||||
@Test
|
||||
public void testDelete() {
|
||||
// fail("Not yet implemented");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.loops.otf.DistributedFile#getInputStream()}.
|
||||
*/
|
||||
@Test
|
||||
public void testGetInputStream() {
|
||||
// fail("Not yet implemented");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,229 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful,
|
||||
* but without any warranty; without even the implied warranty of
|
||||
* merchantability or fitness for a particular purpose. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this code. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.psi.fda.core.loops;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
|
||||
import ch.psi.fda.core.TestConfiguration;
|
||||
import ch.psi.fda.core.loops.otf.OTFLoop;
|
||||
import ch.psi.fda.core.loops.otf.OTFNamedChannelSensor;
|
||||
import ch.psi.fda.core.loops.otf.OTFScalerChannelSensor;
|
||||
import ch.psi.fda.core.loops.otf.TemplateOTF;
|
||||
import ch.psi.fda.core.sensors.TimestampSensor;
|
||||
import ch.psi.fda.messages.ControlMessage;
|
||||
import ch.psi.fda.messages.DataMessage;
|
||||
import ch.psi.fda.messages.Message;
|
||||
import ch.psi.jcae.Channel;
|
||||
import ch.psi.jcae.ChannelDescriptor;
|
||||
import ch.psi.jcae.ChannelException;
|
||||
import ch.psi.jcae.ChannelService;
|
||||
import ch.psi.jcae.impl.DefaultChannelService;
|
||||
|
||||
public class OTFLoopTest {
|
||||
|
||||
private static Logger logger = Logger.getLogger(OTFLoopTest.class.getName());
|
||||
|
||||
private ChannelService cservice;
|
||||
|
||||
|
||||
|
||||
private static final TestConfiguration configuration = TestConfiguration.getInstance();
|
||||
|
||||
|
||||
private OTFLoop loopZigZag;
|
||||
private OTFLoop loop;
|
||||
private Channel<Integer> statusChannel;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
cservice = new DefaultChannelService();
|
||||
statusChannel = cservice.createChannel(new ChannelDescriptor<>(Integer.class, configuration.getOtfPrefix()+":USTAT"));
|
||||
|
||||
OTFScalerChannelSensor s2 = new OTFScalerChannelSensor("id1", 0);
|
||||
OTFScalerChannelSensor s3 = new OTFScalerChannelSensor("id2", 1);
|
||||
TimestampSensor s4 = new TimestampSensor("id3");
|
||||
OTFNamedChannelSensor s5 = new OTFNamedChannelSensor("id4", configuration.getAnalogIn1());
|
||||
|
||||
Map<String, String> macros = new HashMap<>();
|
||||
macros.put("PREFIX", configuration.getOtfPrefix());
|
||||
TemplateOTF template = new TemplateOTF();
|
||||
cservice.createAnnotatedChannels(template, macros);
|
||||
|
||||
|
||||
// ZigZag loop
|
||||
loopZigZag = new OTFLoop(template, configuration.getServer(), configuration.getShare(), configuration.getSmbShare(), true);
|
||||
loopZigZag.setActuator("id0", configuration.getMotor1(), null, 0, 8, 0.5, 0.5, 0);
|
||||
loopZigZag.getSensors().add(s2);
|
||||
loopZigZag.getSensors().add(s3);
|
||||
loopZigZag.getSensors().add(s4);
|
||||
loopZigZag.getSensors().add(s5);
|
||||
|
||||
|
||||
// Normal loop
|
||||
loop = new OTFLoop(template, configuration.getServer(), configuration.getShare(), configuration.getSmbShare(), false);
|
||||
loop.setActuator("id0", configuration.getMotor1(), null, 0, 8, 0.5, 0.5, 0);
|
||||
loop.getSensors().add(s2);
|
||||
loop.getSensors().add(s3);
|
||||
loop.getSensors().add(s4);
|
||||
loop.getSensors().add(s5);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
cservice.destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.loops.otf.OTFLoop#execute()}.
|
||||
* Test ordinary 1D OTF scan
|
||||
* @throws ExecutionException
|
||||
* @throws ChannelException
|
||||
* @throws TimeoutException
|
||||
* @throws CAException
|
||||
*/
|
||||
@Test
|
||||
public void testExecute() throws InterruptedException, TimeoutException, ChannelException, ExecutionException {
|
||||
|
||||
Object l = new Object(){
|
||||
boolean first = true;
|
||||
@Subscribe
|
||||
public void onMessage(DataMessage m) {
|
||||
if(first){
|
||||
first = false;
|
||||
|
||||
int numberOfSensors = 5;
|
||||
if(m.getMetadata().size() != numberOfSensors){
|
||||
fail("Loop returned wrong number of components inside the data message metadata");
|
||||
}
|
||||
|
||||
boolean fail = false;
|
||||
for(int x=0;x<numberOfSensors; x++){
|
||||
if(! m.getMetadata().get(x).getId().equals("id"+x)){
|
||||
fail = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(fail){
|
||||
fail("Ids of the component metadata elements inside the data message metadata is not correct");
|
||||
}
|
||||
}
|
||||
logger.info(m.toString());
|
||||
}
|
||||
};
|
||||
|
||||
loop.getEventBus().register(l);
|
||||
|
||||
loop.prepare();
|
||||
loop.execute();
|
||||
loop.cleanup();
|
||||
|
||||
if(statusChannel.getValue()!=1){
|
||||
fail("OTF C Logic status is not on INACTIVE");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.loops.otf.OTFLoop#execute()}.
|
||||
* Test OTF ZigZag mode
|
||||
* @throws ExecutionException
|
||||
* @throws ChannelException
|
||||
* @throws TimeoutException
|
||||
* @throws CAException
|
||||
*/
|
||||
@Test
|
||||
public void testExecuteZigZag() throws InterruptedException, TimeoutException, ChannelException, ExecutionException {
|
||||
|
||||
loopZigZag.getEventBus().register(new TestCollector());
|
||||
|
||||
loopZigZag.prepare();
|
||||
|
||||
loopZigZag.execute();
|
||||
loopZigZag.execute();
|
||||
|
||||
loopZigZag.cleanup();
|
||||
|
||||
if(statusChannel.getValue()!=1){
|
||||
fail("OTF C Logic status is not on INACTIVE");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link ch.psi.fda.core.loops.otf.OTFLoop#execute()}.
|
||||
* Test abort functionality while executing an OTF scan
|
||||
* @throws ExecutionException
|
||||
* @throws ChannelException
|
||||
* @throws TimeoutException
|
||||
* @throws CAException
|
||||
*/
|
||||
@Test
|
||||
public void testExecuteAbort() throws InterruptedException, TimeoutException, ChannelException, ExecutionException {
|
||||
|
||||
loop.getEventBus().register(new TestCollector());
|
||||
|
||||
// Thread to simulate asynchronous abort operation
|
||||
Thread t1 = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Thread.sleep(6000); // Wait some seconds before aborting the loop
|
||||
loop.abort();
|
||||
} catch (InterruptedException e) {
|
||||
logger.log(Level.SEVERE, "An Exception occured while testing the abort functionality", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
t1.start();
|
||||
|
||||
loop.prepare();
|
||||
|
||||
loop.execute();
|
||||
|
||||
loop.cleanup();
|
||||
|
||||
if(statusChannel.getValue()!=1){
|
||||
fail("OTF C Logic status is not on INACTIVE");
|
||||
}
|
||||
}
|
||||
|
||||
class TestCollector {
|
||||
@Subscribe
|
||||
public void onMessage(Message m) {
|
||||
if (m instanceof DataMessage) {
|
||||
DataMessage x = (DataMessage) m;
|
||||
logger.info(x.toString());
|
||||
} else if (m instanceof ControlMessage) {
|
||||
logger.info("---- " + m.toString() + " ----");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -95,15 +95,4 @@ public class CrlogicLoopStreamTest {
|
||||
cservice.destroy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReceive(){
|
||||
ChannelService cservice = new DefaultChannelService();
|
||||
CrlogicLoopStream crlogic = new CrlogicLoopStream(cservice, "X05LA-ES2-CRL", "localhost", false);
|
||||
crlogic.connect("localhost");
|
||||
|
||||
crlogic.receive();
|
||||
|
||||
crlogic.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ public class ParallelCrlogicTest {
|
||||
ScrlogicLoop scrlogic = new ScrlogicLoop(ids, sensors);
|
||||
|
||||
|
||||
CrlogicLoop crlogic = new CrlogicLoop(cservice, c.getCrlogicPrefix(), c.getServer(), c.getShare(), c.getSmbShare(), zigZag);
|
||||
CrlogicLoopStream crlogic = new CrlogicLoopStream(cservice, c.getCrlogicPrefix(), c.getServer(), zigZag);
|
||||
crlogic.setActuator("cmot", c.getMotor1(), readback, start, end, stepSize, integrationTime, additionalBacklash);
|
||||
crlogic.getSensors().add(new CrlogicResource("trigger", "TRIGGER0"));
|
||||
crlogic.getSensors().add(new CrlogicResource("scaler0", "SCALER0", true));
|
||||
|
||||
Reference in New Issue
Block a user