Initial commit
This commit is contained in:
411
src/Scienta.java
Normal file
411
src/Scienta.java
Normal file
@@ -0,0 +1,411 @@
|
||||
|
||||
import ch.psi.jcae.ChannelException;
|
||||
import ch.psi.pshell.device.AccessType;
|
||||
import ch.psi.pshell.device.ArrayCalibration;
|
||||
import ch.psi.pshell.device.CameraImageDescriptor;
|
||||
import ch.psi.pshell.device.MatrixCalibration;
|
||||
import ch.psi.pshell.device.Device;
|
||||
import ch.psi.pshell.device.DeviceAdapter;
|
||||
import ch.psi.pshell.device.DeviceListener;
|
||||
import ch.psi.pshell.device.Readable.ReadableCalibratedArray;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import ch.psi.pshell.epics.*;
|
||||
import ch.psi.utils.State;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Implementation of Scienta spectrometer analyser.
|
||||
*/
|
||||
public class Scienta extends AreaDetector {
|
||||
final ChannelInteger acquire;
|
||||
final ChannelInteger slices;
|
||||
final ChannelDouble lowEnergy, centerEnergy, highEnergy, stepSize, energyWidth;
|
||||
final GenericArray data;
|
||||
final ChannelInteger totalSteps, currentStep;
|
||||
final ChannelString lensMode, acquisitionMode, passEnergy;
|
||||
final ChannelInteger numSlices;
|
||||
final Stats[] stats;
|
||||
final String channelCtrl;
|
||||
|
||||
public Scienta(final String name, final String channelPrefix) {
|
||||
this(name, channelPrefix + ":cam1", channelPrefix + ":image1");
|
||||
}
|
||||
|
||||
public Scienta(String name, String channelCtrl, String channelData) {
|
||||
super(name, channelCtrl, channelData);
|
||||
this.channelCtrl = channelCtrl;
|
||||
|
||||
acquire = new ChannelInteger(name + " aquire", channelCtrl + ":Acquire", false);
|
||||
|
||||
slices = new ChannelInteger(name + " slices", channelCtrl + ":SLICES", false);
|
||||
//frames = new ChannelInteger(name + " frames", channelCtrl + ":FRAMES", false);
|
||||
|
||||
lowEnergy = new ChannelDouble(name + " low energy", channelCtrl + ":LOW_ENERGY", 3, false);
|
||||
centerEnergy = new ChannelDouble(name + " center energy", channelCtrl + ":CENTRE_ENERGY", 3, false);
|
||||
highEnergy = new ChannelDouble(name + " high energy", channelCtrl + ":HIGH_ENERGY", 3, false);
|
||||
stepSize = new ChannelDouble(name + " step size", channelCtrl + ":STEP_SIZE", 3, false);
|
||||
|
||||
energyWidth = new ChannelDouble(name + " energy width", channelCtrl + ":ENERGY_WIDTH_RBV", 3, false);
|
||||
energyWidth.setAccessType(AccessType.Read);
|
||||
passEnergy = new ChannelString(name + " pass energy", channelCtrl + ":PASS_ENERGY", false);
|
||||
lensMode = new ChannelString(name + " lens mode", channelCtrl + ":LENS_MODE", false);
|
||||
acquisitionMode = new ChannelString(name + " lens mode", channelCtrl + ":ACQ_MODE", false);
|
||||
numSlices = new ChannelInteger(name + " num slices", channelCtrl + ":SLICES_RBV", false);
|
||||
|
||||
numSlices.setAccessType(AccessType.Read);
|
||||
|
||||
data = new GenericArray(name + " data", channelData + ":ArrayData", SIZE_MAX, false); //If nullable on invalidd value, read blocks on Scienta.
|
||||
data.setAutoResolveType(false);
|
||||
|
||||
totalSteps = new ChannelInteger(name + " total steps", channelCtrl + ":STEPS_RBV", false);
|
||||
totalSteps.setAccessType(AccessType.Read);
|
||||
currentStep = new ChannelInteger(name + " current step", channelCtrl + ":STEPS_COUNTER_RBV", false);
|
||||
currentStep.setAccessType(AccessType.Read);
|
||||
|
||||
|
||||
|
||||
|
||||
addChildren(new Device[]{acquire, slices,
|
||||
lowEnergy, centerEnergy, highEnergy, stepSize, energyWidth,
|
||||
data,
|
||||
totalSteps, currentStep,
|
||||
passEnergy, lensMode, acquisitionMode,
|
||||
numSlices
|
||||
});
|
||||
|
||||
stats = new Stats[5];
|
||||
stats[0] = new Stats("CountsR1", 1);
|
||||
stats[1] = new Stats("CountsR2", 2);
|
||||
stats[2] = new Stats("CountsR3", 3);
|
||||
stats[3] = new Stats("CountsR4", 4);
|
||||
stats[4] = new Stats("Counts", 5);
|
||||
addChildren(stats);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStart() throws IOException, InterruptedException {
|
||||
|
||||
acquire.write(1);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void doUpdate() throws IOException, InterruptedException {
|
||||
super.doUpdate();
|
||||
acquire.update();
|
||||
slices.update();
|
||||
lowEnergy.update();
|
||||
centerEnergy.update();
|
||||
highEnergy.update();
|
||||
energyWidth.update();
|
||||
stepSize.update();
|
||||
totalSteps.update();
|
||||
currentStep.update();
|
||||
passEnergy.update();
|
||||
lensMode.update();
|
||||
acquisitionMode.update();
|
||||
//channelBegin.update();
|
||||
//channelEnd.update();
|
||||
///sliceBegin.update();
|
||||
//sliceEnd.update();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doSetMonitored(boolean value) {
|
||||
super.doSetMonitored(value);
|
||||
acquire.setMonitored(value);
|
||||
slices.setMonitored(value);
|
||||
lowEnergy.setMonitored(value);
|
||||
centerEnergy.setMonitored(value);
|
||||
highEnergy.setMonitored(value);
|
||||
energyWidth.setMonitored(value);
|
||||
stepSize.setMonitored(value);
|
||||
totalSteps.setMonitored(value);
|
||||
currentStep.setMonitored(value);
|
||||
passEnergy.setMonitored(value);
|
||||
lensMode.setMonitored(value);
|
||||
acquisitionMode.setMonitored(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CameraImageDescriptor doReadImageDescriptor() throws IOException, InterruptedException {
|
||||
CameraImageDescriptor ret = super.doReadImageDescriptor();
|
||||
List<Double> channelRange = getChannelRange();
|
||||
List<Double> sliceRange = getSliceRange();
|
||||
|
||||
Double cb = channelRange.get(0);
|
||||
Double ce = channelRange.get(1);
|
||||
Double sb = sliceRange.get(0);
|
||||
Double se = sliceRange.get(1);
|
||||
|
||||
if ((cb == null) || (ce == null) || (sb == null) || (se == null) || (ret.width == 0) || (ret.height == 0)) {
|
||||
ret.calibration = null;
|
||||
} else {
|
||||
double scaleX = (ce - cb) / Math.max(ret.width - 1, 1);
|
||||
double offsetX = cb;
|
||||
double scaleY = (se - sb) / Math.max(ret.height - 1, 1);
|
||||
double offsetY = sb;
|
||||
|
||||
ret.calibration = new MatrixCalibration(scaleX, scaleY, offsetX, offsetY);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
//Modes
|
||||
public enum AcquisitionMode {
|
||||
Fixed,
|
||||
Swept_Energy,
|
||||
Swept_ThetaY,
|
||||
Swept_Energy_ThetaY
|
||||
}
|
||||
|
||||
public void setAcquisitionMode(AcquisitionMode mode) throws IOException, InterruptedException {
|
||||
acquisitionMode.write(String.valueOf(mode).replaceAll("_", " "));
|
||||
}
|
||||
|
||||
public AcquisitionMode getAcquisitionMode() throws IOException, InterruptedException {
|
||||
String val = acquisitionMode.getValue();
|
||||
return (AcquisitionMode) convertCtrlEnum(val, AcquisitionMode.class);
|
||||
}
|
||||
|
||||
public enum EnergyMode {
|
||||
|
||||
Binding,
|
||||
Kinetic
|
||||
}
|
||||
|
||||
public void setEnergyMode(EnergyMode mode) throws IOException, InterruptedException {
|
||||
writeCtrlEnum("ENERGY_MODE", String.valueOf(mode));
|
||||
}
|
||||
|
||||
public EnergyMode getEnergyMode() throws IOException, InterruptedException {
|
||||
return (EnergyMode) readCtrlEnum("ENERGY_MODE", EnergyMode.class);
|
||||
}
|
||||
|
||||
public enum LensMode {
|
||||
A14_01,
|
||||
A14_08,
|
||||
A30_01,
|
||||
A30_08,
|
||||
A7_08,
|
||||
DA14_01,
|
||||
DA14_08,
|
||||
DA30_01,
|
||||
DA30_08,
|
||||
DA7_08,
|
||||
Transmission,
|
||||
Transmission_XPS
|
||||
|
||||
}
|
||||
|
||||
public void setLensMode(LensMode mode) throws IOException, InterruptedException {
|
||||
//writeCtrlEnum("LENS_MODE", String.valueOf(mode));
|
||||
lensMode.write(mode.equals(LensMode.Transmission_XPS) ? "Transmission XPS" : String.valueOf(mode));
|
||||
}
|
||||
|
||||
public LensMode getLensMode() throws IOException, InterruptedException {
|
||||
//return (LensMode) readCtrlEnum("LENS_MODE", LensMode.class);
|
||||
String val = lensMode.getValue();
|
||||
return convertCtrlEnum(val, LensMode.class);
|
||||
}
|
||||
|
||||
public enum DetectorMode {
|
||||
Pulse,
|
||||
ADC
|
||||
}
|
||||
|
||||
public void setDetectorMode(DetectorMode mode) throws IOException, InterruptedException {
|
||||
writeCtrlEnum("DETECTOR_MODE", String.valueOf(mode));
|
||||
}
|
||||
|
||||
public DetectorMode getDetectorMode() throws IOException, InterruptedException {
|
||||
return (DetectorMode) readCtrlEnum("DETECTOR_MODE", DetectorMode.class);
|
||||
}
|
||||
|
||||
public enum ElementSet {
|
||||
High_Pass_XPS,
|
||||
Low_Pass_UPS
|
||||
}
|
||||
|
||||
public void setElementSet(ElementSet mode) throws IOException, InterruptedException {
|
||||
throw new IOException("Read-only value");
|
||||
//writeCtrlEnum("ELEMENT_SET", String.valueOf(mode));
|
||||
}
|
||||
|
||||
public ElementSet getElementSet() throws IOException, InterruptedException {
|
||||
return readCtrl("ELEMENT_SET_RBV", String.class).equals("High Pass (XPS)") ? ElementSet.High_Pass_XPS : ElementSet.Low_Pass_UPS;
|
||||
}
|
||||
|
||||
public static final int[] PASS_ENERGY_VALUES = new int[]{1, 2, 5, 10, 20};
|
||||
|
||||
public void setPassEnergy(int energy) throws IOException, InterruptedException {
|
||||
//writeCtrl("PASS_ENERGY", String.valueOf(energy));
|
||||
passEnergy.write(String.valueOf(energy));
|
||||
|
||||
}
|
||||
|
||||
public int getPassEnergy() throws IOException, InterruptedException {
|
||||
//String ret = (String) readCtrl("PASS_ENERGY", String.class);
|
||||
String ret = passEnergy.getValue();
|
||||
try {
|
||||
return Integer.valueOf(ret);
|
||||
} catch (Exception ex) {
|
||||
throw new DeviceInvalidParameterException("Pass Energy", ret);
|
||||
}
|
||||
}
|
||||
|
||||
public void zeroSupplies() throws IOException, InterruptedException {
|
||||
writeCtrl("ZERO_SUPPLIES", 1);
|
||||
}
|
||||
|
||||
//Progress
|
||||
//Disconnected operations
|
||||
public double getProgress() {
|
||||
Double cur = currentStep.take().doubleValue();
|
||||
Double total = totalSteps.take().doubleValue();
|
||||
if ((cur == null) || (total == null) || (total == 0)) {
|
||||
return 0.0;
|
||||
}
|
||||
return cur / total;
|
||||
}
|
||||
|
||||
|
||||
//Direct register access
|
||||
public ChannelInteger getAcquire() {
|
||||
return acquire;
|
||||
}
|
||||
|
||||
public ChannelInteger getSlices() {
|
||||
return slices;
|
||||
}
|
||||
|
||||
public ChannelDouble getLowEnergy() {
|
||||
return lowEnergy;
|
||||
}
|
||||
|
||||
public ChannelDouble getCenterEnergy() {
|
||||
return centerEnergy;
|
||||
}
|
||||
|
||||
public ChannelDouble getHighEnergy() {
|
||||
return highEnergy;
|
||||
}
|
||||
|
||||
public ChannelDouble getStepSize() {
|
||||
return stepSize;
|
||||
}
|
||||
|
||||
public ChannelDouble getEnergyWidth() {
|
||||
return energyWidth;
|
||||
}
|
||||
|
||||
public List<Double> getChannelRange() throws IOException, InterruptedException {
|
||||
ArrayList<Double> ret = new ArrayList<>();
|
||||
switch (getAcquisitionMode()) {
|
||||
case Fixed:
|
||||
double eCenter = centerEnergy.getValue();
|
||||
int ePass = getPassEnergy();
|
||||
double xe = 0.04464;
|
||||
double xn = 0.04464;
|
||||
ret.add(eCenter - xe * ePass);
|
||||
ret.add(eCenter + xn * ePass);
|
||||
break;
|
||||
default:
|
||||
ret.add(lowEnergy.getValue());
|
||||
ret.add(highEnergy.getValue());
|
||||
break;
|
||||
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public List<Double> getSliceRange() throws IOException, InterruptedException {
|
||||
ArrayList<Double> ret = new ArrayList<>();
|
||||
//ret.add(sliceBegin.getValue());
|
||||
//ret.add(sliceEnd.getValue());
|
||||
try {
|
||||
switch (getLensMode()) {
|
||||
//TODO:
|
||||
/*
|
||||
case Angular45:
|
||||
ret.add(-28.148);
|
||||
ret.add(27.649);
|
||||
break;
|
||||
case Angular60:
|
||||
ret.add(-34.736);
|
||||
ret.add(34.119);
|
||||
break;
|
||||
*/
|
||||
case Transmission:
|
||||
default:
|
||||
ret.add(-2.332);
|
||||
ret.add(2.291);
|
||||
break;
|
||||
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
ret.add(Double.NaN);
|
||||
ret.add(Double.NaN);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public ChannelInteger getNumSlices() {
|
||||
return numSlices;
|
||||
}
|
||||
|
||||
public ChannelInteger getTotalSteps() {
|
||||
return totalSteps;
|
||||
}
|
||||
|
||||
public ChannelInteger getCurrentStep() {
|
||||
return currentStep;
|
||||
}
|
||||
|
||||
public Stats[] getStats() {
|
||||
return stats;
|
||||
}
|
||||
|
||||
public class Stats extends ChannelDouble {
|
||||
|
||||
final int index;
|
||||
final ChannelInteger uid;
|
||||
|
||||
Stats(String name, int index) {
|
||||
super(name, channelCtrl.split(":")[0] + ":Stats" + index + ":Total_RBV", 3, false);
|
||||
this.index = index;
|
||||
uid = new ChannelInteger(name + " uid", channelCtrl.split(":")[0] + ":Stats" + index + ":UniqueId_RBV", false);
|
||||
//setParent(Scienta.this);
|
||||
addChild(uid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReady() throws IOException, InterruptedException {
|
||||
Integer imageCounter = getImageCounter().getValue();
|
||||
if (imageCounter == null) {
|
||||
return false;
|
||||
}
|
||||
Integer id = uid.take();
|
||||
if ((id == null) || (!imageCounter.equals(id))) {
|
||||
uid.update();
|
||||
}
|
||||
return imageCounter.equals(uid.take());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double read() throws IOException, InterruptedException {
|
||||
assertInitialized();
|
||||
waitReady(10000);
|
||||
return super.read();
|
||||
}
|
||||
|
||||
public int getUID() throws IOException, InterruptedException {
|
||||
return uid.getValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user