Files
x03da/plugins/Scienta.java
gac-x03da 99f1ed3e4f Startup
2021-09-21 09:52:05 +02:00

548 lines
19 KiB
Java

//package ch.psi.pshell.epics;
import ch.psi.pshell.epics.*;
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.Readable.ReadableCalibratedArray;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
/**
* Implementation of Scienta spectrometer analyser.
*/
public class Scienta extends AreaDetector {
final ChannelInteger slices, frames;
final ChannelDouble lowEnergy, centerEnergy, highEnergy, stepSize, stepTime, energyWidth;
final ChannelDoubleArray spectrum, image, extio;
final ChannelDouble currentChannel, totalPoints;
final ChannelDouble channelBegin, channelEnd, sliceBegin, sliceEnd;
final ChannelString lensMode, acquisitionMode, passEnergy;
final ChannelInteger numChannels, numSlices;
final ChannelDouble acquisitionTime;
final Stats[] stats;
final String channelCtrl, channelData;
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;
this.channelData = channelData;
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);
stepTime = new ChannelDouble(name + " step time", channelCtrl + ":STEP_TIME", 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);
channelBegin = new ChannelDouble(name + " channel begin", channelCtrl + ":CHANNEL_BEGIN_RBV", 3, false);
channelBegin.setAccessType(AccessType.Read);
channelEnd = new ChannelDouble(name + " channel end", channelCtrl + ":CHANNEL_END_RBV", 3, false);
channelEnd.setAccessType(AccessType.Read);
sliceBegin = new ChannelDouble(name + " slice begin", channelCtrl + ":SLICE_BEGIN_RBV", 3, false);
sliceBegin.setAccessType(AccessType.Read);
sliceEnd = new ChannelDouble(name + " slice end", channelCtrl + ":SLICE_END_RBV", 3, false);
sliceEnd.setAccessType(AccessType.Read);
numChannels = new ChannelInteger(name + " num channels", channelCtrl + ":NUM_CHANNELS_RBV", false);
numChannels.setAccessType(AccessType.Read);
numSlices = new ChannelInteger(name + " num slices", channelCtrl + ":SLICES_RBV", false);
numSlices.setAccessType(AccessType.Read);
numChannels.addListener(new DeviceAdapter() {
@Override
public void onValueChanged(Device device, Object value, Object former) {
try {
if (value != null) {
spectrum.setSize((Integer) value);
}
} catch (IOException ex) {
getLogger().log(Level.WARNING, null, ex);
}
}
});
acquisitionTime = new ChannelDouble(name + " acquire time", channelCtrl + ":TOTAL_ACQ_TIME_RBV", 3, false);
acquisitionTime.setAccessType(AccessType.Read);
/*
spectrum = new ChannelDoubleArray(name + " spectrum", channelCtrl + ":INT_SPECTRUM", 8, 200, false) {
@Override
protected double[] doRead() throws IOException, InterruptedException {
numChannels.getValue();
return super.doRead();
}
};
spectrum.setAccessType(AccessType.Read);
*/
spectrum = new ScientaSpectrum();
image = new ChannelDoubleArray(name + " image", channelCtrl + ":IMAGE", 8, EpicsRegister.SIZE_MAX, false);
image.setAccessType(AccessType.Read);
extio = new ChannelDoubleArray(name + " extio", channelCtrl + ":EXTIO", 8, EpicsRegister.SIZE_MAX, false);
extio.setAccessType(AccessType.Read);
currentChannel = new ChannelDouble(name + " current channel", channelCtrl + ":CURRENT_CHANNEL_RBV", 0, false);
currentChannel.setAccessType(AccessType.Read);
totalPoints = new ChannelDouble(name + " total points", channelCtrl + ":TOTAL_POINTS_RBV", 0, false);
totalPoints.setAccessType(AccessType.Read);
addChildren(new Device[]{slices, frames,
lowEnergy, centerEnergy, highEnergy, stepSize, stepTime, energyWidth,
spectrum, image, extio,
currentChannel, totalPoints,
channelBegin, channelEnd, sliceBegin, sliceEnd,
passEnergy, lensMode, acquisitionMode,
numChannels, numSlices, acquisitionTime
});
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);
}
public class ScientaSpectrum extends ChannelDoubleArray implements ReadableCalibratedArray<double[]> {
ScientaSpectrum() {
super(Scienta.this.getName() + " spectrum", channelCtrl + ":INT_SPECTRUM", 8, 200, false);
setAccessType(AccessType.Read);
}
@Override
protected double[] doRead() throws IOException, InterruptedException {
numChannels.getValue();
return super.doRead();
}
@Override
public ArrayCalibration getCalibration() {
double scale = 1.0;
double offset = 0.0;
try {
List<Double> channelRange = getChannelRange();
Double cb = channelRange.get(0);
Double ce = channelRange.get(1);
scale = (ce - cb) / Math.max(numChannels.getValue() - 1, 1);
offset = cb;
} catch (Exception ex) {
}
return new ArrayCalibration(scale, offset);
}
}
@Override
protected void doSetSimulated() {
super.doSetSimulated();
setCache(channelBegin, 50.0);
setCache(channelEnd, 150.0);
setCache(sliceBegin, -20.0);
setCache(sliceEnd, 20.0);
setCache(numChannels, 100);
setCache(numSlices, 10);
setCache(spectrum, new double[100]);
setCache(currentChannel, 0.0);
setCache(totalPoints, 100.0);
setCache(passEnergy, String.valueOf(PASS_ENERGY_VALUES[0]));
setCache(lensMode, LensMode.Angular45.toString());
setCache(acquisitionMode, AcquisitionMode.Fixed.toString());
setCache(acquisitionTime, 10.0);
setSimulatedValue("ENERGY_MODE", EnergyMode.Binding.toString());
setSimulatedValue("DETECTOR_MODE", DetectorMode.Pulse_Counting.toString());
setSimulatedValue("ELEMENT_SET", ElementSet.High_Pass.toString());
//setSimulatedValue("ACQ_MODE", AcquisitionMode.Fixed.toString());
//setSimulatedValue("LENS_MODE", LensMode.Angular45.toString());
//setSimulatedValue("PASS_ENERGY", String.valueOf(PASS_ENERGY_VALUES[0]));
}
@Override
protected void doUpdate() throws IOException, InterruptedException {
super.doUpdate();
numChannels.update();
currentChannel.update();
slices.update();
lowEnergy.update();
centerEnergy.update();
highEnergy.update();
energyWidth.update();
stepSize.update();
stepTime.update();
totalPoints.update();
passEnergy.update();
lensMode.update();
acquisitionMode.update();
acquisitionTime.update();
//channelBegin.update();
//channelEnd.update();
///sliceBegin.update();
//sliceEnd.update();
}
@Override
protected void doSetMonitored(boolean value) {
super.doSetMonitored(value);
numChannels.setMonitored(value);
currentChannel.setMonitored(value);
slices.setMonitored(value);
lowEnergy.setMonitored(value);
centerEnergy.setMonitored(value);
highEnergy.setMonitored(value);
energyWidth.setMonitored(value);
stepSize.setMonitored(value);
stepTime.setMonitored(value);
totalPoints.setMonitored(value);
passEnergy.setMonitored(value);
lensMode.setMonitored(value);
acquisitionMode.setMonitored(value);
acquisitionTime.setMonitored(value);
//channelBegin.setMonitored(value);
//channelEnd.setMonitored(value);
//sliceBegin.setMonitored(value);
//sliceEnd.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 {
Swept,
Fixed
}
public void setAcquisitionMode(AcquisitionMode mode) throws IOException, InterruptedException {
//writeCtrlEnum("ACQ_MODE", String.valueOf(mode));
acquisitionMode.write(String.valueOf(mode));
}
public AcquisitionMode getAcquisitionMode() throws IOException, InterruptedException {
//return (AcquisitionMode) readCtrlEnum("ACQ_MODE", AcquisitionMode.class);
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 {
Transmission,
Angular45,
Angular60
}
public void setLensMode(LensMode mode) throws IOException, InterruptedException {
//writeCtrlEnum("LENS_MODE", String.valueOf(mode));
lensMode.write(String.valueOf(mode));
}
public LensMode getLensMode() throws IOException, InterruptedException {
//return (LensMode) readCtrlEnum("LENS_MODE", LensMode.class);
String val = lensMode.getValue();
return (LensMode) convertCtrlEnum(val, LensMode.class);
}
public enum DetectorMode {
Pulse_Counting,
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 {
Low_Pass,
High_Pass
}
public void setElementSet(ElementSet mode) throws IOException, InterruptedException {
writeCtrlEnum("ELEMENT_SET", String.valueOf(mode));
}
public ElementSet getElementSet() throws IOException, InterruptedException {
return (ElementSet) readCtrlEnum("ELEMENT_SET", ElementSet.class);
}
public static final int[] PASS_ENERGY_VALUES = new int[]{2, 5, 10, 20, 50, 100, 200};
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 = currentChannel.take();
Double total = totalPoints.take();
if ((cur == null) || (total == null) || (total == 0)) {
return 0.0;
}
return cur / total;
}
public double[] getSpectrumX() throws IOException, InterruptedException {
List<Double> range = getChannelRange();
Double begin = range.get(0);
Double end = range.get(1);
double[] spectrum = getSpectrum().take();
if ((begin == null) || (end == null) || (spectrum == null)) {
return null;
}
int spectrumSize = spectrum.length;
double step = (end - begin) / (spectrumSize - 1);
double[] x = new double[spectrumSize];
for (int i = 0; i < spectrumSize; i++) {
x[i] = begin + step * i;
}
return x;
}
//Direct register access
public ChannelInteger getSlices() {
return slices;
}
public ChannelInteger getFrames() {
return frames;
}
public ChannelDouble getLowEnergy() {
return lowEnergy;
}
public ChannelDouble getCenterEnergy() {
return centerEnergy;
}
public ChannelDouble getHighEnergy() {
return highEnergy;
}
public ChannelDouble getStepSize() {
return stepSize;
}
public ChannelDouble getStepTime() {
return stepTime;
}
public ChannelDouble getEnergyWidth() {
return energyWidth;
}
public ChannelDoubleArray getSpectrum() {
return spectrum;
}
public ChannelDoubleArray getImage() {
return image;
}
public ChannelDoubleArray getExtio() {
return extio;
}
public ChannelDouble getChannelBegin() {
return channelBegin;
}
public ChannelDouble getChannelEnd() {
return channelEnd;
}
public ChannelDouble getSliceBegin() {
return sliceBegin;
}
public ChannelDouble getSliceEnd() {
return sliceEnd;
}
public ChannelDouble getAcquisitionTime() {
return acquisitionTime;
}
public List<Double> getChannelRange() throws IOException, InterruptedException {
ArrayList<Double> ret = new ArrayList<>();
//ret.add(getChannelBegin().getValue());
//ret.add(getChannelEnd().getValue());
switch (getAcquisitionMode()) {
case Swept:
ret.add(lowEnergy.getValue());
ret.add(highEnergy.getValue());
break;
case Fixed:
default:
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;
}
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()) {
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 getNumChannels() {
return numChannels;
}
public ChannelInteger getNumSlices() {
return numSlices;
}
public ChannelDouble getTotalChannels() {
return totalPoints;
}
public ChannelDouble getCurrentChannel() {
return currentChannel;
}
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();
}
}
}