removed legacy code for continuous scans

This commit is contained in:
2015-08-17 16:12:05 +02:00
parent 49ad7c61e1
commit b2a67e06fb
15 changed files with 90 additions and 3116 deletions
+1 -6
View File
@@ -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));