This commit is contained in:
Alexander Nozik 2017-05-25 17:50:19 +03:00
parent 10f9753556
commit b06b2bc746
6 changed files with 108 additions and 251 deletions

View File

@ -16,9 +16,9 @@
package inr.numass.control.msp;
import hep.dataforge.context.Context;
import hep.dataforge.control.NamedValueListener;
import hep.dataforge.control.RoleDef;
import hep.dataforge.control.collectors.RegularPointCollector;
import hep.dataforge.control.collectors.ValueCollector;
import hep.dataforge.control.connections.Roles;
import hep.dataforge.control.connections.StorageConnection;
import hep.dataforge.control.devices.Device;
@ -26,9 +26,9 @@ import hep.dataforge.control.devices.PortSensor;
import hep.dataforge.control.devices.SingleMeasurementDevice;
import hep.dataforge.control.devices.StateDef;
import hep.dataforge.control.measurements.AbstractMeasurement;
import hep.dataforge.control.measurements.Measurement;
import hep.dataforge.control.ports.PortHandler;
import hep.dataforge.control.ports.TcpPortHandler;
import hep.dataforge.events.EventBuilder;
import hep.dataforge.exceptions.ControlException;
import hep.dataforge.exceptions.MeasurementException;
import hep.dataforge.exceptions.PortException;
@ -47,7 +47,6 @@ import inr.numass.control.StorageHelper;
import java.time.Duration;
import java.time.Instant;
import java.util.*;
import java.util.function.Consumer;
/**
* @author Alexander Nozik
@ -58,15 +57,12 @@ import java.util.function.Consumer;
@StateDef(name = "storing", writable = true, info = "Define if this device is currently writes to storage")
@StateDef(name = "filamentOn", writable = true, info = "Mass-spectrometer filament on")
@StateDef(name = "filamentStatus", info = "Filament status")
public class MspDevice extends SingleMeasurementDevice implements PortHandler.PortController {
public class MspDevice extends SingleMeasurementDevice<MspDevice.PeakJumpMeasurement> implements PortHandler.PortController {
public static final String MSP_DEVICE_TYPE = "msp";
private static final int TIMEOUT = 200;
private TcpPortHandler handler;
//listener
private MspListener mspListener;
private Consumer<MspResponse> responseDelegate;
public MspDevice() {
}
@ -91,13 +87,13 @@ public class MspDevice extends SingleMeasurementDevice implements PortHandler.Po
@Override
public void shutdown() throws ControlException {
super.shutdown();
super.stopMeasurement(true);
if (isConnected()) {
setFilamentOn(false);
setConnected(false);
}
getHandler().close();
super.shutdown();
}
@Override
@ -106,7 +102,7 @@ public class MspDevice extends SingleMeasurementDevice implements PortHandler.Po
}
@Override
protected Measurement createMeasurement(Meta meta) throws ControlException {
protected PeakJumpMeasurement createMeasurement(Meta meta) throws ControlException {
switch (meta.getString("type", "peakJump")) {
case "peakJump":
return new PeakJumpMeasurement(meta);
@ -200,10 +196,6 @@ public class MspDevice extends SingleMeasurementDevice implements PortHandler.Po
}
}
public void setMspListener(MspListener listener) {
this.mspListener = listener;
}
/**
* Send request to the msp
*
@ -213,9 +205,12 @@ public class MspDevice extends SingleMeasurementDevice implements PortHandler.Po
*/
private void send(String command, Object... parameters) throws PortException {
String request = buildCommand(command, parameters);
if (mspListener != null) {
mspListener.acceptRequest(request);
}
dispatchEvent(
EventBuilder
.make("msp")
.setMetaValue("request", request)
.build()
);
getHandler().send(request);
}
@ -247,9 +242,12 @@ public class MspDevice extends SingleMeasurementDevice implements PortHandler.Po
private MspResponse sendAndWait(String commandName, Object... parameters) throws PortException {
String request = buildCommand(commandName, parameters);
if (mspListener != null) {
mspListener.acceptRequest(request);
}
dispatchEvent(
EventBuilder
.make("msp")
.setMetaValue("request", request)
.build()
);
String response = getHandler().sendAndWait(
request,
@ -275,8 +273,8 @@ public class MspDevice extends SingleMeasurementDevice implements PortHandler.Po
return getState("filamentOn").booleanValue();
}
public void selectFillament(int fillament) throws PortException {
sendAndWait("FilamentSelect", fillament);
public void selectFillament(int filament) throws PortException {
sendAndWait("FilamentSelect", filament);
}
/**
@ -305,9 +303,11 @@ public class MspDevice extends SingleMeasurementDevice implements PortHandler.Po
@Override
public void accept(String message) {
if (mspListener != null) {
mspListener.acceptMessage(message.trim());
}
dispatchEvent(
EventBuilder
.make("msp")
.setMetaValue("response", message.trim()).build()
);
MspResponse response = new MspResponse(message);
switch (response.getCommandName()) {
@ -316,25 +316,17 @@ public class MspDevice extends SingleMeasurementDevice implements PortHandler.Po
String status = response.get(0, 2);
updateState("filamentOn", status.equals("ON"));
updateState("filamentStatus", status);
if (mspListener != null) {
mspListener.acceptFilamentStateChange(status);
}
break;
}
if (responseDelegate != null) {
responseDelegate.accept(response);
PeakJumpMeasurement measurement = getMeasurement();
if (measurement != null) {
measurement.eval(response);
}
}
@Override
public void error(String errorMessage, Throwable error) {
if (mspListener != null) {
mspListener.error(errorMessage, error);
} else if (error != null) {
throw new RuntimeException(error);
} else {
throw new RuntimeException(errorMessage);
}
notifyError(errorMessage, error);
}
private TcpPortHandler getHandler() {
@ -345,17 +337,17 @@ public class MspDevice extends SingleMeasurementDevice implements PortHandler.Po
}
private Duration getAveragingDuration() {
return Duration.parse(meta().getString("averagingDuration", "PT60S"));
return Duration.parse(meta().getString("averagingDuration", "PT30S"));
}
/**
* The MKS response as two-dimensional array of strings
*/
static class MspResponse {
private static class MspResponse {
private final List<List<String>> data = new ArrayList<>();
public MspResponse(String response) {
MspResponse(String response) {
String rx = "[^\"\\s]+|\"(\\\\.|[^\\\\\"])*\"";
Scanner scanner = new Scanner(response.trim());
@ -370,15 +362,15 @@ public class MspDevice extends SingleMeasurementDevice implements PortHandler.Po
}
}
public String getCommandName() {
String getCommandName() {
return this.get(0, 0);
}
public boolean isOK() {
boolean isOK() {
return "OK".equals(this.get(0, 1));
}
public int errorCode() {
int errorCode() {
if (isOK()) {
return -1;
} else {
@ -386,7 +378,7 @@ public class MspDevice extends SingleMeasurementDevice implements PortHandler.Po
}
}
public String errorDescription() {
String errorDescription() {
if (isOK()) {
return null;
} else {
@ -394,20 +386,20 @@ public class MspDevice extends SingleMeasurementDevice implements PortHandler.Po
}
}
public String get(int lineNo, int columnNo) {
String get(int lineNo, int columnNo) {
return data.get(lineNo).get(columnNo);
}
}
private class PeakJumpMeasurement extends AbstractMeasurement<DataPoint> {
public class PeakJumpMeasurement extends AbstractMeasurement<DataPoint> {
private ValueCollector collector = new RegularPointCollector(getAveragingDuration(), this::result);
private RegularPointCollector collector = new RegularPointCollector(getAveragingDuration(), this::result);
private StorageHelper helper = new StorageHelper(MspDevice.this, this::makeLoader);
private final Meta meta;
private Map<Integer, String> peakMap;
private double zero = 0;
public PeakJumpMeasurement(Meta meta) {
private PeakJumpMeasurement(Meta meta) {
this.meta = meta;
}
@ -441,15 +433,13 @@ public class MspDevice extends SingleMeasurementDevice implements PortHandler.Po
@Override
public void start() {
responseDelegate = this::eval;
try {
String name = "peakJump";//an.getString("measurementNAmname", "default");
String measurementName = "peakJump";
String filterMode = meta.getString("filterMode", "PeakAverage");
int accuracy = meta.getInt("accuracy", 5);
//PENDING вставить остальные параметры?
sendAndWait("MeasurementRemove", name);
if (sendAndWait("AddPeakJump", name, filterMode, accuracy, 0, 0, 0).isOK()) {
sendAndWait("MeasurementRemoveAll");
if (sendAndWait("AddPeakJump", measurementName, filterMode, accuracy, 0, 0, 0).isOK()) {
peakMap = new LinkedHashMap<>();
for (Meta peak : meta.getMetaList("peak")) {
peakMap.put(peak.getInt("mass"), peak.getString("name", peak.getString("mass")));
@ -464,7 +454,7 @@ public class MspDevice extends SingleMeasurementDevice implements PortHandler.Po
if (!isFilamentOn()) {
this.error("Can't start measurement. Filament is not turned on.", null);
}
if (!sendAndWait("ScanAdd", "peakJump").isOK()) {
if (!sendAndWait("ScanAdd", measurementName).isOK()) {
this.error("Failed to add scan", null);
}
@ -480,9 +470,9 @@ public class MspDevice extends SingleMeasurementDevice implements PortHandler.Po
@Override
public boolean stop(boolean force) throws MeasurementException {
try {
collector.stop();
boolean stop = sendAndWait("ScanStop").isOK();
afterStop();
responseDelegate = null;
helper.close();
return stop;
} catch (PortException ex) {
@ -496,7 +486,7 @@ public class MspDevice extends SingleMeasurementDevice implements PortHandler.Po
helper.push(result);
}
public void eval(MspResponse response) {
void eval(MspResponse response) {
//Evaluating device state change
evaluateResponse(response);
@ -507,9 +497,11 @@ public class MspDevice extends SingleMeasurementDevice implements PortHandler.Po
double value = Double.parseDouble(response.get(0, 2)) / 100d;
String massName = Integer.toString((int) Math.floor(mass + 0.5));
collector.put(massName, value);
forEachConnection(Roles.VIEW_ROLE, NamedValueListener.class, listener -> listener.pushValue(massName, value));
break;
case "ZeroReading":
zero = Double.parseDouble(response.get(0, 2)) / 100d;
break;
case "StartingScan":
int numScans = Integer.parseInt(response.get(0, 3));
@ -525,7 +517,7 @@ public class MspDevice extends SingleMeasurementDevice implements PortHandler.Po
}
}
public void error(String errorMessage, Throwable error) {
void error(String errorMessage, Throwable error) {
if (error == null) {
error(new MeasurementException(errorMessage));
} else {

View File

@ -1,33 +0,0 @@
/*
* Copyright 2015 Alexander Nozik.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package inr.numass.control.msp;
/**
*
* @author darksnake
*/
public interface MspListener {
void error(String errorMessage, Throwable error);
void acceptMessage(String message);
void acceptRequest(String message);
default void acceptFilamentStateChange(String fillamentState){
}
}

View File

@ -52,66 +52,5 @@ public class MspApp extends NumassControlApplication<MspDevice> {
return Objects.equals(meta.getString("name"), "msp");
}
// private Device device;
//
//
// /**
// * @param args the command line arguments
// */
// public static void main(String[] args) {
// launch(args);
// }
//
// @Override
// public void start(Stage primaryStage) throws Exception {
// Locale.setDefault(Locale.US);// чтобы отделение десятичных знаков было точкой
// ch.qos.logback.classic.Logger rootLogger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(ch.qos.logback.classic.Logger.ROOT_LOGGER_NAME);
// rootLogger.setLevel(Level.INFO);
//
// FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/MspView.fxml"));
//
// Parent parent = loader.load();
// MspViewController controller = loader.getController();
//
// Scene scene = new Scene(parent, 800, 600);
//
// primaryStage.setTitle("Numass mass-spectrometer view");
// primaryStage.setScene(scene);
// primaryStage.setMinHeight(400);
// primaryStage.setMinWidth(600);
//
// primaryStage.show();
//
// setupDevice(controller);
// }
//
// private void setupDevice(MspViewController controller){
// Meta config = NumassControlUtils.getConfig(this)
// .orElseGet(() -> NumassControlUtils.readResourceMeta("/config/msp-config.xml"));
//
// Context ctx = NumassControlUtils.setupContext(config);
// Meta mspConfig = NumassControlUtils.findDeviceMeta(config,it-> Objects.equals(it.getString("name"), "msp"))
// .orElseThrow(()-> new RuntimeException("Msp configuration not found"));
//
//
// Platform.runLater(() -> {
// try {
// device = new MspDeviceFactory().build(ctx, mspConfig);
// device.init();
// device.connect(controller, Roles.VIEW_ROLE);
// NumassControlUtils.connectStorage(device,config);
// } catch (ControlException e) {
// throw new RuntimeException("Failed to build device", e);
// }
// });
// }
//
// @Override
// public void stop() throws Exception {
// super.stop();
// if (device != null) {
// device.shutdown();
// }
// }
}

View File

@ -15,9 +15,9 @@
*/
package inr.numass.control.msp.fx;
import hep.dataforge.control.NamedValueListener;
import hep.dataforge.control.devices.Device;
import hep.dataforge.control.devices.DeviceListener;
import hep.dataforge.control.measurements.Measurement;
import hep.dataforge.control.measurements.MeasurementListener;
import hep.dataforge.exceptions.ControlException;
import hep.dataforge.exceptions.PortException;
import hep.dataforge.fx.fragments.FragmentWindow;
@ -28,12 +28,11 @@ import hep.dataforge.plots.data.TimePlottable;
import hep.dataforge.plots.data.TimePlottableGroup;
import hep.dataforge.plots.fx.PlotContainer;
import hep.dataforge.plots.jfreechart.JFreeChartFrame;
import hep.dataforge.tables.DataPoint;
import hep.dataforge.values.Value;
import inr.numass.control.DeviceViewConnection;
import inr.numass.control.msp.MspDevice;
import inr.numass.control.msp.MspListener;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.event.ActionEvent;
@ -52,7 +51,6 @@ import org.controlsfx.control.ToggleSwitch;
import java.io.IOException;
import java.net.URL;
import java.time.Instant;
import java.util.ResourceBundle;
/**
@ -60,7 +58,7 @@ import java.util.ResourceBundle;
*
* @author darksnake
*/
public class MspViewController extends DeviceViewConnection<MspDevice> implements DeviceListener, Initializable, MspListener, MeasurementListener {
public class MspViewController extends DeviceViewConnection<MspDevice> implements DeviceListener, Initializable, NamedValueListener {
public static MspViewController build() {
try {
@ -77,26 +75,12 @@ public class MspViewController extends DeviceViewConnection<MspDevice> implement
private JFreeChartFrame plot;
private LogFragment logFragment;
// private final ConfigChangeListener viewConfigObserver = new ConfigChangeListener() {
//
// @Override
// public void notifyElementChanged(String name, List<? extends Meta> oldItem, List<? extends Meta> newItem) {
// updatePlot();
// }
//
// @Override
// public void notifyValueChanged(String name, Value oldItem, Value newItem) {
// updatePlot();
// }
//
// };
@FXML
private BorderPane root;
@FXML
private ToggleSwitch fillamentButton;
private ToggleSwitch filamentButton;
@FXML
private Circle fillamentIndicator;
private Circle filamentIndicator;
@FXML
private ToggleButton measureButton;
@FXML
@ -106,7 +90,7 @@ public class MspViewController extends DeviceViewConnection<MspDevice> implement
@FXML
private ToggleButton consoleButton;
@FXML
private ComboBox<Integer> fillamentSelector;
private ComboBox<Integer> filamentSelector;
@FXML
private ToggleButton storeButton;
@ -121,8 +105,8 @@ public class MspViewController extends DeviceViewConnection<MspDevice> implement
logFragment = new LogFragment();
new FragmentWindow(logFragment).bindTo(consoleButton);
logFragment.addRootLogHandler();
fillamentSelector.setItems(FXCollections.observableArrayList(1, 2));
fillamentSelector.setConverter(new StringConverter<Integer>() {
filamentSelector.setItems(FXCollections.observableArrayList(1, 2));
filamentSelector.setConverter(new StringConverter<Integer>() {
@Override
public String toString(Integer object) {
return "Filament " + object;
@ -134,19 +118,39 @@ public class MspViewController extends DeviceViewConnection<MspDevice> implement
}
});
fillamentSelector.getSelectionModel().select(0);
fillamentButton.selectedProperty().addListener((ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) -> {
filamentSelector.getSelectionModel().select(0);
filamentButton.selectedProperty().addListener((ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) -> {
try {
fillamentSelector.setDisable(newValue);
filamentSelector.setDisable(newValue);
getDevice().setFilamentOn(newValue);
} catch (PortException ex) {
getDevice().getLogger().error("Failed to toggle filaments");
}
});
fillamentButton.disableProperty().bind(connectButton.selectedProperty().not());
measureButton.disableProperty().bind(fillamentButton.selectedProperty().not());
filamentButton.disableProperty().bind(connectButton.selectedProperty().not());
measureButton.disableProperty().bind(filamentButton.selectedProperty().not());
storeButton.disableProperty().bind(measureButton.selectedProperty().not());
getStateBinding("filamentStatus").addListener(new ChangeListener<Value>() {
@Override
public void changed(ObservableValue<? extends Value> observable, Value oldValue, Value newValue) {
String filamentState = newValue.stringValue();
Platform.runLater(() -> {
switch (filamentState) {
case "ON":
filamentIndicator.setFill(Paint.valueOf("red"));
break;
case "OFF":
filamentIndicator.setFill(Paint.valueOf("blue"));
break;
case "WARM-UP":
case "COOL-DOWN":
filamentIndicator.setFill(Paint.valueOf("yellow"));
break;
}
});
}
});
}
@ -158,7 +162,6 @@ public class MspViewController extends DeviceViewConnection<MspDevice> implement
@Override
public void open(MspDevice device) throws Exception {
super.open(device);
getDevice().setMspListener(this);
updatePlot();
bindBooleanToState("connected", connectButton.selectedProperty());
@ -187,17 +190,18 @@ public class MspViewController extends DeviceViewConnection<MspDevice> implement
this.plot.configure(config.getMeta("plotFrame"));
}
if (config.hasMeta("peakJump.peak")) {
for (Meta an : config.getMetaList("peakJump.peak")) {
String mass = an.getString("mass");
for (Meta peakMeta : config.getMetaList("peakJump.peak")) {
String mass = peakMeta.getString("mass");
if (!this.plottables.has(mass)) {
TimePlottable newPlottable = new TimePlottable(mass, mass);
newPlottable.configure(an);
newPlottable.configure(peakMeta);
newPlottable.setMaxItems(1000);
newPlottable.setPrefItems(400);
newPlottable.configureValue("titleBase",peakMeta.getString("title",mass));
this.plottables.add(newPlottable);
plot.add(newPlottable);
} else {
plottables.get(mass).configure(an);
plottables.get(mass).configure(peakMeta);
}
}
} else {
@ -207,28 +211,13 @@ public class MspViewController extends DeviceViewConnection<MspDevice> implement
}
@Override
public void acceptMessage(String message) {
public void evaluateDeviceException(Device device, String message, Throwable exception) {
Platform.runLater(() -> {
logFragment.appendLine("RECIEVE: " + message);
logFragment.appendLine("ERROR: " + message);
showError(message);
});
}
@Override
public void acceptRequest(String message) {
Platform.runLater(() -> {
logFragment.appendLine("SEND: " + message);
});
}
@Override
public void error(String errorMessage, Throwable error) {
Platform.runLater(() -> {
logFragment.appendLine("ERROR: " + errorMessage);
showError(errorMessage);
});
}
@FXML
private void onPlotToggle(ActionEvent event) throws ControlException {
if (measureButton.isSelected()) {
@ -251,50 +240,28 @@ public class MspViewController extends DeviceViewConnection<MspDevice> implement
}
@Override
public void acceptFilamentStateChange(String fillamentState) {
Platform.runLater(() -> {
switch (fillamentState) {
case "ON":
this.fillamentIndicator.setFill(Paint.valueOf("red"));
break;
case "OFF":
this.fillamentIndicator.setFill(Paint.valueOf("blue"));
break;
case "WARM-UP":
case "COOL-DOWN":
this.fillamentIndicator.setFill(Paint.valueOf("yellow"));
break;
}
});
}
@FXML
private void onStoreButtonClick(ActionEvent event) {
getDevice().setState("storing", storeButton.isSelected());
}
@Override
public Node getFXNode() {
return root;
}
@Override
public void onMeasurementResult(Measurement<?> measurement, Object res, Instant time) {
DataPoint result = DataPoint.class.cast(res);
for (String valueName : result.names()) {
public void pushValue(String valueName, Value value) {
TimePlottable pl = plottables.get(valueName);
if (pl != null) {
pl.put(Value.of(result.getValue(valueName)));
if (value.doubleValue() > 0) {
pl.put(value);
} else {
pl.put(Value.NULL);
}
String titleBase = pl.getConfig().getString("titleBase");
String title = String.format("%s (%.4g)", titleBase, value.doubleValue());
pl.configureValue("title", title);
}
}
}
@Override
public void onMeasurementFailed(Measurement<?> measurement, Throwable exception) {
}
}

View File

@ -21,23 +21,15 @@ limitations under the License.
<!--<connection ip="127.0.0.1" port="10014"/>-->
<connection ip="192.168.111.11" port="10014"/>
<peakJump>
<peak mass="2"/>
<peak mass="2" title="hydrogen" color="black" thickness="4"/>
<peak mass="3"/>
<peak mass="4"/>
<peak mass="6"/>
<peak mass="6" title="tritium" thickness="4"/>
<peak mass="12"/>
<peak mass="14"/>
<peak mass="18"/>
<peak mass="28"/>
<peak mass="32"/>
</peakJump>
<plotConfig>
<peakJump>
<peak mass="2" title="hydrogen" color="black" thickness="6"/>
<peak mass="6" title="tritium" thickness="4"/>
<peak mass="18" title="water"/>
<peak mass="28"/>
<peak mass="32" title="oxygen"/>
</peakJump>
</plotConfig>
</device>
</config>

View File

@ -27,13 +27,13 @@ limitations under the License.
<top>
<ToolBar prefHeight="50.0" prefWidth="200.0">
<ToggleButton fx:id="connectButton" mnemonicParsing="false" text="Connect" />
<ComboBox fx:id="fillamentSelector" promptText="Fillament 1" visibleRowCount="2" />
<ToggleSwitch fx:id="fillamentButton" prefHeight="40.0" prefWidth="35.0">
<ComboBox fx:id="filamentSelector" promptText="Fillament 1" visibleRowCount="2" />
<ToggleSwitch fx:id="filamentButton" prefHeight="40.0" prefWidth="35.0">
<padding>
<Insets top="11.0" />
</padding>
</ToggleSwitch>
<Circle fx:id="fillamentIndicator" fill="GRAY" radius="10.0" stroke="BLACK" strokeType="INSIDE" />
<Circle fx:id="filamentIndicator" fill="GRAY" radius="10.0" stroke="BLACK" strokeType="INSIDE" />
<Separator orientation="VERTICAL" prefHeight="20.0" />
<ToggleButton fx:id="measureButton" mnemonicParsing="false" onAction="#onPlotToggle" text="Measure" />
<ToggleButton fx:id="storeButton" mnemonicParsing="false" onAction="#onStoreButtonClick" text="Store" />