numass cryotemp update

This commit is contained in:
darksnake 2016-10-07 14:19:01 +03:00
parent 50947c9219
commit f9f605bde0
12 changed files with 544 additions and 332 deletions

View File

@ -21,4 +21,12 @@ task debug(dependsOn: classes, type: JavaExec) {
classpath = sourceSets.main.runtimeClasspath classpath = sourceSets.main.runtimeClasspath
description "Start application in debug mode with default virtual port" description "Start application in debug mode with default virtual port"
group "debug" 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"
} }

View File

@ -16,10 +16,16 @@
package inr.numass.cryotemp; package inr.numass.cryotemp;
import ch.qos.logback.classic.Level; 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.exceptions.ControlException;
import hep.dataforge.io.MetaFileReader; 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 hep.dataforge.storage.commons.StorageManager;
import javafx.application.Application; import javafx.application.Application;
import javafx.application.Platform;
import javafx.fxml.FXMLLoader; import javafx.fxml.FXMLLoader;
import javafx.scene.Parent; import javafx.scene.Parent;
import javafx.scene.Scene; import javafx.scene.Scene;
@ -28,6 +34,7 @@ import org.slf4j.LoggerFactory;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.net.URISyntaxException;
import java.text.ParseException; import java.text.ParseException;
import java.util.Locale; import java.util.Locale;
@ -35,54 +42,10 @@ import java.util.Locale;
* @author darksnake * @author darksnake
*/ */
public class PKT8App extends Application { public class PKT8App extends Application {
public static final String DEFAULT_CONFIG_LOCATION = "numass-devices.xml";
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);
primaryStage.setTitle("PKT8 cryogenic temperature viewer"); PKT8Device device;
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);
}
/** /**
* @param args the command line arguments * @param args the command line arguments
@ -91,4 +54,109 @@ public class PKT8App extends Application {
launch(args); 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();
}
}
} }

View File

@ -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);
}
}
}
}

View File

@ -21,6 +21,7 @@ import hep.dataforge.control.connections.PointListenerConnection;
import hep.dataforge.control.connections.Roles; import hep.dataforge.control.connections.Roles;
import hep.dataforge.control.connections.StorageConnection; import hep.dataforge.control.connections.StorageConnection;
import hep.dataforge.control.devices.PortSensor; import hep.dataforge.control.devices.PortSensor;
import hep.dataforge.control.devices.annotations.RoleDef;
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;
@ -30,8 +31,8 @@ import hep.dataforge.exceptions.PortException;
import hep.dataforge.exceptions.StorageException; import hep.dataforge.exceptions.StorageException;
import hep.dataforge.meta.Meta; import hep.dataforge.meta.Meta;
import hep.dataforge.storage.api.PointLoader; import hep.dataforge.storage.api.PointLoader;
import hep.dataforge.storage.api.Storage;
import hep.dataforge.storage.commons.LoaderFactory; import hep.dataforge.storage.commons.LoaderFactory;
import hep.dataforge.storage.commons.StorageFactory;
import hep.dataforge.tables.DataPoint; import hep.dataforge.tables.DataPoint;
import hep.dataforge.tables.PointListener; import hep.dataforge.tables.PointListener;
import hep.dataforge.tables.TableFormatBuilder; import hep.dataforge.tables.TableFormatBuilder;
@ -39,12 +40,15 @@ import hep.dataforge.tables.TableFormatBuilder;
import java.time.Duration; import java.time.Duration;
import java.time.Instant; import java.time.Instant;
import java.util.*; import java.util.*;
import java.util.stream.Collectors;
/** /**
* A device controller for Dubna PKT 8 cryogenic thermometry device * A device controller for Dubna PKT 8 cryogenic thermometry device
* *
* @author Alexander Nozik * @author Alexander Nozik
*/ */
@RoleDef(name = Roles.STORAGE_ROLE)
@RoleDef(name = Roles.POINT_LISTENER_ROLE)
public class PKT8Device extends PortSensor<PKT8Result> { public class PKT8Device extends PortSensor<PKT8Result> {
public static final String PGA = "pga"; 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 * The key is the letter (a,b,c,d...) as in measurements
*/ */
private final Map<String, PKT8Channel> channels = new HashMap<>(); private final Map<String, PKT8Channel> channels = new HashMap<>();
// private PointLoader pointLoader;
private RegularPointCollector collector; private RegularPointCollector collector;
public PKT8Device(String portName) { public PKT8Device(String portName) {
@ -95,7 +98,7 @@ public class PKT8Device extends PortSensor<PKT8Result> {
setSPS(meta().getInt("sps", 0)); setSPS(meta().getInt("sps", 0));
setBUF(meta().getInt("abuf", 100)); setBUF(meta().getInt("abuf", 100));
setupStorage(); setupLoaders();
} }
@ -240,7 +243,7 @@ public class PKT8Device extends PortSensor<PKT8Result> {
return getState(ABUF).stringValue(); return getState(ABUF).stringValue();
} }
private void setupStorage() { private void setupLoaders() {
// Building data format // Building data format
TableFormatBuilder tableFormatBuilder = new TableFormatBuilder() TableFormatBuilder tableFormatBuilder = new TableFormatBuilder()
@ -252,24 +255,21 @@ public class PKT8Device extends PortSensor<PKT8Result> {
names.add(channel.getName()); 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 // 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()); String suffix = Integer.toString((int) Instant.now().toEpochMilli());
PointLoader pointLoader = null; PointLoader pointLoader = null;
try { try {
pointLoader = LoaderFactory.buildPointLoder(connection.getStorage(), pointLoader = LoaderFactory.buildPointLoder(storage,
"cryotemp_" + suffix, "", "timestamp", tableFormatBuilder.build()); "cryotemp_" + suffix, "", "timestamp", tableFormatBuilder.build());
this.connect(new LoaderConnection(pointLoader), Roles.POINT_LISTENER_ROLE); this.connect(new LoaderConnection(pointLoader), Roles.POINT_LISTENER_ROLE);
} catch (StorageException e) { } 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); }, duration, names);
} }
public void connectPointListener(PointListenerConnection listener){ public void connectPointListener(PointListenerConnection listener) {
this.connect(listener, Roles.POINT_LISTENER_ROLE); this.connect(listener, Roles.POINT_LISTENER_ROLE);
} }
@ -334,6 +334,7 @@ public class PKT8Device extends PortSensor<PKT8Result> {
} }
try { try {
getLogger().info("Starting measurement");
handler.holdBy(this); handler.holdBy(this);
handler.send("s"); handler.send("s");
afterStart(); afterStart();
@ -350,6 +351,7 @@ public class PKT8Device extends PortSensor<PKT8Result> {
} }
try { try {
getLogger().info("Stopping measurement");
String response = getHandler().sendAndWait("p", 400).trim(); String response = getHandler().sendAndWait("p", 400).trim();
// Должно быть именно с большой буквы!!! // Должно быть именно с большой буквы!!!
return "Stopped".equals(response) || "stopped".equals(response); return "Stopped".equals(response) || "stopped".equals(response);
@ -372,7 +374,7 @@ public class PKT8Device extends PortSensor<PKT8Result> {
if (isStarted()) { if (isStarted()) {
if (trimmed.equals("Stopped") || trimmed.equals("stopped")) { if (trimmed.equals("Stopped") || trimmed.equals("stopped")) {
afterPause(); afterPause();
getLogger().info("Measurement stopped"); // getLogger().info("Measurement stopped");
} else { } else {
String designation = trimmed.substring(0, 1); String designation = trimmed.substring(0, 1);
double rawValue = Double.parseDouble(trimmed.substring(1)) / 100; double rawValue = Double.parseDouble(trimmed.substring(1)) / 100;

View File

@ -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) {
}
}
}
}

View File

@ -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) {
}
}

View File

@ -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);
}
}
}

View File

@ -31,4 +31,15 @@ public class PKT8Result {
this.temperature = temperature; this.temperature = temperature;
} }
public String getChannel() {
return channel;
}
public String getRawString() {
return String.format("%.2f", rawValue);
}
public String getTemperatureString() {
return String.format("%.2f", temperature);
}
} }

View File

@ -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>

View File

@ -16,23 +16,22 @@ See the License for the specific language governing permissions and
limitations under the License. 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.*?> <?import javafx.scene.layout.*?>
<BorderPane prefHeight="600.0" prefWidth="800.0" xmlns="http://javafx.com/javafx/8.0.60" <BorderPane xmlns:fx="http://javafx.com/fxml/1" prefHeight="600.0" prefWidth="800.0"
xmlns:fx="http://javafx.com/fxml/1" fx:controller="inr.numass.cryotemp.PKT8MainViewController"> xmlns="http://javafx.com/javafx/8.0.60">
<center> <center>
<AnchorPane fx:id="plotArea"/> <AnchorPane fx:id="plotArea"/>
</center> </center>
<top> <top>
<ToolBar BorderPane.alignment="CENTER"> <ToolBar BorderPane.alignment="CENTER">
<items> <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"/> <ToggleButton fx:id="rawDataButton" mnemonicParsing="false" text="Raw data"/>
<Separator orientation="VERTICAL"/> <Separator orientation="VERTICAL"/>
<Pane HBox.hgrow = "ALWAYS"/> <Pane HBox.hgrow="ALWAYS"/>
<Separator orientation="VERTICAL"/> <Separator orientation="VERTICAL"/>
<ToggleButton fx:id="consoleButton" contentDisplay="CENTER" mnemonicParsing="false" text="Console"/>
</items> </items>
</ToolBar> </ToolBar>
</top> </top>

View File

@ -20,7 +20,7 @@ import inr.numass.server.NumassServer
import inr.numass.storage.NumassStorage import inr.numass.storage.NumassStorage
import org.apache.commons.vfs2.FileObject 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)) FileObject file = VFSUtils.getLocalFile(new File(path))

View File

@ -51,7 +51,7 @@ public class NumassStorageHandler extends StorageRatpackHandler {
List<String> notes = getNotes(noteLoader).limit(100).map(note -> render(note)).collect(Collectors.toList()); 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); data.put("notes", notes);
StringWriter writer = new StringWriter(); StringWriter writer = new StringWriter();