Updating Device UI
This commit is contained in:
parent
7749dd31de
commit
dcf318b16c
@ -1,15 +1,7 @@
|
|||||||
configurations {
|
|
||||||
compile.exclude module: 'groovy'
|
|
||||||
compile.exclude module: 'groovy-all'
|
|
||||||
compile.exclude module: 'shichimifx'
|
|
||||||
compile.exclude module: 'zt-zip'
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile project(':numass-client')
|
compile project(':numass-client')
|
||||||
compile "hep.dataforge:plots-jfc" // project(':dataforge-plots:plots-jfc')
|
compile "hep.dataforge:plots-jfc" // project(':dataforge-plots:plots-jfc')
|
||||||
compile "hep.dataforge:dataforge-control" //project(':dataforge-control')
|
compile "hep.dataforge:dataforge-control" //project(':dataforge-control')
|
||||||
compile "hep.dataforge:dataforge-fx" //project(':dataforge-fx')
|
|
||||||
|
|
||||||
// https://mvnrepository.com/artifact/org.controlsfx/controlsfx
|
// https://mvnrepository.com/artifact/org.controlsfx/controlsfx
|
||||||
compile group: 'org.controlsfx', name: 'controlsfx', version: '8.40.12'
|
compile group: 'org.controlsfx', name: 'controlsfx', version: '8.40.12'
|
||||||
|
@ -21,7 +21,7 @@ import hep.dataforge.io.MetaFileReader;
|
|||||||
import hep.dataforge.meta.Meta;
|
import hep.dataforge.meta.Meta;
|
||||||
import hep.dataforge.meta.MetaUtils;
|
import hep.dataforge.meta.MetaUtils;
|
||||||
import hep.dataforge.storage.commons.StorageManager;
|
import hep.dataforge.storage.commons.StorageManager;
|
||||||
import inr.numass.control.NumassConnections;
|
import inr.numass.control.NumassControlUtils;
|
||||||
import javafx.application.Application;
|
import javafx.application.Application;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
import javafx.fxml.FXMLLoader;
|
import javafx.fxml.FXMLLoader;
|
||||||
@ -75,7 +75,7 @@ public class PKT8App extends Application {
|
|||||||
device = setupDevice(deviceName, config);
|
device = setupDevice(deviceName, config);
|
||||||
|
|
||||||
// setting up storage connections
|
// setting up storage connections
|
||||||
NumassConnections.connectStorage(device, config);
|
NumassControlUtils.connectStorage(device, config);
|
||||||
|
|
||||||
FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/PKT8Indicator.fxml"));
|
FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/PKT8Indicator.fxml"));
|
||||||
PKT8Controller controller = new PKT8Controller();
|
PKT8Controller controller = new PKT8Controller();
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
apply plugin: 'application'
|
apply plugin: 'application'
|
||||||
|
|
||||||
version = "0.3.0"
|
version = "0.4.0"
|
||||||
|
|
||||||
if (!hasProperty('mainClass')) {
|
if (!hasProperty('mainClass')) {
|
||||||
ext.mainClass = 'inr.numass.control.msp.fx.MspApp'
|
ext.mainClass = 'inr.numass.control.msp.fx.MspApp'
|
||||||
|
@ -20,6 +20,7 @@ import hep.dataforge.control.connections.Roles;
|
|||||||
import hep.dataforge.control.connections.StorageConnection;
|
import hep.dataforge.control.connections.StorageConnection;
|
||||||
import hep.dataforge.control.devices.SingleMeasurementDevice;
|
import hep.dataforge.control.devices.SingleMeasurementDevice;
|
||||||
import hep.dataforge.control.devices.annotations.RoleDef;
|
import hep.dataforge.control.devices.annotations.RoleDef;
|
||||||
|
import hep.dataforge.control.devices.annotations.StateDef;
|
||||||
import hep.dataforge.control.measurements.AbstractMeasurement;
|
import hep.dataforge.control.measurements.AbstractMeasurement;
|
||||||
import hep.dataforge.control.measurements.Measurement;
|
import hep.dataforge.control.measurements.Measurement;
|
||||||
import hep.dataforge.control.ports.PortHandler;
|
import hep.dataforge.control.ports.PortHandler;
|
||||||
@ -37,6 +38,7 @@ import hep.dataforge.tables.MapPoint;
|
|||||||
import hep.dataforge.tables.TableFormat;
|
import hep.dataforge.tables.TableFormat;
|
||||||
import hep.dataforge.tables.TableFormatBuilder;
|
import hep.dataforge.tables.TableFormatBuilder;
|
||||||
import hep.dataforge.utils.DateTimeUtils;
|
import hep.dataforge.utils.DateTimeUtils;
|
||||||
|
import hep.dataforge.values.Value;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
@ -44,23 +46,28 @@ import java.util.concurrent.ConcurrentSkipListMap;
|
|||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* @author Alexander Nozik
|
* @author Alexander Nozik
|
||||||
*/
|
*/
|
||||||
@RoleDef(name = Roles.STORAGE_ROLE, objectType = StorageConnection.class)
|
@RoleDef(name = Roles.STORAGE_ROLE, objectType = StorageConnection.class)
|
||||||
|
@RoleDef(name = Roles.VIEW_ROLE)
|
||||||
|
@StateDef(name = "connected", writable = true, info = "Connection with the device itself")
|
||||||
|
@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 implements PortHandler.PortController {
|
||||||
public static final String MSP_DEVICE_TYPE = "msp";
|
public static final String MSP_DEVICE_TYPE = "msp";
|
||||||
|
|
||||||
// private static final String PEAK_SET_PATH = "peakJump.peak";
|
// private static final String PEAK_SET_PATH = "peakJump.peak";
|
||||||
private static final int TIMEOUT = 200;
|
private static final int TIMEOUT = 200;
|
||||||
boolean connected = false;
|
// private boolean connected = false;
|
||||||
boolean selected = false;
|
// private boolean selected = false;
|
||||||
boolean controlled = false;
|
// private boolean controlled = false;
|
||||||
|
// private boolean storing = false;
|
||||||
|
|
||||||
private TcpPortHandler handler;
|
private TcpPortHandler handler;
|
||||||
//listener
|
//listener
|
||||||
private MspListener mspListener;
|
private MspListener mspListener;
|
||||||
private Consumer<MspResponse> responseDelegate;
|
private Consumer<MspResponse> responseDelegate;
|
||||||
private Consumer<Throwable> errorDelegate;
|
|
||||||
|
|
||||||
public MspDevice() {
|
public MspDevice() {
|
||||||
}
|
}
|
||||||
@ -81,17 +88,16 @@ public class MspDevice extends SingleMeasurementDevice implements PortHandler.Po
|
|||||||
getLogger().info("Connection to MKS mass-spectrometer on {}:{}...", ip, port);
|
getLogger().info("Connection to MKS mass-spectrometer on {}:{}...", ip, port);
|
||||||
handler = new TcpPortHandler(ip, port);
|
handler = new TcpPortHandler(ip, port);
|
||||||
handler.setDelimeter("\r\r");
|
handler.setDelimeter("\r\r");
|
||||||
handler.holdBy(this);
|
|
||||||
setConnected(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void shutdown() throws ControlException {
|
public void shutdown() throws ControlException {
|
||||||
super.shutdown();
|
super.shutdown();
|
||||||
super.stopMeasurement(true);
|
super.stopMeasurement(true);
|
||||||
setFileamentOn(false);
|
if(isConnected()) {
|
||||||
setConnected(false);
|
setFileamentOn(false);
|
||||||
getHandler().unholdBy(this);
|
setConnected(false);
|
||||||
|
}
|
||||||
getHandler().close();
|
getHandler().close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,10 +124,14 @@ public class MspDevice extends SingleMeasurementDevice implements PortHandler.Po
|
|||||||
@Override
|
@Override
|
||||||
protected Object computeState(String stateName) throws ControlException {
|
protected Object computeState(String stateName) throws ControlException {
|
||||||
switch (stateName) {
|
switch (stateName) {
|
||||||
|
case "connected":
|
||||||
|
return false;
|
||||||
case "filamentOn":
|
case "filamentOn":
|
||||||
return false;//Always return false on first request
|
return false;//Always return false on first request
|
||||||
case "filamentStatus":
|
case "filamentStatus":
|
||||||
return "UNKNOWN";
|
return "UNKNOWN";
|
||||||
|
case "storing":
|
||||||
|
return false;
|
||||||
default:
|
default:
|
||||||
throw new ControlException("State not defined");
|
throw new ControlException("State not defined");
|
||||||
}
|
}
|
||||||
@ -132,17 +142,17 @@ public class MspDevice extends SingleMeasurementDevice implements PortHandler.Po
|
|||||||
return "MKS E-Vision";
|
return "MKS E-Vision";
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Override
|
@Override
|
||||||
// public void command(String commandName, Value argument) throws ControlException {
|
protected void requestStateChange(String stateName, Value value) throws ControlException {
|
||||||
// switch (commandName) {
|
switch (stateName) {
|
||||||
// case "connect":
|
case "connected":
|
||||||
// setConnected(argument.booleanValue());
|
setConnected(value.booleanValue());
|
||||||
// case "setFilamentOn":
|
case "filamentOn":
|
||||||
// setFileamentOn(argument.booleanValue());
|
setFileamentOn(value.booleanValue());
|
||||||
// default:
|
default:
|
||||||
// super.command(commandName, argument);
|
super.requestStateChange(stateName, value);
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Startup MSP: get available sensors, select sensor and control.
|
* Startup MSP: get available sensors, select sensor and control.
|
||||||
@ -151,10 +161,11 @@ public class MspDevice extends SingleMeasurementDevice implements PortHandler.Po
|
|||||||
* @return
|
* @return
|
||||||
* @throws hep.dataforge.exceptions.ControlException
|
* @throws hep.dataforge.exceptions.ControlException
|
||||||
*/
|
*/
|
||||||
public boolean setConnected(boolean connected) throws ControlException {
|
private boolean setConnected(boolean connected) throws ControlException {
|
||||||
String sensorName;
|
String sensorName;
|
||||||
if (isConnected() != connected) {
|
if (isConnected() != connected) {
|
||||||
if (connected) {
|
if (connected) {
|
||||||
|
handler.holdBy(this);
|
||||||
MspResponse response = sendAndWait("Sensors");
|
MspResponse response = sendAndWait("Sensors");
|
||||||
if (response.isOK()) {
|
if (response.isOK()) {
|
||||||
sensorName = response.get(2, 1);
|
sensorName = response.get(2, 1);
|
||||||
@ -166,8 +177,8 @@ public class MspDevice extends SingleMeasurementDevice implements PortHandler.Po
|
|||||||
|
|
||||||
response = sendAndWait("Select", sensorName);
|
response = sendAndWait("Select", sensorName);
|
||||||
if (response.isOK()) {
|
if (response.isOK()) {
|
||||||
selected = true;
|
updateState("selected", true);
|
||||||
// updateState("selected", true);
|
// selected = true;
|
||||||
} else {
|
} else {
|
||||||
error(response.errorDescription(), null);
|
error(response.errorDescription(), null);
|
||||||
return false;
|
return false;
|
||||||
@ -175,17 +186,18 @@ public class MspDevice extends SingleMeasurementDevice implements PortHandler.Po
|
|||||||
|
|
||||||
response = sendAndWait("Control", "inr.numass.msp", "1.0");
|
response = sendAndWait("Control", "inr.numass.msp", "1.0");
|
||||||
if (response.isOK()) {
|
if (response.isOK()) {
|
||||||
controlled = true;
|
// controlled = true;
|
||||||
// invalidateState("controlled");
|
// invalidateState("controlled");
|
||||||
// updateState("controlled", true);
|
updateState("controlled", true);
|
||||||
} else {
|
} else {
|
||||||
error(response.errorDescription(), null);
|
error(response.errorDescription(), null);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
connected = true;
|
// connected = true;
|
||||||
// updateState("connected", true);
|
updateState("connected", true);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
|
handler.unholdBy(this);
|
||||||
return !sendAndWait("Release").isOK();
|
return !sendAndWait("Release").isOK();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,7 +250,7 @@ public class MspDevice extends SingleMeasurementDevice implements PortHandler.Po
|
|||||||
* @return
|
* @return
|
||||||
* @throws PortException
|
* @throws PortException
|
||||||
*/
|
*/
|
||||||
public MspResponse sendAndWait(String commandName, Object... paremeters) throws PortException {
|
private MspResponse sendAndWait(String commandName, Object... paremeters) throws PortException {
|
||||||
|
|
||||||
String request = buildCommand(commandName, paremeters);
|
String request = buildCommand(commandName, paremeters);
|
||||||
if (mspListener != null) {
|
if (mspListener != null) {
|
||||||
@ -254,18 +266,15 @@ public class MspDevice extends SingleMeasurementDevice implements PortHandler.Po
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean isConnected() {
|
public boolean isConnected() {
|
||||||
return connected;
|
return getState("connected").booleanValue();
|
||||||
//return getState("connected") != null && getState("connected").booleanValue();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isSelected() {
|
public boolean isSelected() {
|
||||||
return selected;
|
return getState("selected").booleanValue();
|
||||||
//return getState("selected") != null && getState("selected").booleanValue();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isControlled() {
|
public boolean isControlled() {
|
||||||
return controlled;
|
return getState("controlled").booleanValue();
|
||||||
//return getState("controlled") != null && getState("controlled").booleanValue();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isFilamentOn() {
|
public boolean isFilamentOn() {
|
||||||
@ -279,9 +288,8 @@ public class MspDevice extends SingleMeasurementDevice implements PortHandler.Po
|
|||||||
/**
|
/**
|
||||||
* Turn filament on or off
|
* Turn filament on or off
|
||||||
*
|
*
|
||||||
* @return
|
|
||||||
*
|
|
||||||
* @param filamentOn
|
* @param filamentOn
|
||||||
|
* @return
|
||||||
* @throws hep.dataforge.exceptions.PortException
|
* @throws hep.dataforge.exceptions.PortException
|
||||||
*/
|
*/
|
||||||
public boolean setFileamentOn(boolean filamentOn) throws PortException {
|
public boolean setFileamentOn(boolean filamentOn) throws PortException {
|
||||||
@ -336,7 +344,7 @@ public class MspDevice extends SingleMeasurementDevice implements PortHandler.Po
|
|||||||
}
|
}
|
||||||
|
|
||||||
private TcpPortHandler getHandler() {
|
private TcpPortHandler getHandler() {
|
||||||
if(handler == null){
|
if (handler == null) {
|
||||||
throw new RuntimeException("Device not initialized");
|
throw new RuntimeException("Device not initialized");
|
||||||
}
|
}
|
||||||
return handler;
|
return handler;
|
||||||
@ -397,7 +405,7 @@ public class MspDevice extends SingleMeasurementDevice implements PortHandler.Po
|
|||||||
|
|
||||||
private final Map<Integer, Double> measurement = new ConcurrentSkipListMap<>();
|
private final Map<Integer, Double> measurement = new ConcurrentSkipListMap<>();
|
||||||
private final Map<StorageConnection, PointLoader> loaderMap = new HashMap<>();
|
private final Map<StorageConnection, PointLoader> loaderMap = new HashMap<>();
|
||||||
// private List<PointLoader> loaders = new ArrayList<>();
|
// private List<PointLoader> loaders = new ArrayList<>();
|
||||||
private final Meta meta;
|
private final Meta meta;
|
||||||
private Map<Integer, String> peakMap;
|
private Map<Integer, String> peakMap;
|
||||||
private double zero = 0;
|
private double zero = 0;
|
||||||
@ -416,16 +424,13 @@ public class MspDevice extends SingleMeasurementDevice implements PortHandler.Po
|
|||||||
}
|
}
|
||||||
|
|
||||||
TableFormatBuilder builder = new TableFormatBuilder().addTime("timestamp");
|
TableFormatBuilder builder = new TableFormatBuilder().addTime("timestamp");
|
||||||
this.peakMap.values().stream().forEach((peakName) -> {
|
this.peakMap.values().forEach(builder::addNumber);
|
||||||
builder.addNumber(peakName);
|
|
||||||
});
|
|
||||||
|
|
||||||
TableFormat format = builder.build();
|
TableFormat format = builder.build();
|
||||||
|
|
||||||
String suffix = Integer.toString((int) DateTimeUtils.now().toEpochMilli());
|
String suffix = DateTimeUtils.now().toString();
|
||||||
PointLoader loader = LoaderFactory
|
return LoaderFactory
|
||||||
.buildPointLoder(storage, "msp" + suffix, "", "timestamp", format);
|
.buildPointLoder(storage, "msp_" + suffix, "", "timestamp", format);
|
||||||
return loader;
|
|
||||||
} catch (StorageException ex) {
|
} catch (StorageException ex) {
|
||||||
getLogger().error("Failed to create Loader", ex);
|
getLogger().error("Failed to create Loader", ex);
|
||||||
return null;
|
return null;
|
||||||
@ -505,30 +510,34 @@ public class MspDevice extends SingleMeasurementDevice implements PortHandler.Po
|
|||||||
case "StartingScan":
|
case "StartingScan":
|
||||||
if (mspListener != null && !measurement.isEmpty()) {
|
if (mspListener != null && !measurement.isEmpty()) {
|
||||||
if (peakMap == null) {
|
if (peakMap == null) {
|
||||||
throw new IllegalStateException("Peal map is not initialized");
|
throw new IllegalStateException("Peak map is not initialized");
|
||||||
}
|
}
|
||||||
|
|
||||||
Instant time = DateTimeUtils.now();
|
|
||||||
|
|
||||||
MapPoint.Builder point = new MapPoint.Builder();
|
|
||||||
point.putValue("timestamp", time);
|
|
||||||
|
|
||||||
measurement.entrySet().stream().forEach((entry) -> {
|
|
||||||
double val = entry.getValue();
|
|
||||||
point.putValue(peakMap.get(entry.getKey()), val);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (isFilamentOn()) {
|
if (isFilamentOn()) {
|
||||||
|
|
||||||
|
Instant time = DateTimeUtils.now();
|
||||||
|
|
||||||
|
MapPoint.Builder point = new MapPoint.Builder();
|
||||||
|
point.putValue("timestamp", time);
|
||||||
|
|
||||||
|
measurement.entrySet().forEach((entry) -> {
|
||||||
|
double val = entry.getValue();
|
||||||
|
point.putValue(peakMap.get(entry.getKey()), val);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
mspListener.acceptScan(measurement);
|
mspListener.acceptScan(measurement);
|
||||||
|
|
||||||
forEachConnection(Roles.STORAGE_ROLE, StorageConnection.class, (StorageConnection connection) -> {
|
if (getState("storing").booleanValue()) {
|
||||||
PointLoader pl = loaderMap.computeIfAbsent(connection, con -> makeLoader(con));
|
forEachConnection(Roles.STORAGE_ROLE, StorageConnection.class, (StorageConnection connection) -> {
|
||||||
try {
|
PointLoader pl = loaderMap.computeIfAbsent(connection, this::makeLoader);
|
||||||
pl.push(point.build());
|
try {
|
||||||
} catch (StorageException ex) {
|
pl.push(point.build());
|
||||||
getLogger().error("Push to loader failed", ex);
|
} catch (StorageException ex) {
|
||||||
}
|
getLogger().error("Push to loader failed", ex);
|
||||||
});
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
measurement.clear();
|
measurement.clear();
|
||||||
|
@ -15,115 +15,95 @@
|
|||||||
*/
|
*/
|
||||||
package inr.numass.control.msp.fx;
|
package inr.numass.control.msp.fx;
|
||||||
|
|
||||||
import ch.qos.logback.classic.Level;
|
import hep.dataforge.control.devices.DeviceFactory;
|
||||||
import hep.dataforge.context.Global;
|
import inr.numass.control.DeviceViewConnection;
|
||||||
import hep.dataforge.control.connections.Roles;
|
import inr.numass.control.NumassControlApplication;
|
||||||
import hep.dataforge.exceptions.ControlException;
|
|
||||||
import hep.dataforge.io.MetaFileReader;
|
|
||||||
import hep.dataforge.io.XMLMetaReader;
|
|
||||||
import hep.dataforge.meta.Meta;
|
|
||||||
import hep.dataforge.storage.commons.StorageManager;
|
|
||||||
import inr.numass.control.msp.MspDevice;
|
import inr.numass.control.msp.MspDevice;
|
||||||
import inr.numass.control.msp.MspDeviceFactory;
|
import inr.numass.control.msp.MspDeviceFactory;
|
||||||
import javafx.application.Application;
|
|
||||||
import javafx.application.Platform;
|
|
||||||
import javafx.fxml.FXMLLoader;
|
|
||||||
import javafx.scene.Parent;
|
|
||||||
import javafx.scene.Scene;
|
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
import static inr.numass.control.msp.MspDevice.MSP_DEVICE_TYPE;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author darksnake
|
* @author darksnake
|
||||||
*/
|
*/
|
||||||
public class MspApp extends Application {
|
public class MspApp extends NumassControlApplication<MspDevice> {
|
||||||
public static final String DEFAULT_CONFIG_LOCATION = "msp-config.xml";
|
|
||||||
|
|
||||||
private MspDevice device;
|
@Override
|
||||||
|
protected DeviceViewConnection<MspDevice> buildView() {
|
||||||
|
return MspViewController.build();
|
||||||
/**
|
|
||||||
* @param args the command line arguments
|
|
||||||
*/
|
|
||||||
public static void main(String[] args) {
|
|
||||||
launch(args);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void start(Stage primaryStage) throws Exception {
|
protected DeviceFactory<MspDevice> getDeviceFactory() {
|
||||||
Locale.setDefault(Locale.US);// чтобы отделение десятичных знаков было точкой
|
return new MspDeviceFactory();
|
||||||
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);
|
|
||||||
new StorageManager().startGlobal();
|
|
||||||
|
|
||||||
String configFileName = getParameters().getNamed().get("config");
|
|
||||||
if (configFileName == null) {
|
|
||||||
configFileName = DEFAULT_CONFIG_LOCATION;
|
|
||||||
}
|
|
||||||
File configFile = new File(configFileName);
|
|
||||||
Meta config;
|
|
||||||
if (configFile.exists()) {
|
|
||||||
config = MetaFileReader.read(configFile).build();
|
|
||||||
} else {
|
|
||||||
config = new XMLMetaReader().read(getClass().getResourceAsStream("/config/msp-config.xml"));
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
Platform.runLater(()->{
|
|
||||||
try {
|
|
||||||
device = new MspDeviceFactory().build(Global.instance(), getMspConfig(config));
|
|
||||||
device.init();
|
|
||||||
device.connect(controller, Roles.VIEW_ROLE);
|
|
||||||
} catch (ControlException e) {
|
|
||||||
throw new RuntimeException("Failed to build device", e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
primaryStage.show();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Meta getMspConfig(Meta config) {
|
|
||||||
Meta mspConfig = null;
|
|
||||||
if (config.hasMeta("device")) {
|
|
||||||
for (Meta d : config.getMetaList("device")) {
|
|
||||||
if (d.getString("type", "unknown").equals(MSP_DEVICE_TYPE)) {
|
|
||||||
mspConfig = d;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (config.hasMeta("peakJump")) {
|
|
||||||
mspConfig = config;
|
|
||||||
}
|
|
||||||
return mspConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// showError(String.format("Can't connect to %s:%d. The port is either busy or not the MKS mass-spectrometer port",
|
|
||||||
// device.meta().getString("connection.ip", "127.0.0.1"),
|
|
||||||
// device.meta().getInt("connection.port", 10014)));
|
|
||||||
// throw new RuntimeException("Can't connect to device");
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void stop() throws Exception {
|
protected void setupStage(Stage stage) {
|
||||||
super.stop();
|
stage.setTitle("Numass mass-spectrometer view");
|
||||||
if (device != null) {
|
stage.setMinHeight(400);
|
||||||
device.shutdown();
|
stage.setMinWidth(600);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -15,28 +15,21 @@
|
|||||||
*/
|
*/
|
||||||
package inr.numass.control.msp.fx;
|
package inr.numass.control.msp.fx;
|
||||||
|
|
||||||
import hep.dataforge.control.connections.DeviceConnection;
|
|
||||||
import hep.dataforge.control.connections.Roles;
|
|
||||||
import hep.dataforge.control.connections.StorageConnection;
|
|
||||||
import hep.dataforge.control.devices.Device;
|
import hep.dataforge.control.devices.Device;
|
||||||
import hep.dataforge.control.devices.DeviceListener;
|
import hep.dataforge.control.devices.DeviceListener;
|
||||||
import hep.dataforge.exceptions.ControlException;
|
import hep.dataforge.exceptions.ControlException;
|
||||||
import hep.dataforge.exceptions.PortException;
|
import hep.dataforge.exceptions.PortException;
|
||||||
import hep.dataforge.exceptions.StorageException;
|
|
||||||
import hep.dataforge.fx.fragments.FragmentWindow;
|
import hep.dataforge.fx.fragments.FragmentWindow;
|
||||||
import hep.dataforge.fx.fragments.LogFragment;
|
import hep.dataforge.fx.fragments.LogFragment;
|
||||||
import hep.dataforge.meta.ConfigChangeListener;
|
import hep.dataforge.meta.ConfigChangeListener;
|
||||||
import hep.dataforge.meta.Configuration;
|
|
||||||
import hep.dataforge.meta.Meta;
|
import hep.dataforge.meta.Meta;
|
||||||
import hep.dataforge.meta.MetaBuilder;
|
import hep.dataforge.meta.MetaBuilder;
|
||||||
import hep.dataforge.plots.data.PlottableGroup;
|
import hep.dataforge.plots.data.PlottableGroup;
|
||||||
import hep.dataforge.plots.data.TimePlottable;
|
import hep.dataforge.plots.data.TimePlottable;
|
||||||
import hep.dataforge.plots.fx.PlotContainer;
|
import hep.dataforge.plots.fx.PlotContainer;
|
||||||
import hep.dataforge.plots.jfreechart.JFreeChartFrame;
|
import hep.dataforge.plots.jfreechart.JFreeChartFrame;
|
||||||
import hep.dataforge.storage.api.Storage;
|
|
||||||
import hep.dataforge.storage.commons.StorageManager;
|
|
||||||
import hep.dataforge.values.Value;
|
import hep.dataforge.values.Value;
|
||||||
import inr.numass.client.NumassClient;
|
import inr.numass.control.DeviceViewConnection;
|
||||||
import inr.numass.control.msp.MspDevice;
|
import inr.numass.control.msp.MspDevice;
|
||||||
import inr.numass.control.msp.MspListener;
|
import inr.numass.control.msp.MspListener;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
@ -44,21 +37,19 @@ import javafx.beans.value.ObservableValue;
|
|||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
import javafx.event.ActionEvent;
|
import javafx.event.ActionEvent;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
|
import javafx.fxml.FXMLLoader;
|
||||||
import javafx.fxml.Initializable;
|
import javafx.fxml.Initializable;
|
||||||
|
import javafx.scene.Node;
|
||||||
import javafx.scene.control.Alert;
|
import javafx.scene.control.Alert;
|
||||||
import javafx.scene.control.ComboBox;
|
import javafx.scene.control.ComboBox;
|
||||||
import javafx.scene.control.Slider;
|
|
||||||
import javafx.scene.control.ToggleButton;
|
import javafx.scene.control.ToggleButton;
|
||||||
import javafx.scene.input.DragEvent;
|
import javafx.scene.layout.BorderPane;
|
||||||
import javafx.scene.layout.AnchorPane;
|
|
||||||
import javafx.scene.paint.Paint;
|
import javafx.scene.paint.Paint;
|
||||||
import javafx.scene.shape.Circle;
|
import javafx.scene.shape.Circle;
|
||||||
import javafx.stage.DirectoryChooser;
|
|
||||||
import javafx.util.StringConverter;
|
import javafx.util.StringConverter;
|
||||||
import org.controlsfx.control.ToggleSwitch;
|
import org.controlsfx.control.ToggleSwitch;
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.IOException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -69,24 +60,23 @@ import java.util.ResourceBundle;
|
|||||||
*
|
*
|
||||||
* @author darksnake
|
* @author darksnake
|
||||||
*/
|
*/
|
||||||
public class MspViewController extends DeviceConnection<MspDevice> implements DeviceListener, Initializable, MspListener {
|
public class MspViewController extends DeviceViewConnection<MspDevice> implements DeviceListener, Initializable, MspListener {
|
||||||
|
|
||||||
|
public static MspViewController build() {
|
||||||
|
try {
|
||||||
|
FXMLLoader loader = new FXMLLoader(MspViewController.class.getResource("/fxml/MspView.fxml"));
|
||||||
|
loader.load();
|
||||||
|
return loader.getController();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new Error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private final PlottableGroup<TimePlottable> plottables = new PlottableGroup<>();
|
private final PlottableGroup<TimePlottable> plottables = new PlottableGroup<>();
|
||||||
private Configuration viewConfig;
|
// private Configuration viewConfig;
|
||||||
private JFreeChartFrame plot;
|
private JFreeChartFrame plot;
|
||||||
private LogFragment logArea;
|
private LogFragment logArea;
|
||||||
private StorageConnection connection;
|
|
||||||
|
|
||||||
@FXML
|
|
||||||
private Slider autoRangeSlider;
|
|
||||||
@FXML
|
|
||||||
private ToggleSwitch fillamentButton;
|
|
||||||
@FXML
|
|
||||||
private Circle fillamentIndicator;
|
|
||||||
@FXML
|
|
||||||
private ToggleButton plotButton;
|
|
||||||
@FXML
|
|
||||||
private AnchorPane plotPane;
|
|
||||||
private final ConfigChangeListener viewConfigObserver = new ConfigChangeListener() {
|
private final ConfigChangeListener viewConfigObserver = new ConfigChangeListener() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -100,6 +90,19 @@ public class MspViewController extends DeviceConnection<MspDevice> implements De
|
|||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private BorderPane root;
|
||||||
|
@FXML
|
||||||
|
private ToggleSwitch fillamentButton;
|
||||||
|
@FXML
|
||||||
|
private Circle fillamentIndicator;
|
||||||
|
@FXML
|
||||||
|
private ToggleButton plotButton;
|
||||||
|
@FXML
|
||||||
|
private BorderPane plotPane;
|
||||||
|
@FXML
|
||||||
|
public ToggleButton connectButton;
|
||||||
@FXML
|
@FXML
|
||||||
private ToggleButton consoleButton;
|
private ToggleButton consoleButton;
|
||||||
@FXML
|
@FXML
|
||||||
@ -139,28 +142,25 @@ public class MspViewController extends DeviceConnection<MspDevice> implements De
|
|||||||
getDevice().getLogger().error("Failed to toggle filaments");
|
getDevice().getLogger().error("Failed to toggle filaments");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Configuration getViewConfig() {
|
|
||||||
if (viewConfig == null) {
|
|
||||||
viewConfig = new Configuration(getDevice().meta().getMeta("peakJump"));
|
public Meta getViewConfig() {
|
||||||
viewConfig.addObserver(viewConfigObserver);
|
return getDevice().meta().getMeta("plot",getDevice().getMeta());
|
||||||
LoggerFactory.getLogger(getClass()).warn("Could not find view configuration. Using default view configuration instead.");
|
|
||||||
}
|
|
||||||
return viewConfig;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setViewConfig(Meta viewConfig) {
|
|
||||||
this.viewConfig = new Configuration(viewConfig);
|
|
||||||
this.viewConfig.addObserver(viewConfigObserver);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void open(MspDevice device) throws Exception {
|
public void open(MspDevice device) throws Exception {
|
||||||
super.open(device);
|
super.open(device);
|
||||||
getDevice().setMspListener(this);
|
getDevice().setMspListener(this);
|
||||||
device.getConfig().optMeta("plot").ifPresent(this::setViewConfig);
|
|
||||||
updatePlot();
|
updatePlot();
|
||||||
|
|
||||||
|
//FIXME
|
||||||
|
getStateBinding("connected").addListener((observable, oldValue, newValue) -> connectButton.setSelected(newValue.booleanValue()));
|
||||||
|
bindStateTo("connected", connectButton.selectedProperty());
|
||||||
}
|
}
|
||||||
|
|
||||||
// public void setDeviceConfig(Context context, File cfgFile) {
|
// public void setDeviceConfig(Context context, File cfgFile) {
|
||||||
@ -172,7 +172,7 @@ public class MspViewController extends DeviceConnection<MspDevice> implements De
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
public void initPlot() {
|
private void initPlot() {
|
||||||
Meta plotConfig = new MetaBuilder("plotFrame")
|
Meta plotConfig = new MetaBuilder("plotFrame")
|
||||||
.setNode(new MetaBuilder("yAxis")
|
.setNode(new MetaBuilder("yAxis")
|
||||||
.setValue("type", "log")
|
.setValue("type", "log")
|
||||||
@ -182,9 +182,9 @@ public class MspViewController extends DeviceConnection<MspDevice> implements De
|
|||||||
.setValue("xAxis.type", "time");
|
.setValue("xAxis.type", "time");
|
||||||
|
|
||||||
this.plot = new JFreeChartFrame(plotConfig);
|
this.plot = new JFreeChartFrame(plotConfig);
|
||||||
PlotContainer container = PlotContainer.anchorTo(plotPane);
|
PlotContainer container = PlotContainer.centerIn(plotPane);
|
||||||
container.setPlot(plot);
|
container.setPlot(plot);
|
||||||
updatePlot();
|
// updatePlot();
|
||||||
// this.plot = DynamicPlot.attachToFX(plotPane, new AnnotationBuilder("plot-config").putValue("logY", true).build());
|
// this.plot = DynamicPlot.attachToFX(plotPane, new AnnotationBuilder("plot-config").putValue("logY", true).build());
|
||||||
// plot.setAutoRange(30 * 60);
|
// plot.setAutoRange(30 * 60);
|
||||||
}
|
}
|
||||||
@ -197,8 +197,8 @@ public class MspViewController extends DeviceConnection<MspDevice> implements De
|
|||||||
if (config.hasMeta("plotFrame")) {
|
if (config.hasMeta("plotFrame")) {
|
||||||
this.plot.configure(config.getMeta("plotFrame"));
|
this.plot.configure(config.getMeta("plotFrame"));
|
||||||
}
|
}
|
||||||
if (config.hasMeta("peakJump.line")) {
|
if (config.hasMeta("peakJump.peak")) {
|
||||||
for (Meta an : config.getMetaList("peakJump.line")) {
|
for (Meta an : config.getMetaList("peakJump.peak")) {
|
||||||
String mass = an.getString("mass");
|
String mass = an.getString("mass");
|
||||||
|
|
||||||
if (!this.plottables.has(mass)) {
|
if (!this.plottables.has(mass)) {
|
||||||
@ -254,11 +254,6 @@ public class MspViewController extends DeviceConnection<MspDevice> implements De
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@FXML
|
|
||||||
private void onAutoRangeChange(DragEvent event) {
|
|
||||||
plottables.setValue(TimePlottable.MAX_AGE_KEY, this.autoRangeSlider.getValue() * 60000);
|
|
||||||
}
|
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private void onPlotToggle(ActionEvent event) throws ControlException {
|
private void onPlotToggle(ActionEvent event) throws ControlException {
|
||||||
if (plotButton.isSelected()) {
|
if (plotButton.isSelected()) {
|
||||||
@ -302,50 +297,51 @@ public class MspViewController extends DeviceConnection<MspDevice> implements De
|
|||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private void onStoreButtonClick(ActionEvent event) {
|
private void onStoreButtonClick(ActionEvent event) {
|
||||||
if (storeButton.isSelected()) {
|
getDevice().setState("storing", storeButton.isSelected());
|
||||||
|
// if (storeButton.isSelected()) {
|
||||||
if (!getDevice().meta().hasMeta("storage")) {
|
//
|
||||||
getDevice().getLogger().info("Storage not defined. Starting storage selection dialog");
|
// if (!getDevice().meta().hasMeta("storage")) {
|
||||||
DirectoryChooser chooser = new DirectoryChooser();
|
// getDevice().getLogger().info("Storage not defined. Starting storage selection dialog");
|
||||||
File storageDir = chooser.showDialog(this.plotPane.getScene().getWindow());
|
// DirectoryChooser chooser = new DirectoryChooser();
|
||||||
if (storageDir == null) {
|
// File storageDir = chooser.showDialog(this.plotPane.getScene().getWindow());
|
||||||
storeButton.setSelected(false);
|
// if (storageDir == null) {
|
||||||
throw new RuntimeException("User canceled directory selection");
|
// storeButton.setSelected(false);
|
||||||
}
|
// throw new RuntimeException("User canceled directory selection");
|
||||||
getDevice().getConfig().putNode(new MetaBuilder("storage")
|
// }
|
||||||
.putValue("path", storageDir.getAbsolutePath()));
|
// getDevice().getConfig().putNode(new MetaBuilder("storage")
|
||||||
}
|
// .putValue("path", storageDir.getAbsolutePath()));
|
||||||
Meta storageConfig = getDevice().meta().getMeta("storage");
|
// }
|
||||||
Storage localStorage = StorageManager.buildFrom(getDevice().getContext())
|
// Meta storageConfig = getDevice().meta().getMeta("storage");
|
||||||
.buildStorage(storageConfig);
|
// Storage localStorage = StorageManager.buildFrom(getDevice().getContext())
|
||||||
|
// .buildStorage(storageConfig);
|
||||||
String runName = getDevice().meta().getString("numass.run", "");
|
//
|
||||||
Meta meta = getDevice().meta();
|
// String runName = getDevice().meta().getString("numass.run", "");
|
||||||
if (meta.hasMeta("numass")) {
|
// Meta meta = getDevice().meta();
|
||||||
try {
|
// if (meta.hasMeta("numass")) {
|
||||||
getDevice().getLogger().info("Obtaining run information from cetral server...");
|
// try {
|
||||||
NumassClient client = new NumassClient(meta.getString("numass.ip", "192.168.111.1"),
|
// getDevice().getLogger().info("Obtaining run information from cetral server...");
|
||||||
meta.getInt("numass.port", 8335));
|
// NumassClient client = new NumassClient(meta.getString("numass.ip", "192.168.111.1"),
|
||||||
runName = client.getCurrentRun().getString("path", "");
|
// meta.getInt("numass.port", 8335));
|
||||||
getDevice().getLogger().info("Run name is '{}'", runName);
|
// runName = client.getCurrentRun().getString("path", "");
|
||||||
} catch (Exception ex) {
|
// getDevice().getLogger().info("Run name is '{}'", runName);
|
||||||
getDevice().getLogger().warn("Failed to download current run information", ex);
|
// } catch (Exception ex) {
|
||||||
}
|
// getDevice().getLogger().warn("Failed to download current run information", ex);
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
if (!runName.isEmpty()) {
|
//
|
||||||
try {
|
// if (!runName.isEmpty()) {
|
||||||
localStorage = localStorage.buildShelf(runName, null);
|
// try {
|
||||||
} catch (StorageException ex) {
|
// localStorage = localStorage.buildShelf(runName, null);
|
||||||
getDevice().getLogger().error("Failed to create storage shelf. Using root storage instead");
|
// } catch (StorageException ex) {
|
||||||
}
|
// getDevice().getLogger().error("Failed to create storage shelf. Using root storage instead");
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
connection = new StorageConnection(localStorage);
|
//
|
||||||
getDevice().connect(connection, Roles.STORAGE_ROLE);
|
// connection = new StorageConnection(localStorage);
|
||||||
} else if (connection != null) {
|
// getDevice().connect(connection, Roles.STORAGE_ROLE);
|
||||||
getDevice().disconnect(connection);
|
// } else if (connection != null) {
|
||||||
}
|
// getDevice().disconnect(connection);
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -362,4 +358,9 @@ public class MspViewController extends DeviceConnection<MspDevice> implements De
|
|||||||
public void evaluateDeviceException(Device device, String message, Throwable exception) {
|
public void evaluateDeviceException(Device device, String message, Throwable exception) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Node getFXNode() {
|
||||||
|
return root;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,10 +32,10 @@ limitations under the License.
|
|||||||
</peakJump>
|
</peakJump>
|
||||||
<plot>
|
<plot>
|
||||||
<peakJump>
|
<peakJump>
|
||||||
<line mass="2" title="hydrogen" color="black" thickness="6"/>
|
<peak mass="2" title="hydrogen" color="black" thickness="6"/>
|
||||||
<line mass="6" title="tritium" thickness="4"/>
|
<peak mass="6" title="tritium" thickness="4"/>
|
||||||
<line mass="18" title="water" />
|
<peak mass="18" title="water" />
|
||||||
<line mass="32" title="oxygen"/>
|
<peak mass="32" title="oxygen"/>
|
||||||
</peakJump>
|
</peakJump>
|
||||||
</plot>
|
</plot>
|
||||||
</device>
|
</device>
|
||||||
|
@ -17,40 +17,32 @@ limitations under the License.
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
<?import javafx.geometry.Insets?>
|
<?import javafx.geometry.Insets?>
|
||||||
<?import javafx.scene.control.ComboBox?>
|
<?import javafx.scene.control.*?>
|
||||||
<?import javafx.scene.control.Label?>
|
<?import javafx.scene.layout.BorderPane?>
|
||||||
<?import javafx.scene.control.Separator?>
|
|
||||||
<?import javafx.scene.control.Slider?>
|
|
||||||
<?import javafx.scene.control.ToggleButton?>
|
|
||||||
<?import javafx.scene.control.ToolBar?>
|
|
||||||
<?import javafx.scene.layout.AnchorPane?>
|
|
||||||
<?import javafx.scene.layout.HBox?>
|
<?import javafx.scene.layout.HBox?>
|
||||||
<?import javafx.scene.layout.Pane?>
|
<?import javafx.scene.layout.Pane?>
|
||||||
<?import javafx.scene.shape.Circle?>
|
<?import javafx.scene.shape.Circle?>
|
||||||
<?import org.controlsfx.control.ToggleSwitch?>
|
<?import org.controlsfx.control.ToggleSwitch?>
|
||||||
|
<BorderPane fx:id="root" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="400.0" minWidth="600.0" prefHeight="480.0" prefWidth="640.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="inr.numass.control.msp.fx.MspViewController">
|
||||||
<AnchorPane id="AnchorPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="400.0" minWidth="600.0" prefHeight="480.0" prefWidth="640.0" xmlns="http://javafx.com/javafx/8.0.65" xmlns:fx="http://javafx.com/fxml/1" fx:controller="inr.numass.control.msp.fx.MspViewController">
|
<top>
|
||||||
<children>
|
<ToolBar prefHeight="50.0" prefWidth="200.0">
|
||||||
<ToolBar prefHeight="50.0" prefWidth="200.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
<ToggleButton fx:id="connectButton" mnemonicParsing="false" text="Connect" />
|
||||||
<items>
|
<ComboBox fx:id="fillamentSelector" promptText="Fillament 1" visibleRowCount="2" />
|
||||||
<ComboBox fx:id="fillamentSelector" promptText="Fillament 1" visibleRowCount="2" />
|
<ToggleSwitch fx:id="fillamentButton" prefHeight="40.0" prefWidth="35.0">
|
||||||
<ToggleSwitch fx:id="fillamentButton" prefHeight="40.0" prefWidth="35.0">
|
<padding>
|
||||||
<padding>
|
<Insets top="11.0" />
|
||||||
<Insets top="11.0" />
|
</padding>
|
||||||
</padding>
|
</ToggleSwitch>
|
||||||
</ToggleSwitch>
|
<Circle fx:id="fillamentIndicator" fill="GRAY" radius="10.0" stroke="BLACK" strokeType="INSIDE" />
|
||||||
<Circle fx:id="fillamentIndicator" fill="GRAY" radius="10.0" stroke="BLACK" strokeType="INSIDE" />
|
<Separator orientation="VERTICAL" prefHeight="20.0" />
|
||||||
<Separator orientation="VERTICAL" prefHeight="20.0" />
|
<ToggleButton fx:id="plotButton" mnemonicParsing="false" onAction="#onPlotToggle" text="Measure" />
|
||||||
<ToggleButton fx:id="plotButton" mnemonicParsing="false" onAction="#onPlotToggle" text="Measure" />
|
<ToggleButton fx:id="storeButton" mnemonicParsing="false" onAction="#onStoreButtonClick" text="Store" />
|
||||||
<ToggleButton fx:id="storeButton" mnemonicParsing="false" onAction="#onStoreButtonClick" text="Store" />
|
<Separator orientation="VERTICAL" prefHeight="20.0" />
|
||||||
<Separator orientation="VERTICAL" prefHeight="20.0" />
|
<Pane HBox.hgrow="ALWAYS" />
|
||||||
<Label text="Autorange (min):" />
|
<ToggleButton fx:id="consoleButton" mnemonicParsing="false" text="Console" />
|
||||||
<Slider fx:id="autoRangeSlider" max="210.0" min="10.0" onDragDone="#onAutoRangeChange" showTickLabels="true" showTickMarks="true" snapToTicks="true" value="30.0" />
|
|
||||||
<Separator orientation="VERTICAL" prefHeight="20.0" />
|
|
||||||
<Pane HBox.hgrow="ALWAYS" />
|
|
||||||
<ToggleButton fx:id="consoleButton" mnemonicParsing="false" text="Console" />
|
|
||||||
</items>
|
|
||||||
</ToolBar>
|
</ToolBar>
|
||||||
<AnchorPane fx:id="plotPane" minHeight="400.0" minWidth="600.0" prefHeight="200.0" prefWidth="200.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="50.0" />
|
</top>
|
||||||
</children>
|
<center>
|
||||||
</AnchorPane>
|
<BorderPane fx:id="plotPane" minHeight="400.0" minWidth="600.0" prefHeight="200.0" prefWidth="200.0" />
|
||||||
|
</center>
|
||||||
|
</BorderPane>
|
||||||
|
@ -0,0 +1,65 @@
|
|||||||
|
package inr.numass.control;
|
||||||
|
|
||||||
|
import hep.dataforge.control.connections.DeviceConnection;
|
||||||
|
import hep.dataforge.control.devices.Device;
|
||||||
|
import hep.dataforge.control.devices.DeviceListener;
|
||||||
|
import hep.dataforge.fx.FXObject;
|
||||||
|
import hep.dataforge.values.Value;
|
||||||
|
import javafx.beans.binding.Bindings;
|
||||||
|
import javafx.beans.binding.BooleanBinding;
|
||||||
|
import javafx.beans.binding.ObjectBinding;
|
||||||
|
import javafx.beans.value.ChangeListener;
|
||||||
|
import javafx.beans.value.ObservableValue;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by darksnake on 14-May-17.
|
||||||
|
*/
|
||||||
|
public abstract class DeviceViewConnection<D extends Device> extends DeviceConnection<D> implements DeviceListener, FXObject {
|
||||||
|
private Map<String, ObjectBinding<Value>> bindings = new HashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get binding for a given device state
|
||||||
|
*
|
||||||
|
* @param state
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
protected ObjectBinding<Value> getStateBinding(String state) {
|
||||||
|
return bindings.computeIfAbsent(state, stateName ->
|
||||||
|
new ObjectBinding<Value>() {
|
||||||
|
@Override
|
||||||
|
protected Value computeValue() {
|
||||||
|
return getDevice().getState(stateName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected BooleanBinding getStateBooleanBinding(String state) {
|
||||||
|
ObjectBinding<Value> b = getStateBinding(state);
|
||||||
|
return Bindings.createBooleanBinding(() -> b.get().booleanValue(), b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bind writable state change to given observable value
|
||||||
|
*
|
||||||
|
* @param state
|
||||||
|
* @param observable
|
||||||
|
*/
|
||||||
|
protected void bindStateTo(String state, ObservableValue<?> observable) {
|
||||||
|
observable.addListener((ChangeListener<Object>) (observable1, oldValue, newValue) -> {
|
||||||
|
if (oldValue != newValue) {
|
||||||
|
getDevice().setState(state, newValue);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void notifyDeviceStateChanged(Device device, String name, Value state) {
|
||||||
|
if (bindings.containsKey(name)) {
|
||||||
|
bindings.get(name).invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,40 +0,0 @@
|
|||||||
package inr.numass.control;
|
|
||||||
|
|
||||||
import hep.dataforge.control.connections.Roles;
|
|
||||||
import hep.dataforge.control.connections.StorageConnection;
|
|
||||||
import hep.dataforge.control.devices.Device;
|
|
||||||
import hep.dataforge.exceptions.StorageException;
|
|
||||||
import hep.dataforge.meta.Meta;
|
|
||||||
import hep.dataforge.storage.api.Storage;
|
|
||||||
import hep.dataforge.storage.commons.StorageFactory;
|
|
||||||
import inr.numass.client.ClientUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by darksnake on 08-May-17.
|
|
||||||
*/
|
|
||||||
public class NumassConnections {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a single or multiple storage connections for a device
|
|
||||||
* @param device
|
|
||||||
* @param config
|
|
||||||
*/
|
|
||||||
public static void connectStorage(Device device, Meta config) {
|
|
||||||
//TODO add on reset listener
|
|
||||||
if (config.hasMeta("storage")) {
|
|
||||||
String numassRun = ClientUtils.getRunName(config);
|
|
||||||
config.getMetaList("storage").forEach(node -> {
|
|
||||||
Storage storage = StorageFactory.buildStorage(device.getContext(), node);
|
|
||||||
if (!numassRun.isEmpty()) {
|
|
||||||
try {
|
|
||||||
storage = storage.buildShelf(numassRun, Meta.empty());
|
|
||||||
} catch (StorageException e) {
|
|
||||||
device.getContext().getLogger().error("Failed to build shelf", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
device.connect(new StorageConnection(storage), Roles.STORAGE_ROLE);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -0,0 +1,93 @@
|
|||||||
|
package inr.numass.control;
|
||||||
|
|
||||||
|
import ch.qos.logback.classic.Level;
|
||||||
|
import hep.dataforge.context.Context;
|
||||||
|
import hep.dataforge.control.connections.DeviceConnection;
|
||||||
|
import hep.dataforge.control.connections.Roles;
|
||||||
|
import hep.dataforge.control.devices.Device;
|
||||||
|
import hep.dataforge.control.devices.DeviceFactory;
|
||||||
|
import hep.dataforge.exceptions.ControlException;
|
||||||
|
import hep.dataforge.meta.Meta;
|
||||||
|
import javafx.application.Application;
|
||||||
|
import javafx.application.Platform;
|
||||||
|
import javafx.scene.Scene;
|
||||||
|
import javafx.scene.layout.BorderPane;
|
||||||
|
import javafx.stage.Stage;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by darksnake on 14-May-17.
|
||||||
|
*/
|
||||||
|
public abstract class NumassControlApplication<D extends Device> extends Application {
|
||||||
|
private D device;
|
||||||
|
|
||||||
|
@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);
|
||||||
|
|
||||||
|
DeviceViewConnection<D> controller = buildView();
|
||||||
|
BorderPane pane = new BorderPane();
|
||||||
|
pane.setCenter(controller.getFXNode());
|
||||||
|
|
||||||
|
Scene scene = new Scene(pane);
|
||||||
|
|
||||||
|
primaryStage.setScene(scene);
|
||||||
|
primaryStage.show();
|
||||||
|
|
||||||
|
setupDevice(controller);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build a view connection
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
protected abstract DeviceViewConnection<D> buildView();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a device factory for given device
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
protected abstract DeviceFactory<D> getDeviceFactory();
|
||||||
|
|
||||||
|
protected abstract void setupStage(Stage stage);
|
||||||
|
|
||||||
|
|
||||||
|
private void setupDevice(DeviceConnection<D> 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 = getDeviceFactory().build(ctx, mspConfig);
|
||||||
|
device.init();
|
||||||
|
device.connect(controller, Roles.VIEW_ROLE, Roles.DEVICE_LISTENER_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();
|
||||||
|
device.getContext().close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,92 @@
|
|||||||
|
package inr.numass.control;
|
||||||
|
|
||||||
|
import hep.dataforge.context.Context;
|
||||||
|
import hep.dataforge.context.Global;
|
||||||
|
import hep.dataforge.control.connections.Roles;
|
||||||
|
import hep.dataforge.control.connections.StorageConnection;
|
||||||
|
import hep.dataforge.control.devices.Device;
|
||||||
|
import hep.dataforge.exceptions.StorageException;
|
||||||
|
import hep.dataforge.io.MetaFileReader;
|
||||||
|
import hep.dataforge.io.XMLMetaReader;
|
||||||
|
import hep.dataforge.meta.Meta;
|
||||||
|
import hep.dataforge.storage.api.Storage;
|
||||||
|
import hep.dataforge.storage.commons.StorageFactory;
|
||||||
|
import hep.dataforge.storage.commons.StorageManager;
|
||||||
|
import inr.numass.client.ClientUtils;
|
||||||
|
import javafx.application.Application;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.text.ParseException;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by darksnake on 08-May-17.
|
||||||
|
*/
|
||||||
|
public class NumassControlUtils {
|
||||||
|
public static final String DEFAULT_CONFIG_LOCATION = "numass-control.xml";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a single or multiple storage connections for a device
|
||||||
|
*
|
||||||
|
* @param device
|
||||||
|
* @param config
|
||||||
|
*/
|
||||||
|
public static void connectStorage(Device device, Meta config) {
|
||||||
|
//TODO add on reset listener
|
||||||
|
if (config.hasMeta("storage")&& device.acceptsRole("storge")) {
|
||||||
|
String numassRun = ClientUtils.getRunName(config);
|
||||||
|
config.getMetaList("storage").forEach(node -> {
|
||||||
|
Storage storage = StorageFactory.buildStorage(device.getContext(), node);
|
||||||
|
if (!numassRun.isEmpty()) {
|
||||||
|
try {
|
||||||
|
storage = storage.buildShelf(numassRun, Meta.empty());
|
||||||
|
} catch (StorageException e) {
|
||||||
|
device.getContext().getLogger().error("Failed to build shelf", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
device.connect(new StorageConnection(storage), Roles.STORAGE_ROLE);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Meta readResourceMeta(String path) {
|
||||||
|
try {
|
||||||
|
return new XMLMetaReader().read(NumassControlUtils.class.getResourceAsStream(path));
|
||||||
|
} catch (IOException | ParseException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Optional<Meta> getConfig(Application app) {
|
||||||
|
String configFileName = app.getParameters().getNamed().get("config");
|
||||||
|
if (configFileName == null) {
|
||||||
|
configFileName = DEFAULT_CONFIG_LOCATION;
|
||||||
|
}
|
||||||
|
File configFile = new File(configFileName);
|
||||||
|
|
||||||
|
if (configFile.exists()) {
|
||||||
|
try {
|
||||||
|
Meta config = MetaFileReader.read(configFile).build();
|
||||||
|
return Optional.of(config);
|
||||||
|
} catch (IOException | ParseException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static Optional<Meta> findDeviceMeta(Meta config, Predicate<Meta> criterion) {
|
||||||
|
return config.getMetaList("device").stream().filter(criterion).findFirst().map(it -> it);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Context setupContext(Meta meta) {
|
||||||
|
Context ctx = Global.getContext("NUMASS-CONTROL");
|
||||||
|
ctx.pluginManager().getOrLoad(StorageManager.class);
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user