numass cryotemp update
This commit is contained in:
parent
50947c9219
commit
f9f605bde0
@ -21,4 +21,12 @@ task debug(dependsOn: classes, type: JavaExec) {
|
||||
classpath = sourceSets.main.runtimeClasspath
|
||||
description "Start application in debug mode with default virtual port"
|
||||
group "debug"
|
||||
}
|
||||
|
||||
task testRun(dependsOn: classes, type: JavaExec) {
|
||||
main mainClass
|
||||
args(["--cfgFile=D:/temp/test/numass-devices.xml", "--device=thermo-1"])
|
||||
classpath = sourceSets.main.runtimeClasspath
|
||||
description "Start application using real device"
|
||||
group "debug"
|
||||
}
|
@ -16,10 +16,16 @@
|
||||
package inr.numass.cryotemp;
|
||||
|
||||
import ch.qos.logback.classic.Level;
|
||||
import hep.dataforge.control.connections.Roles;
|
||||
import hep.dataforge.control.connections.StorageConnection;
|
||||
import hep.dataforge.exceptions.ControlException;
|
||||
import hep.dataforge.io.MetaFileReader;
|
||||
import hep.dataforge.meta.Meta;
|
||||
import hep.dataforge.meta.MetaUtils;
|
||||
import hep.dataforge.storage.commons.StorageFactory;
|
||||
import hep.dataforge.storage.commons.StorageManager;
|
||||
import javafx.application.Application;
|
||||
import javafx.application.Platform;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.scene.Parent;
|
||||
import javafx.scene.Scene;
|
||||
@ -28,6 +34,7 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.text.ParseException;
|
||||
import java.util.Locale;
|
||||
|
||||
@ -35,54 +42,10 @@ import java.util.Locale;
|
||||
* @author darksnake
|
||||
*/
|
||||
public class PKT8App extends Application {
|
||||
|
||||
PKT8MainViewController controller;
|
||||
|
||||
@Override
|
||||
public void start(Stage primaryStage) throws IOException, ControlException, ParseException {
|
||||
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);
|
||||
new StorageManager().startGlobal();
|
||||
|
||||
FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/PKT8MainView.fxml"));
|
||||
|
||||
Parent parent = loader.load();
|
||||
controller = loader.getController();
|
||||
|
||||
// Meta deviceMeta = XMLMetaConverter.fromStream(getClass().getResourceAsStream("/defaultConfig.xml"));
|
||||
|
||||
// controller.setupDevice(deviceMeta);
|
||||
|
||||
Scene scene = new Scene(parent, 600, 400);
|
||||
public static final String DEFAULT_CONFIG_LOCATION = "numass-devices.xml";
|
||||
|
||||
|
||||
primaryStage.setTitle("PKT8 cryogenic temperature viewer");
|
||||
primaryStage.setScene(scene);
|
||||
primaryStage.setMinHeight(400);
|
||||
primaryStage.setMinWidth(600);
|
||||
// primaryStage.setResizable(false);
|
||||
|
||||
primaryStage.show();
|
||||
|
||||
if (getParameters().getNamed().containsKey("cfgFile")) {
|
||||
controller.setConfig(MetaFileReader.read(new File(getParameters().getNamed().get("cfgFile"))));
|
||||
} else if (Boolean.parseBoolean(getParameters().getNamed().getOrDefault("debug", "false"))) {
|
||||
controller.loadTestConfig();
|
||||
} else {
|
||||
controller.startConfigDialog();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() throws Exception {
|
||||
super.stop();
|
||||
if (controller != null) {
|
||||
controller.close();
|
||||
controller = null;
|
||||
}
|
||||
// System.exit(0);
|
||||
}
|
||||
PKT8Device device;
|
||||
|
||||
/**
|
||||
* @param args the command line arguments
|
||||
@ -91,4 +54,109 @@ public class PKT8App extends Application {
|
||||
launch(args);
|
||||
}
|
||||
|
||||
|
||||
// public Meta startConfigDialog(Scene scene) throws IOException, ParseException, ControlException {
|
||||
// FileChooser fileChooser = new FileChooser();
|
||||
// fileChooser.setTitle("Open configuration file");
|
||||
// fileChooser.setInitialFileName(DEFAULT_CONFIG_LOCATION);
|
||||
//// fileChooser.setInitialDirectory(GlobalContext.instance().io().getRootDirectory());
|
||||
// fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("xml", "*.xml", "*.XML"));
|
||||
// fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("json", "*.json", "*.JSON"));
|
||||
//// fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("all", "*.*"));
|
||||
// File cfgFile = fileChooser.showOpenDialog(scene.getWindow());
|
||||
//
|
||||
// if (cfgFile != null) {
|
||||
// return MetaFileReader.read(cfgFile);
|
||||
// } else {
|
||||
// return null;
|
||||
// }
|
||||
// }
|
||||
|
||||
@Override
|
||||
public void start(Stage primaryStage) throws IOException, ControlException, ParseException {
|
||||
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);
|
||||
new StorageManager().startGlobal();
|
||||
|
||||
String deviceName = getParameters().getNamed().getOrDefault("device", "PKT-8");
|
||||
|
||||
Meta config;
|
||||
|
||||
if (Boolean.parseBoolean(getParameters().getNamed().getOrDefault("debug", "false"))) {
|
||||
config = loadTestConfig();
|
||||
} else {
|
||||
config = MetaFileReader.read(new File(getParameters().getNamed().getOrDefault("cfgFile", DEFAULT_CONFIG_LOCATION)));
|
||||
}
|
||||
|
||||
|
||||
device = setupDevice(deviceName, config);
|
||||
|
||||
// setting up storage connections
|
||||
if (config.hasNode("storage")) {
|
||||
config.getNodes("storage").forEach(node -> {
|
||||
device.connect(new StorageConnection(StorageFactory.buildStorage(device.getContext(), node)), Roles.STORAGE_ROLE);
|
||||
});
|
||||
}
|
||||
|
||||
FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/PKT8Indicator.fxml"));
|
||||
PKT8Controller controller = new PKT8Controller(device);
|
||||
loader.setController(controller);
|
||||
|
||||
Parent parent = loader.load();
|
||||
|
||||
|
||||
Scene scene = new Scene(parent, 400, 400);
|
||||
primaryStage.setTitle("Numass temperature view");
|
||||
primaryStage.setScene(scene);
|
||||
primaryStage.setMinHeight(400);
|
||||
primaryStage.setMinWidth(400);
|
||||
// primaryStage.setResizable(false);
|
||||
|
||||
primaryStage.show();
|
||||
|
||||
Platform.runLater(() -> {
|
||||
try {
|
||||
device.init();
|
||||
// controller.start();
|
||||
} catch (ControlException e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public Meta loadTestConfig() throws ControlException {
|
||||
try {
|
||||
return MetaFileReader
|
||||
.read(new File(getClass().getResource("/config/defaultConfig.xml").toURI()));
|
||||
} catch (URISyntaxException | IOException | ParseException ex) {
|
||||
throw new Error(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public PKT8Device setupDevice(String deviceName, Meta config) throws ControlException {
|
||||
Meta deviceMeta;
|
||||
|
||||
if (config.hasNode("device")) {
|
||||
deviceMeta = MetaUtils.findNodeByValue(config, "device", "name", deviceName);
|
||||
} else {
|
||||
deviceMeta = config;
|
||||
}
|
||||
|
||||
PKT8Device device = new PKT8Device(deviceMeta.getString("port", "virtual"));
|
||||
|
||||
device.configure(deviceMeta);
|
||||
|
||||
return device;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() throws Exception {
|
||||
super.stop();
|
||||
if (device != null) {
|
||||
device.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,125 @@
|
||||
package inr.numass.cryotemp;
|
||||
|
||||
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.MeasurementException;
|
||||
import hep.dataforge.fx.ConsoleFragment;
|
||||
import hep.dataforge.values.Value;
|
||||
import javafx.application.Platform;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.Initializable;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import javafx.scene.control.TableView;
|
||||
import javafx.scene.control.ToggleButton;
|
||||
import javafx.scene.control.cell.PropertyValueFactory;
|
||||
|
||||
import java.net.URL;
|
||||
import java.time.Instant;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
/**
|
||||
* Created by darksnake on 07-Oct-16.
|
||||
*/
|
||||
public class PKT8Controller implements Initializable, DeviceListener, MeasurementListener<PKT8Result> {
|
||||
|
||||
private final PKT8Device device;
|
||||
private ConsoleFragment consoleFragment;
|
||||
private PKT8PlotFragment plotFragment;
|
||||
@FXML
|
||||
private ToggleButton startStopButton;
|
||||
@FXML
|
||||
private ToggleButton consoleButton;
|
||||
@FXML
|
||||
private ToggleButton plotButton;
|
||||
@FXML
|
||||
private Label lastUpdateLabel;
|
||||
|
||||
@FXML
|
||||
private TableView<PKT8Result> table;
|
||||
|
||||
@FXML
|
||||
private TableColumn<TableView<PKT8Result>, String> sensorColumn;
|
||||
|
||||
@FXML
|
||||
private TableColumn<TableView<PKT8Result>, Double> resColumn;
|
||||
|
||||
@FXML
|
||||
private TableColumn<TableView<PKT8Result>, String> tempColumn;
|
||||
|
||||
|
||||
public PKT8Controller(PKT8Device device) {
|
||||
this.device = device;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize(URL location, ResourceBundle resources) {
|
||||
this.consoleFragment = new ConsoleFragment();
|
||||
consoleFragment.bindTo(consoleButton);
|
||||
plotFragment = new PKT8PlotFragment(device);
|
||||
plotFragment.bindTo(plotButton);
|
||||
|
||||
sensorColumn.setCellValueFactory(new PropertyValueFactory<>("channel"));
|
||||
resColumn.setCellValueFactory(new PropertyValueFactory<>("rawString"));
|
||||
tempColumn.setCellValueFactory(new PropertyValueFactory<>("temperatureString"));
|
||||
startStopButton.selectedProperty().setValue(device.isMeasuring());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMeasurementResult(Measurement<PKT8Result> measurement, PKT8Result result, Instant time) {
|
||||
Platform.runLater(() -> {
|
||||
lastUpdateLabel.setText(time.toString());
|
||||
table.getItems().removeIf(it -> it.channel.equals(result.channel));
|
||||
table.getItems().add(result);
|
||||
table.getItems().sort((o1, o2) -> o1.channel.compareTo(o2.channel));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMeasurementFailed(Measurement measurement, Throwable exception) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyDeviceStateChanged(Device device, String name, Value state) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void evaluateDeviceException(Device device, String message, Throwable exception) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void start() throws MeasurementException {
|
||||
device.startMeasurement().addListener(this);
|
||||
}
|
||||
|
||||
public void stop() throws MeasurementException {
|
||||
if (device.isMeasuring()) {
|
||||
device.getMeasurement().removeListener(this);
|
||||
device.stopMeasurement(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@FXML
|
||||
private void onStartStopClick(ActionEvent event) {
|
||||
if (device != null) {
|
||||
try {
|
||||
if (startStopButton.isSelected()) {
|
||||
start();
|
||||
} else {
|
||||
//in case device started
|
||||
stop();
|
||||
}
|
||||
} catch (ControlException ex) {
|
||||
evaluateDeviceException(device, "Failed to start or stop device", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -21,6 +21,7 @@ import hep.dataforge.control.connections.PointListenerConnection;
|
||||
import hep.dataforge.control.connections.Roles;
|
||||
import hep.dataforge.control.connections.StorageConnection;
|
||||
import hep.dataforge.control.devices.PortSensor;
|
||||
import hep.dataforge.control.devices.annotations.RoleDef;
|
||||
import hep.dataforge.control.measurements.AbstractMeasurement;
|
||||
import hep.dataforge.control.measurements.Measurement;
|
||||
import hep.dataforge.control.ports.PortHandler;
|
||||
@ -30,8 +31,8 @@ import hep.dataforge.exceptions.PortException;
|
||||
import hep.dataforge.exceptions.StorageException;
|
||||
import hep.dataforge.meta.Meta;
|
||||
import hep.dataforge.storage.api.PointLoader;
|
||||
import hep.dataforge.storage.api.Storage;
|
||||
import hep.dataforge.storage.commons.LoaderFactory;
|
||||
import hep.dataforge.storage.commons.StorageFactory;
|
||||
import hep.dataforge.tables.DataPoint;
|
||||
import hep.dataforge.tables.PointListener;
|
||||
import hep.dataforge.tables.TableFormatBuilder;
|
||||
@ -39,12 +40,15 @@ import hep.dataforge.tables.TableFormatBuilder;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* A device controller for Dubna PKT 8 cryogenic thermometry device
|
||||
*
|
||||
* @author Alexander Nozik
|
||||
*/
|
||||
@RoleDef(name = Roles.STORAGE_ROLE)
|
||||
@RoleDef(name = Roles.POINT_LISTENER_ROLE)
|
||||
public class PKT8Device extends PortSensor<PKT8Result> {
|
||||
|
||||
public static final String PGA = "pga";
|
||||
@ -55,7 +59,6 @@ public class PKT8Device extends PortSensor<PKT8Result> {
|
||||
* The key is the letter (a,b,c,d...) as in measurements
|
||||
*/
|
||||
private final Map<String, PKT8Channel> channels = new HashMap<>();
|
||||
// private PointLoader pointLoader;
|
||||
private RegularPointCollector collector;
|
||||
|
||||
public PKT8Device(String portName) {
|
||||
@ -95,7 +98,7 @@ public class PKT8Device extends PortSensor<PKT8Result> {
|
||||
setSPS(meta().getInt("sps", 0));
|
||||
setBUF(meta().getInt("abuf", 100));
|
||||
|
||||
setupStorage();
|
||||
setupLoaders();
|
||||
|
||||
}
|
||||
|
||||
@ -240,7 +243,7 @@ public class PKT8Device extends PortSensor<PKT8Result> {
|
||||
return getState(ABUF).stringValue();
|
||||
}
|
||||
|
||||
private void setupStorage() {
|
||||
private void setupLoaders() {
|
||||
|
||||
// Building data format
|
||||
TableFormatBuilder tableFormatBuilder = new TableFormatBuilder()
|
||||
@ -252,24 +255,21 @@ public class PKT8Device extends PortSensor<PKT8Result> {
|
||||
names.add(channel.getName());
|
||||
}
|
||||
|
||||
// setting up storage connections
|
||||
if (meta().hasNode("storage")) {
|
||||
meta().getNodes("storage").forEach(node -> {
|
||||
connect(new StorageConnection(StorageFactory.buildStorage(getContext(), node)));
|
||||
});
|
||||
}
|
||||
|
||||
// setting up loader for each of storages
|
||||
forEachTypedConnection(Roles.STORAGE_ROLE, StorageConnection.class, connection -> {
|
||||
List<Storage> storages = connections().filter(it -> it.getValue()
|
||||
.contains(Roles.STORAGE_ROLE) && it.getKey() instanceof StorageConnection)
|
||||
.map(it -> ((StorageConnection) it.getKey()).getStorage()).collect(Collectors.toList());
|
||||
|
||||
storages.forEach(storage -> {
|
||||
String suffix = Integer.toString((int) Instant.now().toEpochMilli());
|
||||
|
||||
PointLoader pointLoader = null;
|
||||
try {
|
||||
pointLoader = LoaderFactory.buildPointLoder(connection.getStorage(),
|
||||
pointLoader = LoaderFactory.buildPointLoder(storage,
|
||||
"cryotemp_" + suffix, "", "timestamp", tableFormatBuilder.build());
|
||||
this.connect(new LoaderConnection(pointLoader), Roles.POINT_LISTENER_ROLE);
|
||||
} catch (StorageException e) {
|
||||
getLogger().error("Failed to build loader from storage {}", connection.getStorage().getName());
|
||||
getLogger().error("Failed to build loader from storage {}", storage.getName());
|
||||
}
|
||||
|
||||
});
|
||||
@ -284,7 +284,7 @@ public class PKT8Device extends PortSensor<PKT8Result> {
|
||||
}, duration, names);
|
||||
}
|
||||
|
||||
public void connectPointListener(PointListenerConnection listener){
|
||||
public void connectPointListener(PointListenerConnection listener) {
|
||||
this.connect(listener, Roles.POINT_LISTENER_ROLE);
|
||||
}
|
||||
|
||||
@ -334,6 +334,7 @@ public class PKT8Device extends PortSensor<PKT8Result> {
|
||||
}
|
||||
|
||||
try {
|
||||
getLogger().info("Starting measurement");
|
||||
handler.holdBy(this);
|
||||
handler.send("s");
|
||||
afterStart();
|
||||
@ -350,6 +351,7 @@ public class PKT8Device extends PortSensor<PKT8Result> {
|
||||
}
|
||||
|
||||
try {
|
||||
getLogger().info("Stopping measurement");
|
||||
String response = getHandler().sendAndWait("p", 400).trim();
|
||||
// Должно быть именно с большой буквы!!!
|
||||
return "Stopped".equals(response) || "stopped".equals(response);
|
||||
@ -372,7 +374,7 @@ public class PKT8Device extends PortSensor<PKT8Result> {
|
||||
if (isStarted()) {
|
||||
if (trimmed.equals("Stopped") || trimmed.equals("stopped")) {
|
||||
afterPause();
|
||||
getLogger().info("Measurement stopped");
|
||||
// getLogger().info("Measurement stopped");
|
||||
} else {
|
||||
String designation = trimmed.substring(0, 1);
|
||||
double rawValue = Double.parseDouble(trimmed.substring(1)) / 100;
|
||||
|
@ -1,261 +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.cryotemp;
|
||||
|
||||
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.fx.ConsoleFragment;
|
||||
import hep.dataforge.io.MetaFileReader;
|
||||
import hep.dataforge.meta.Meta;
|
||||
import hep.dataforge.meta.MetaUtils;
|
||||
import hep.dataforge.plots.PlotUtils;
|
||||
import hep.dataforge.plots.data.TimePlottable;
|
||||
import hep.dataforge.plots.data.TimePlottableGroup;
|
||||
import hep.dataforge.plots.data.XYPlottable;
|
||||
import hep.dataforge.plots.fx.FXPlotFrame;
|
||||
import hep.dataforge.plots.fx.PlotContainer;
|
||||
import hep.dataforge.plots.jfreechart.JFreeChartFrame;
|
||||
import hep.dataforge.values.Value;
|
||||
import javafx.beans.InvalidationListener;
|
||||
import javafx.beans.Observable;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.Initializable;
|
||||
import javafx.scene.control.ToggleButton;
|
||||
import javafx.scene.layout.AnchorPane;
|
||||
import javafx.stage.FileChooser;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.text.ParseException;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Collection;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
/**
|
||||
* FXML Controller class
|
||||
*
|
||||
* @author darksnake
|
||||
*/
|
||||
public class PKT8MainViewController implements Initializable, DeviceListener, MeasurementListener<PKT8Result>, AutoCloseable {
|
||||
|
||||
public static final String DEFAULT_CONFIG_LOCATION = "devices.xml";
|
||||
ConsoleFragment consoleFragment;
|
||||
private PKT8Device device;
|
||||
private FXPlotFrame<XYPlottable> plotFrame;
|
||||
private TimePlottableGroup plottables;
|
||||
|
||||
@FXML
|
||||
private ToggleButton startStopButton;
|
||||
@FXML
|
||||
private ToggleButton rawDataButton;
|
||||
@FXML
|
||||
private AnchorPane plotArea;
|
||||
@FXML
|
||||
private ToggleButton consoleButton;
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
if (device != null) {
|
||||
device.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the controller class.
|
||||
*/
|
||||
@Override
|
||||
public void initialize(URL url, ResourceBundle rb) {
|
||||
// setupPlotFrame(Meta.empty());
|
||||
this.consoleFragment = new ConsoleFragment();
|
||||
consoleFragment.bindTo(consoleButton);
|
||||
rawDataButton.selectedProperty().addListener(new InvalidationListener() {
|
||||
@Override
|
||||
public void invalidated(Observable observable) {
|
||||
if (plotFrame != null) {
|
||||
setupPlotFrame(plotFrame.getConfig());
|
||||
if (device != null) {
|
||||
setupChannels();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void startConfigDialog() throws IOException, ParseException, ControlException {
|
||||
FileChooser fileChooser = new FileChooser();
|
||||
fileChooser.setTitle("Open configuration file");
|
||||
fileChooser.setInitialFileName(DEFAULT_CONFIG_LOCATION);
|
||||
// fileChooser.setInitialDirectory(GlobalContext.instance().io().getRootDirectory());
|
||||
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("xml", "*.xml", "*.XML"));
|
||||
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("json", "*.json", "*.JSON"));
|
||||
// fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("all", "*.*"));
|
||||
File cfgFile = fileChooser.showOpenDialog(startStopButton.getScene().getWindow());
|
||||
|
||||
if (cfgFile != null) {
|
||||
setConfig(MetaFileReader.read(cfgFile));
|
||||
}
|
||||
}
|
||||
|
||||
public void loadTestConfig() throws ControlException {
|
||||
try {
|
||||
Meta testConfig = MetaFileReader
|
||||
.read(new File(getClass().getResource("/config/defaultConfig.xml").toURI()));
|
||||
setConfig(testConfig);
|
||||
} catch (URISyntaxException | IOException | ParseException ex) {
|
||||
throw new Error(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public String getDeviceName() {
|
||||
return "PKT8";
|
||||
}
|
||||
|
||||
public void setConfig(Meta config) throws ControlException {
|
||||
if (config.hasNode("plotConfig")) {
|
||||
Meta plotConfig = MetaUtils.findNodeByValue(config, "plotConfig", "device", getDeviceName());
|
||||
if (plotConfig == null) {
|
||||
plotConfig = config.getNode("plotConfig");
|
||||
}
|
||||
|
||||
setupPlotFrame(plotConfig.getNode("plotFrame", Meta.empty()));
|
||||
}
|
||||
|
||||
if (config.hasNode("device")) {
|
||||
Meta deviceMeta = MetaUtils.findNodeByValue(config, "device", "name", Value.of(getDeviceName()));
|
||||
setupDevice(deviceMeta);
|
||||
} else {
|
||||
setupDevice(config);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Set o reset plot area
|
||||
*/
|
||||
private synchronized void setupPlotFrame(Meta plotFrameMeta) {
|
||||
plottables = new TimePlottableGroup();
|
||||
plottables.setMaxItems(plotFrameMeta.getInt("maxItems", 3000));
|
||||
plottables.setMaxAge(Duration.parse(plotFrameMeta.getString("maxAge", "PT2H")));
|
||||
plotArea.getChildren().clear();
|
||||
plotFrame = new JFreeChartFrame(plotFrameMeta);
|
||||
PlotUtils.setXAxis(plotFrame, "timestamp", null, "time");
|
||||
PlotContainer container = PlotContainer.anchorTo(plotArea);
|
||||
container.setPlot(plotFrame);
|
||||
}
|
||||
|
||||
public void setupDevice(Meta deviceMeta) throws ControlException {
|
||||
if (device != null) {
|
||||
device.stopMeasurement(true);
|
||||
device.shutdown();
|
||||
}
|
||||
|
||||
this.device = new PKT8Device(deviceMeta.getString("port", "virtual"));
|
||||
|
||||
device.configure(deviceMeta);
|
||||
|
||||
device.addDeviceListener(this);
|
||||
consoleFragment.addLogHandler(device.getLogger());
|
||||
|
||||
device.init();
|
||||
}
|
||||
|
||||
private void setupChannels() {
|
||||
Collection<PKT8Channel> channels = this.device.getChanels();
|
||||
|
||||
//plot config from device configuration
|
||||
//Do not use view config here, it is applyed separately
|
||||
channels.stream()
|
||||
.filter(channel -> !plottables.hasPlottable(channel.getName()))
|
||||
.forEach(channel -> {
|
||||
|
||||
//plot config from device configuration
|
||||
Meta deviceLineMeta = channel.meta().getNode("plot", channel.meta());
|
||||
|
||||
//Do not use view config here, it is applyed separately
|
||||
TimePlottable plottable = new TimePlottable(channel.getName());
|
||||
plottable.configure(deviceLineMeta);
|
||||
plottables.addPlottable(plottable);
|
||||
plotFrame.add(plottable);
|
||||
});
|
||||
plottables.applyConfig(plotFrame.getConfig());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyDeviceInitialized(Device device) {
|
||||
setupChannels();
|
||||
startStopButton.setDisable(false);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void notifyDeviceShutdown(Device device) {
|
||||
startStopButton.setDisable(true);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public synchronized void onMeasurementResult(Measurement<PKT8Result> measurement, PKT8Result result, Instant time) {
|
||||
//PENDING replace by connection?
|
||||
if (rawDataButton.isSelected()) {
|
||||
plottables.put(result.channel, result.rawValue);
|
||||
} else {
|
||||
plottables.put(result.channel, result.temperature);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMeasurementFailed(Measurement measurement, Throwable exception) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyDeviceStateChanged(Device device, String name, Value state) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void evaluateDeviceException(Device device, String message, Throwable exception) {
|
||||
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void onStartStopClick(ActionEvent event) {
|
||||
if (device != null) {
|
||||
try {
|
||||
if (startStopButton.isSelected()) {
|
||||
device.startMeasurement()
|
||||
.addListener(this);
|
||||
} else {
|
||||
//in case device started
|
||||
if (device.isMeasuring()) {
|
||||
device.getMeasurement().removeListener(this);
|
||||
device.stopMeasurement(false);
|
||||
}
|
||||
}
|
||||
} catch (ControlException ex) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,145 @@
|
||||
/*
|
||||
* 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.cryotemp;
|
||||
|
||||
import hep.dataforge.control.measurements.Measurement;
|
||||
import hep.dataforge.control.measurements.MeasurementListener;
|
||||
import hep.dataforge.meta.Meta;
|
||||
import hep.dataforge.meta.MetaUtils;
|
||||
import hep.dataforge.plots.PlotUtils;
|
||||
import hep.dataforge.plots.data.TimePlottable;
|
||||
import hep.dataforge.plots.data.TimePlottableGroup;
|
||||
import hep.dataforge.plots.data.XYPlottable;
|
||||
import hep.dataforge.plots.fx.FXPlotFrame;
|
||||
import hep.dataforge.plots.fx.PlotContainer;
|
||||
import hep.dataforge.plots.jfreechart.JFreeChartFrame;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.Initializable;
|
||||
import javafx.scene.control.ToggleButton;
|
||||
import javafx.scene.layout.AnchorPane;
|
||||
|
||||
import java.net.URL;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Collection;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
/**
|
||||
* FXML Controller class
|
||||
*
|
||||
* @author darksnake
|
||||
*/
|
||||
public class PKT8PlotController implements Initializable, MeasurementListener<PKT8Result> {
|
||||
|
||||
private final PKT8Device device;
|
||||
private FXPlotFrame<XYPlottable> plotFrame;
|
||||
private TimePlottableGroup plottables;
|
||||
|
||||
@FXML
|
||||
private ToggleButton rawDataButton;
|
||||
@FXML
|
||||
private AnchorPane plotArea;
|
||||
|
||||
public PKT8PlotController(PKT8Device device) {
|
||||
this.device = device;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the controller class.
|
||||
*/
|
||||
@Override
|
||||
public void initialize(URL url, ResourceBundle rb) {
|
||||
rawDataButton.selectedProperty().addListener(observable -> {
|
||||
if (plotFrame != null) {
|
||||
setupPlotFrame(plotFrame.getConfig());
|
||||
if (device != null) {
|
||||
setupChannels();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
configure(device.getConfig());
|
||||
setupChannels();
|
||||
}
|
||||
|
||||
public String getDeviceName() {
|
||||
return device.getName();
|
||||
}
|
||||
|
||||
public void configure(Meta config) {
|
||||
if (config.hasNode("plotConfig")) {
|
||||
Meta plotConfig = MetaUtils.findNodeByValue(config, "plotConfig", "device", getDeviceName());
|
||||
if (plotConfig == null) {
|
||||
plotConfig = config.getNode("plotConfig");
|
||||
}
|
||||
|
||||
setupPlotFrame(plotConfig.getNode("plotFrame", Meta.empty()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set o reset plot area
|
||||
*/
|
||||
private synchronized void setupPlotFrame(Meta plotFrameMeta) {
|
||||
plottables = new TimePlottableGroup();
|
||||
plottables.setMaxItems(plotFrameMeta.getInt("maxItems", 3000));
|
||||
plottables.setMaxAge(Duration.parse(plotFrameMeta.getString("maxAge", "PT2H")));
|
||||
plotArea.getChildren().clear();
|
||||
plotFrame = new JFreeChartFrame(plotFrameMeta);
|
||||
PlotUtils.setXAxis(plotFrame, "timestamp", null, "time");
|
||||
PlotContainer container = PlotContainer.anchorTo(plotArea);
|
||||
container.setPlot(plotFrame);
|
||||
}
|
||||
|
||||
private void setupChannels() {
|
||||
Collection<PKT8Channel> channels = this.device.getChanels();
|
||||
|
||||
//plot config from device configuration
|
||||
//Do not use view config here, it is applyed separately
|
||||
channels.stream()
|
||||
.filter(channel -> !plottables.hasPlottable(channel.getName()))
|
||||
.forEach(channel -> {
|
||||
|
||||
//plot config from device configuration
|
||||
Meta deviceLineMeta = channel.meta().getNode("plot", channel.meta());
|
||||
|
||||
//Do not use view config here, it is applyed separately
|
||||
TimePlottable plottable = new TimePlottable(channel.getName());
|
||||
plottable.configure(deviceLineMeta);
|
||||
plottables.addPlottable(plottable);
|
||||
plotFrame.add(plottable);
|
||||
});
|
||||
plottables.applyConfig(plotFrame.getConfig());
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void onMeasurementResult(Measurement<PKT8Result> measurement, PKT8Result result, Instant time) {
|
||||
//PENDING replace by connection?
|
||||
if (rawDataButton.isSelected()) {
|
||||
plottables.put(result.channel, result.rawValue);
|
||||
} else {
|
||||
plottables.put(result.channel, result.temperature);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMeasurementFailed(Measurement measurement, Throwable exception) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
package inr.numass.cryotemp;
|
||||
|
||||
import hep.dataforge.fx.FXFragment;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.scene.Parent;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.stage.Stage;
|
||||
import javafx.stage.Window;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Created by darksnake on 07-Oct-16.
|
||||
*/
|
||||
public class PKT8PlotFragment extends FXFragment {
|
||||
private final PKT8Device device;
|
||||
private PKT8PlotController plotController;
|
||||
|
||||
public PKT8PlotFragment(PKT8Device device) {
|
||||
this.device = device;
|
||||
}
|
||||
|
||||
public PKT8PlotFragment(Window window, PKT8Device device) {
|
||||
super(window);
|
||||
this.device = device;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Stage buildStage(Parent root) {
|
||||
Stage stage = new Stage();
|
||||
Scene scene = new Scene(root, 600, 400);
|
||||
|
||||
|
||||
stage.setTitle("PKT8 cryogenic temperature viewer");
|
||||
stage.setScene(scene);
|
||||
stage.setMinHeight(400);
|
||||
stage.setMinWidth(600);
|
||||
stage.sizeToScene();
|
||||
|
||||
return stage;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Parent getRoot() {
|
||||
FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/PKT8Plot.fxml"));
|
||||
plotController = new PKT8PlotController(device);
|
||||
loader.setController(plotController);
|
||||
try {
|
||||
return loader.load();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onShow() {
|
||||
super.onShow();
|
||||
if (device.isMeasuring()) {
|
||||
device.getMeasurement().addListener(plotController);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onHide() {
|
||||
super.onHide();
|
||||
if (device.isMeasuring()) {
|
||||
device.getMeasurement().removeListener(plotController);
|
||||
}
|
||||
}
|
||||
}
|
@ -31,4 +31,15 @@ public class PKT8Result {
|
||||
this.temperature = temperature;
|
||||
}
|
||||
|
||||
public String getChannel() {
|
||||
return channel;
|
||||
}
|
||||
|
||||
public String getRawString() {
|
||||
return String.format("%.2f", rawValue);
|
||||
}
|
||||
|
||||
public String getTemperatureString() {
|
||||
return String.format("%.2f", temperature);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.scene.control.*?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
<?import javafx.scene.text.Font?>
|
||||
<BorderPane xmlns:fx="http://javafx.com/fxml/1" prefHeight="400.0" prefWidth="400.0"
|
||||
xmlns="http://javafx.com/javafx/8.0.60">
|
||||
<center>
|
||||
<TableView fx:id="table" BorderPane.alignment="CENTER">
|
||||
<columns>
|
||||
<TableColumn fx:id="sensorColumn" prefWidth="75.0" text="Sensor"/>
|
||||
<TableColumn fx:id="resColumn" prefWidth="75.0" text="Resistance"/>
|
||||
<TableColumn fx:id="tempColumn" prefWidth="116.0" text="Temperature"/>
|
||||
</columns>
|
||||
<columnResizePolicy>
|
||||
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY"/>
|
||||
</columnResizePolicy>
|
||||
</TableView>
|
||||
</center>
|
||||
<top>
|
||||
<ToolBar prefHeight="40.0" prefWidth="200.0" BorderPane.alignment="CENTER">
|
||||
<items>
|
||||
<ToggleButton fx:id="startStopButton" mnemonicParsing="false" onAction="#onStartStopClick"
|
||||
text="Start"/>
|
||||
<Separator orientation="VERTICAL"/>
|
||||
<Pane HBox.hgrow="ALWAYS"/>
|
||||
<Separator orientation="VERTICAL"/>
|
||||
<ToggleButton fx:id="plotButton" mnemonicParsing="false" text="Plot"/>
|
||||
<ToggleButton fx:id="consoleButton" mnemonicParsing="false" text="Console"/>
|
||||
</items>
|
||||
</ToolBar>
|
||||
</top>
|
||||
<bottom>
|
||||
<ToolBar prefHeight="40.0" prefWidth="200.0" BorderPane.alignment="CENTER">
|
||||
<items>
|
||||
<Label text="Last update: "/>
|
||||
<Label fx:id="lastUpdateLabel" text="NONE">
|
||||
<font>
|
||||
<Font name="System Bold" size="12.0"/>
|
||||
</font>
|
||||
</Label>
|
||||
</items>
|
||||
</ToolBar>
|
||||
</bottom>
|
||||
</BorderPane>
|
@ -16,23 +16,22 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<?import javafx.scene.control.*?>
|
||||
<?import javafx.scene.control.Separator?>
|
||||
<?import javafx.scene.control.ToggleButton?>
|
||||
<?import javafx.scene.control.ToolBar?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
<BorderPane prefHeight="600.0" prefWidth="800.0" xmlns="http://javafx.com/javafx/8.0.60"
|
||||
xmlns:fx="http://javafx.com/fxml/1" fx:controller="inr.numass.cryotemp.PKT8MainViewController">
|
||||
<BorderPane xmlns:fx="http://javafx.com/fxml/1" prefHeight="600.0" prefWidth="800.0"
|
||||
xmlns="http://javafx.com/javafx/8.0.60">
|
||||
<center>
|
||||
<AnchorPane fx:id="plotArea"/>
|
||||
</center>
|
||||
<top>
|
||||
<ToolBar BorderPane.alignment="CENTER">
|
||||
<items>
|
||||
<ToggleButton fx:id="startStopButton" disable="true" mnemonicParsing="false"
|
||||
onAction="#onStartStopClick" prefWidth="50.0" text="Start"/>
|
||||
<ToggleButton fx:id="rawDataButton" mnemonicParsing="false" text="Raw data"/>
|
||||
<Separator orientation="VERTICAL"/>
|
||||
<Pane HBox.hgrow = "ALWAYS"/>
|
||||
<Pane HBox.hgrow="ALWAYS"/>
|
||||
<Separator orientation="VERTICAL"/>
|
||||
<ToggleButton fx:id="consoleButton" contentDisplay="CENTER" mnemonicParsing="false" text="Console"/>
|
||||
</items>
|
||||
</ToolBar>
|
||||
</top>
|
@ -20,7 +20,7 @@ import inr.numass.server.NumassServer
|
||||
import inr.numass.storage.NumassStorage
|
||||
import org.apache.commons.vfs2.FileObject
|
||||
|
||||
String path = "D:\\temp\\test\\numass-server\\"
|
||||
String path = "D:\\temp\\test\\numass\\"
|
||||
|
||||
FileObject file = VFSUtils.getLocalFile(new File(path))
|
||||
|
||||
|
@ -51,7 +51,7 @@ public class NumassStorageHandler extends StorageRatpackHandler {
|
||||
|
||||
List<String> notes = getNotes(noteLoader).limit(100).map(note -> render(note)).collect(Collectors.toList());
|
||||
|
||||
Map data = new HashMap(2);
|
||||
Map<String, Object> data = new HashMap<>(2);
|
||||
data.put("notes", notes);
|
||||
|
||||
StringWriter writer = new StringWriter();
|
||||
|
Loading…
Reference in New Issue
Block a user