Numass control room global update
This commit is contained in:
parent
c160fcdea4
commit
0bc03b6053
@ -16,7 +16,7 @@ dependencies {
|
|||||||
|
|
||||||
task debug(dependsOn: classes, type: JavaExec) {
|
task debug(dependsOn: classes, type: JavaExec) {
|
||||||
main mainClass
|
main mainClass
|
||||||
args "--config.resource=/config-debug/devices.xml"
|
args = ["--config.resource=/config-debug/devices.xml"]
|
||||||
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"
|
||||||
@ -24,7 +24,7 @@ task debug(dependsOn: classes, type: JavaExec) {
|
|||||||
|
|
||||||
task testRun(dependsOn: classes, type: JavaExec) {
|
task testRun(dependsOn: classes, type: JavaExec) {
|
||||||
main mainClass
|
main mainClass
|
||||||
args(["--config=D:/temp/test/numass-devices.xml", "--device=thermo-1"])
|
args = ["--config=D:/temp/test/numass-devices.xml", "--device=thermo-1"]
|
||||||
classpath = sourceSets.main.runtimeClasspath
|
classpath = sourceSets.main.runtimeClasspath
|
||||||
description "Start application using real device"
|
description "Start application using real device"
|
||||||
group "debug"
|
group "debug"
|
||||||
|
@ -1,53 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2015 Alexander Nozik.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package inr.numass.control.cryotemp;
|
|
||||||
|
|
||||||
import hep.dataforge.control.devices.DeviceFactory;
|
|
||||||
import hep.dataforge.meta.Meta;
|
|
||||||
import inr.numass.control.DeviceViewConnection;
|
|
||||||
import inr.numass.control.NumassControlApplication;
|
|
||||||
import javafx.stage.Stage;
|
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author darksnake
|
|
||||||
*/
|
|
||||||
public class PKT8App extends NumassControlApplication<PKT8Device> {
|
|
||||||
@Override
|
|
||||||
protected DeviceViewConnection<PKT8Device> buildView(PKT8Device device) {
|
|
||||||
return PKT8ViewConnection.build(device.getContext());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected DeviceFactory getDeviceFactory() {
|
|
||||||
return new PKT8DeviceFactory();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void setupStage(Stage stage, PKT8Device device) {
|
|
||||||
stage.setTitle("Numass temperature view " + device.getName());
|
|
||||||
stage.setMinHeight(400);
|
|
||||||
stage.setMinWidth(400);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean acceptDevice(Meta meta) {
|
|
||||||
return Objects.equals(meta.getString("type"), "PKT8");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
@ -22,6 +22,6 @@ public class PKT8DeviceFactory implements DeviceViewFactory {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DeviceViewConnection buildView(Device device) {
|
public DeviceViewConnection buildView(Device device) {
|
||||||
return PKT8ViewConnection.build(device.getContext());
|
return new PKT8ViewConnection();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,35 +0,0 @@
|
|||||||
package inr.numass.control.cryotemp;
|
|
||||||
|
|
||||||
import hep.dataforge.control.connections.Roles;
|
|
||||||
import hep.dataforge.fx.fragments.FXFragment;
|
|
||||||
import javafx.fxml.FXMLLoader;
|
|
||||||
import javafx.scene.Parent;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by darksnake on 07-Oct-16.
|
|
||||||
*/
|
|
||||||
public class PKT8PlotFragment extends FXFragment {
|
|
||||||
private PKT8PlotView plotController;
|
|
||||||
|
|
||||||
public PKT8PlotFragment(PKT8Device device) {
|
|
||||||
super("PKT8 cryogenic temperature viewer", 600, 400);
|
|
||||||
|
|
||||||
try {
|
|
||||||
FXMLLoader loader = new FXMLLoader(device.getContext().getClassLoader().getResource("fxml/PKT8Plot.fxml"));
|
|
||||||
loader.setClassLoader(device.getContext().getClassLoader());
|
|
||||||
loader.load();
|
|
||||||
plotController = loader.getController();
|
|
||||||
device.connect(plotController, Roles.VIEW_ROLE);
|
|
||||||
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Parent buildRoot() {
|
|
||||||
return plotController.getPane();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,144 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2015 Alexander Nozik.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package inr.numass.control.cryotemp;
|
|
||||||
|
|
||||||
import hep.dataforge.control.measurements.Measurement;
|
|
||||||
import hep.dataforge.control.measurements.MeasurementListener;
|
|
||||||
import hep.dataforge.meta.Meta;
|
|
||||||
import hep.dataforge.plots.PlotUtils;
|
|
||||||
import hep.dataforge.plots.data.TimePlottable;
|
|
||||||
import hep.dataforge.plots.data.TimePlottableGroup;
|
|
||||||
import hep.dataforge.plots.fx.FXPlotFrame;
|
|
||||||
import hep.dataforge.plots.fx.PlotContainer;
|
|
||||||
import hep.dataforge.plots.jfreechart.JFreeChartFrame;
|
|
||||||
import inr.numass.control.DeviceViewConnection;
|
|
||||||
import javafx.fxml.FXML;
|
|
||||||
import javafx.fxml.Initializable;
|
|
||||||
import javafx.scene.Node;
|
|
||||||
import javafx.scene.control.ToggleButton;
|
|
||||||
import javafx.scene.layout.AnchorPane;
|
|
||||||
import javafx.scene.layout.BorderPane;
|
|
||||||
|
|
||||||
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 PKT8PlotView extends DeviceViewConnection<PKT8Device> implements Initializable, MeasurementListener {
|
|
||||||
|
|
||||||
private FXPlotFrame plotFrame;
|
|
||||||
private TimePlottableGroup plottables;
|
|
||||||
|
|
||||||
@FXML
|
|
||||||
private BorderPane root;
|
|
||||||
@FXML
|
|
||||||
private ToggleButton rawDataButton;
|
|
||||||
@FXML
|
|
||||||
private AnchorPane plotArea;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes the controller class.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void initialize(URL url, ResourceBundle rb) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void open(PKT8Device device) throws Exception {
|
|
||||||
super.open(device);
|
|
||||||
rawDataButton.selectedProperty().addListener(observable -> {
|
|
||||||
if (plotFrame != null) {
|
|
||||||
setupPlotFrame(plotFrame.getConfig());
|
|
||||||
if (device != null) {
|
|
||||||
setupChannels(device);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
setupPlotFrame(device.meta().getMetaOrEmpty("plot.frame"));
|
|
||||||
setupChannels(device);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() throws Exception {
|
|
||||||
super.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set o reset plot area
|
|
||||||
*/
|
|
||||||
private synchronized void setupPlotFrame(Meta plotFrameMeta) {
|
|
||||||
plottables = new TimePlottableGroup();
|
|
||||||
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(PKT8Device device) {
|
|
||||||
Collection<PKT8Channel> channels = device.getChanels();
|
|
||||||
|
|
||||||
//plot config from device configuration
|
|
||||||
//Do not use view config here, it is applyed separately
|
|
||||||
channels.stream()
|
|
||||||
.filter(channel -> !plottables.has(channel.getName()))
|
|
||||||
.forEachOrdered(channel -> {
|
|
||||||
//plot config from device configuration
|
|
||||||
TimePlottable plottable = new TimePlottable(channel.getName());
|
|
||||||
plottable.configure(channel.meta());
|
|
||||||
plottables.add(plottable);
|
|
||||||
plotFrame.add(plottable);
|
|
||||||
});
|
|
||||||
if (device.meta().hasMeta("plotConfig")) {
|
|
||||||
plottables.applyConfig(device.meta().getMeta("plotConfig"));
|
|
||||||
plottables.setMaxItems(1000);
|
|
||||||
plottables.setPrefItems(400);
|
|
||||||
}
|
|
||||||
// getPlottables.applyConfig(plotFrame.getConfig());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized void onMeasurementResult(Measurement measurement, Object result, Instant time) {
|
|
||||||
PKT8Result res = PKT8Result.class.cast(result);
|
|
||||||
//PENDING replace by connection?
|
|
||||||
if (rawDataButton.isSelected()) {
|
|
||||||
plottables.put(res.getChannel(), res.getRawValue());
|
|
||||||
} else {
|
|
||||||
plottables.put(res.getChannel(), res.getTemperature());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onMeasurementFailed(Measurement measurement, Throwable exception) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Node getFXNode() {
|
|
||||||
return root;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,150 +0,0 @@
|
|||||||
package inr.numass.control.cryotemp;
|
|
||||||
|
|
||||||
import hep.dataforge.context.Context;
|
|
||||||
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.fragments.FragmentWindow;
|
|
||||||
import hep.dataforge.fx.fragments.LogFragment;
|
|
||||||
import inr.numass.control.DeviceViewConnection;
|
|
||||||
import javafx.application.Platform;
|
|
||||||
import javafx.event.ActionEvent;
|
|
||||||
import javafx.fxml.FXML;
|
|
||||||
import javafx.fxml.FXMLLoader;
|
|
||||||
import javafx.fxml.Initializable;
|
|
||||||
import javafx.scene.Node;
|
|
||||||
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 javafx.scene.layout.BorderPane;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.time.Instant;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.ResourceBundle;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by darksnake on 07-Oct-16.
|
|
||||||
*/
|
|
||||||
public class PKT8View extends DeviceViewConnection<PKT8Device> implements Initializable, MeasurementListener {
|
|
||||||
|
|
||||||
public static PKT8ViewConnection build(Context context) {
|
|
||||||
try {
|
|
||||||
FXMLLoader loader = new FXMLLoader(context.getClassLoader().getResource("fxml/PKT8Indicator.fxml"));
|
|
||||||
loader.setClassLoader(context.getClassLoader());
|
|
||||||
loader.load();
|
|
||||||
return loader.getController();
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new Error(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private LogFragment logFragment;
|
|
||||||
private PKT8PlotFragment plotFragment;
|
|
||||||
|
|
||||||
@FXML
|
|
||||||
private BorderPane root;
|
|
||||||
@FXML
|
|
||||||
private ToggleButton startStopButton;
|
|
||||||
@FXML
|
|
||||||
private ToggleButton storeButton;
|
|
||||||
@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;
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void initialize(URL location, ResourceBundle resources) {
|
|
||||||
sensorColumn.setCellValueFactory(new PropertyValueFactory<>("channel"));
|
|
||||||
resColumn.setCellValueFactory(new PropertyValueFactory<>("rawString"));
|
|
||||||
tempColumn.setCellValueFactory(new PropertyValueFactory<>("temperatureString"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void open(@NotNull PKT8Device device) throws Exception {
|
|
||||||
super.open(device);
|
|
||||||
|
|
||||||
this.logFragment = new LogFragment();
|
|
||||||
logFragment.addRootLogHandler();
|
|
||||||
new FragmentWindow(logFragment).bindTo(consoleButton);
|
|
||||||
|
|
||||||
|
|
||||||
plotFragment = new PKT8PlotFragment(device);
|
|
||||||
startStopButton.selectedProperty().setValue(getDevice().isMeasuring());
|
|
||||||
|
|
||||||
new FragmentWindow(plotFragment).bindTo(plotButton);
|
|
||||||
bindBooleanToState("storing", storeButton.selectedProperty());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() throws Exception {
|
|
||||||
super.close();
|
|
||||||
logFragment = null;
|
|
||||||
plotFragment = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onMeasurementResult(Measurement<?> measurement, Object result, Instant time) {
|
|
||||||
PKT8Result res = PKT8Result.class.cast(result);
|
|
||||||
Platform.runLater(() -> {
|
|
||||||
lastUpdateLabel.setText(time.toString());
|
|
||||||
table.getItems().removeIf(it -> it.getChannel().equals(res.getChannel()));
|
|
||||||
table.getItems().add(res);
|
|
||||||
table.getItems().sort(Comparator.comparing(PKT8Result::getChannel));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onMeasurementFailed(Measurement measurement, Throwable exception) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void startMeasurement() throws MeasurementException {
|
|
||||||
getDevice().startMeasurement();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void stopMeasurement() throws MeasurementException {
|
|
||||||
if (getDevice().isMeasuring()) {
|
|
||||||
getDevice().stopMeasurement(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@FXML
|
|
||||||
private void onStartStopClick(ActionEvent event) {
|
|
||||||
if (getDevice() != null) {
|
|
||||||
try {
|
|
||||||
if (startStopButton.isSelected()) {
|
|
||||||
startMeasurement();
|
|
||||||
} else {
|
|
||||||
//in case device started
|
|
||||||
stopMeasurement();
|
|
||||||
}
|
|
||||||
} catch (ControlException ex) {
|
|
||||||
getDevice().getLogger().error("Failed to start or stop device", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Node getFXNode() {
|
|
||||||
return root;
|
|
||||||
}
|
|
||||||
}
|
|
@ -27,7 +27,7 @@ public class PKT8VirtualPort extends VirtualPort implements Metoid {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void evaluateRequest(String request) {
|
protected synchronized void evaluateRequest(String request) {
|
||||||
switch (request) {
|
switch (request) {
|
||||||
case "s":
|
case "s":
|
||||||
String[] letters = {"a", "b", "c", "d", "e", "f", "g", "h"};
|
String[] letters = {"a", "b", "c", "d", "e", "f", "g", "h"};
|
||||||
@ -48,16 +48,15 @@ public class PKT8VirtualPort extends VirtualPort implements Metoid {
|
|||||||
() -> {
|
() -> {
|
||||||
double res = average + generator.nextGaussian() * sigma;
|
double res = average + generator.nextGaussian() * sigma;
|
||||||
//TODO convert double value to formatted string
|
//TODO convert double value to formatted string
|
||||||
return letter + "000120000\n";
|
return String.format("%s000%d", letter, (int) (res * 100));
|
||||||
},
|
},
|
||||||
Duration.ZERO, Duration.ofMillis(200), letter, "measurement"
|
Duration.ZERO, Duration.ofMillis(500), letter, "measurement"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case "p":
|
case "p":
|
||||||
cancelByTag("measurement");
|
cancelByTag("measurement");
|
||||||
this.recievePhrase("stopped\n\r");
|
this.receivePhrase("Stopped");
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 Alexander Nozik.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package inr.numass.control.cryotemp
|
||||||
|
|
||||||
|
import hep.dataforge.control.connections.Roles
|
||||||
|
import hep.dataforge.control.devices.DeviceFactory
|
||||||
|
import hep.dataforge.meta.Meta
|
||||||
|
import inr.numass.control.DeviceViewConnection
|
||||||
|
import inr.numass.control.NumassControlApplication
|
||||||
|
import javafx.stage.Stage
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author darksnake
|
||||||
|
*/
|
||||||
|
class PKT8App : NumassControlApplication<PKT8Device>() {
|
||||||
|
override fun buildView(device: PKT8Device): DeviceViewConnection<PKT8Device> {
|
||||||
|
return PKT8ViewConnection().apply {
|
||||||
|
device.connect(this, Roles.VIEW_ROLE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override val deviceFactory: DeviceFactory = PKT8DeviceFactory()
|
||||||
|
|
||||||
|
override fun setupStage(stage: Stage, device: PKT8Device) {
|
||||||
|
stage.title = "Numass temperature view " + device.name
|
||||||
|
stage.minHeight = 400.0
|
||||||
|
stage.minWidth = 400.0
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun acceptDevice(meta: Meta): Boolean {
|
||||||
|
return meta.getString("type") == "PKT8"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -13,11 +13,13 @@ import hep.dataforge.plots.fx.FXPlotFrame
|
|||||||
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 inr.numass.control.DeviceViewConnection
|
import inr.numass.control.DeviceViewConnection
|
||||||
|
import inr.numass.control.bindView
|
||||||
import javafx.application.Platform
|
import javafx.application.Platform
|
||||||
|
import javafx.beans.binding.ListBinding
|
||||||
import javafx.beans.property.SimpleObjectProperty
|
import javafx.beans.property.SimpleObjectProperty
|
||||||
import javafx.collections.FXCollections
|
import javafx.collections.FXCollections
|
||||||
import javafx.collections.ListChangeListener
|
import javafx.collections.MapChangeListener
|
||||||
import javafx.collections.transformation.SortedList
|
import javafx.collections.ObservableList
|
||||||
import javafx.geometry.Orientation
|
import javafx.geometry.Orientation
|
||||||
import javafx.scene.Node
|
import javafx.scene.Node
|
||||||
import javafx.scene.Parent
|
import javafx.scene.Parent
|
||||||
@ -33,10 +35,11 @@ import java.time.Instant
|
|||||||
* Created by darksnake on 30-May-17.
|
* Created by darksnake on 30-May-17.
|
||||||
*/
|
*/
|
||||||
class PKT8ViewConnection : DeviceViewConnection<PKT8Device>(), MeasurementListener {
|
class PKT8ViewConnection : DeviceViewConnection<PKT8Device>(), MeasurementListener {
|
||||||
private val view by lazy { CryoView() }
|
private val cryoView by lazy{ CryoView()}
|
||||||
internal val table = SortedList(FXCollections.observableArrayList<PKT8Result>()) { r1, r2 ->
|
private val plotView by lazy { CryoPlotView()}
|
||||||
r1.channel.compareTo(r2.channel)
|
|
||||||
}
|
internal val table = FXCollections.observableHashMap<String, PKT8Result>()
|
||||||
|
|
||||||
|
|
||||||
val lastUpdateProperty = SimpleObjectProperty<String>("NEVER")
|
val lastUpdateProperty = SimpleObjectProperty<String>("NEVER")
|
||||||
|
|
||||||
@ -48,23 +51,21 @@ class PKT8ViewConnection : DeviceViewConnection<PKT8Device>(), MeasurementListen
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun getFXNode(): Node {
|
override fun getFXNode(): Node {
|
||||||
return view.root;
|
if (!isOpen) {
|
||||||
|
throw RuntimeException("Not connected!")
|
||||||
|
}
|
||||||
|
return cryoView.root;
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onMeasurementFailed(measurement: Measurement<*>, exception: Throwable) {
|
override fun onMeasurementFailed(measurement: Measurement<*>, exception: Throwable) {
|
||||||
throw exception;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onMeasurementResult(measurement: Measurement<*>, result: Any, time: Instant) {
|
override fun onMeasurementResult(measurement: Measurement<*>, result: Any, time: Instant) {
|
||||||
if (result is PKT8Result) {
|
if (result is PKT8Result) {
|
||||||
Platform.runLater {
|
Platform.runLater {
|
||||||
lastUpdateProperty.set(time.toString())
|
lastUpdateProperty.set(time.toString())
|
||||||
val item = table.find { it.channel == result.channel };
|
table.put(result.channel, result);
|
||||||
if (item == null) {
|
|
||||||
table.add(result);
|
|
||||||
} else {
|
|
||||||
table[table.indexOf(item)] = result
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -74,9 +75,11 @@ class PKT8ViewConnection : DeviceViewConnection<PKT8Device>(), MeasurementListen
|
|||||||
top {
|
top {
|
||||||
toolbar {
|
toolbar {
|
||||||
togglebutton("Measure") {
|
togglebutton("Measure") {
|
||||||
|
isSelected = false
|
||||||
bindBooleanToState(Sensor.MEASURING_STATE, selectedProperty())
|
bindBooleanToState(Sensor.MEASURING_STATE, selectedProperty())
|
||||||
}
|
}
|
||||||
togglebutton("Store") {
|
togglebutton("Store") {
|
||||||
|
isSelected = false
|
||||||
bindBooleanToState("storing", selectedProperty())
|
bindBooleanToState("storing", selectedProperty())
|
||||||
}
|
}
|
||||||
separator(Orientation.VERTICAL)
|
separator(Orientation.VERTICAL)
|
||||||
@ -85,9 +88,11 @@ class PKT8ViewConnection : DeviceViewConnection<PKT8Device>(), MeasurementListen
|
|||||||
}
|
}
|
||||||
separator(Orientation.VERTICAL)
|
separator(Orientation.VERTICAL)
|
||||||
togglebutton("Plot") {
|
togglebutton("Plot") {
|
||||||
FragmentWindow(CryoPlotView().root).bindTo(this)
|
isSelected = false
|
||||||
|
bindView(plotView)
|
||||||
}
|
}
|
||||||
togglebutton("Log") {
|
togglebutton("Log") {
|
||||||
|
isSelected = false
|
||||||
FragmentWindow(LogFragment().apply {
|
FragmentWindow(LogFragment().apply {
|
||||||
addLogHandler(device.logger)
|
addLogHandler(device.logger)
|
||||||
}).bindTo(this)
|
}).bindTo(this)
|
||||||
@ -95,12 +100,24 @@ class PKT8ViewConnection : DeviceViewConnection<PKT8Device>(), MeasurementListen
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
center {
|
center {
|
||||||
tableview(table) {
|
tableview<PKT8Result> {
|
||||||
|
items = object : ListBinding<PKT8Result>() {
|
||||||
|
init {
|
||||||
|
bind(table)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun computeValue(): ObservableList<PKT8Result> {
|
||||||
|
return FXCollections.observableArrayList(table.values).apply {
|
||||||
|
sortBy { it.channel }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
column("Sensor", PKT8Result::channel);
|
column("Sensor", PKT8Result::channel);
|
||||||
column("Resistance", PKT8Result::rawValue).cellFormat {
|
column("Resistance", PKT8Result::rawValue).cellFormat {
|
||||||
text = String.format("%.2f", it)
|
text = String.format("%.2f", it)
|
||||||
}
|
}
|
||||||
column("Resistance", PKT8Result::temperature).cellFormat {
|
column("Temperature", PKT8Result::temperature).cellFormat {
|
||||||
text = String.format("%.2f", it)
|
text = String.format("%.2f", it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -116,7 +133,7 @@ class PKT8ViewConnection : DeviceViewConnection<PKT8Device>(), MeasurementListen
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inner class CryoPlotView : View() {
|
inner class CryoPlotView : View("PKT8 temperature plot") {
|
||||||
val plotFrameMeta: Meta = device.meta.getMetaOrEmpty("plotConfig")
|
val plotFrameMeta: Meta = device.meta.getMetaOrEmpty("plotConfig")
|
||||||
|
|
||||||
val plotFrame: FXPlotFrame by lazy {
|
val plotFrame: FXPlotFrame by lazy {
|
||||||
@ -130,27 +147,24 @@ class PKT8ViewConnection : DeviceViewConnection<PKT8Device>(), MeasurementListen
|
|||||||
val plottables: TimePlottableGroup by lazy {
|
val plottables: TimePlottableGroup by lazy {
|
||||||
TimePlottableGroup().apply {
|
TimePlottableGroup().apply {
|
||||||
setMaxAge(Duration.parse(plotFrameMeta.getString("maxAge", "PT2H")))
|
setMaxAge(Duration.parse(plotFrameMeta.getString("maxAge", "PT2H")))
|
||||||
table.addListener(ListChangeListener { change ->
|
|
||||||
while (change.next()) {
|
|
||||||
change.addedSubList.forEach {
|
|
||||||
if (rawDataButton.isSelected()) {
|
|
||||||
plottables.put(it.channel, it.rawValue)
|
|
||||||
} else {
|
|
||||||
plottables.put(it.channel, it.temperature)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override val root: Parent = borderpane {
|
override val root: Parent = borderpane {
|
||||||
|
prefWidth = 800.0
|
||||||
|
prefHeight = 600.0
|
||||||
PlotContainer.centerIn(this).plot = plotFrame
|
PlotContainer.centerIn(this).plot = plotFrame
|
||||||
bottom {
|
top {
|
||||||
rawDataButton = togglebutton("Raw data") {
|
toolbar {
|
||||||
action {
|
rawDataButton = togglebutton("Raw data") {
|
||||||
plottables.forEach {
|
isSelected = false
|
||||||
it.clear()
|
action {
|
||||||
|
clearPlot()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
button("Reset") {
|
||||||
|
action {
|
||||||
|
clearPlot()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -158,7 +172,7 @@ class PKT8ViewConnection : DeviceViewConnection<PKT8Device>(), MeasurementListen
|
|||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val channels = device.chanels
|
val channels = device.chanels
|
||||||
|
|
||||||
//plot config from device configuration
|
//plot config from device configuration
|
||||||
//Do not use view config here, it is applyed separately
|
//Do not use view config here, it is applyed separately
|
||||||
@ -176,6 +190,23 @@ class PKT8ViewConnection : DeviceViewConnection<PKT8Device>(), MeasurementListen
|
|||||||
plottables.setMaxItems(1000)
|
plottables.setMaxItems(1000)
|
||||||
plottables.setPrefItems(400)
|
plottables.setPrefItems(400)
|
||||||
}
|
}
|
||||||
|
table.addListener(MapChangeListener { change ->
|
||||||
|
if (change.wasAdded()) {
|
||||||
|
change.valueAdded.apply {
|
||||||
|
if (rawDataButton.isSelected()) {
|
||||||
|
plottables.put(this.channel, this.rawValue)
|
||||||
|
} else {
|
||||||
|
plottables.put(this.channel, this.temperature)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fun clearPlot() {
|
||||||
|
plottables.forEach {
|
||||||
|
it.clear()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,10 +18,11 @@ package inr.numass.control.magnet;
|
|||||||
import hep.dataforge.control.ports.VirtualPort;
|
import hep.dataforge.control.ports.VirtualPort;
|
||||||
import hep.dataforge.exceptions.PortException;
|
import hep.dataforge.exceptions.PortException;
|
||||||
import hep.dataforge.meta.Meta;
|
import hep.dataforge.meta.Meta;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -69,7 +70,7 @@ public class VirtualLambdaPort extends VirtualPort {
|
|||||||
evaluateRequest(comand.trim(), value.trim());
|
evaluateRequest(comand.trim(), value.trim());
|
||||||
} catch (RuntimeException ex) {
|
} catch (RuntimeException ex) {
|
||||||
|
|
||||||
recievePhrase("FAIL");//TODO какая команда правильная?
|
receivePhrase("FAIL");//TODO какая команда правильная?
|
||||||
LoggerFactory.getLogger(getClass()).error("Request evaluation failure", ex);
|
LoggerFactory.getLogger(getClass()).error("Request evaluation failure", ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
package inr.numass.control
|
package inr.numass.control
|
||||||
|
|
||||||
|
import hep.dataforge.fx.fragments.FXFragment
|
||||||
|
import hep.dataforge.fx.fragments.FragmentWindow
|
||||||
import hep.dataforge.values.Value
|
import hep.dataforge.values.Value
|
||||||
import javafx.beans.value.ObservableValue
|
import javafx.beans.value.ObservableValue
|
||||||
import javafx.event.EventTarget
|
import javafx.event.EventTarget
|
||||||
import javafx.geometry.Orientation
|
import javafx.geometry.Orientation
|
||||||
|
import javafx.scene.control.ToggleButton
|
||||||
import javafx.scene.paint.Color
|
import javafx.scene.paint.Color
|
||||||
import javafx.scene.paint.Paint
|
import javafx.scene.paint.Paint
|
||||||
import javafx.scene.shape.Circle
|
import javafx.scene.shape.Circle
|
||||||
@ -96,3 +99,9 @@ fun EventTarget.deviceStateIndicator(connection: DeviceViewConnection<*>, state:
|
|||||||
separator(Orientation.VERTICAL)
|
separator(Orientation.VERTICAL)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun ToggleButton.bindView(view: View) {
|
||||||
|
//TODO use view instead of FXFragment
|
||||||
|
FragmentWindow(FXFragment.buildFromNode(view.title) { view.root }).bindTo(this)
|
||||||
|
}
|
||||||
|
|
@ -67,7 +67,7 @@ abstract class NumassControlApplication<D : Device> : App() {
|
|||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
val d = deviceFactory.build(ctx, deviceConfig) as D
|
val d = deviceFactory.build(ctx, deviceConfig) as D
|
||||||
d.init()
|
d.init()
|
||||||
connectStorage(d, config)
|
connectStorage(d, config)
|
||||||
@ -80,9 +80,14 @@ abstract class NumassControlApplication<D : Device> : App() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun stop() {
|
override fun stop() {
|
||||||
super.stop()
|
try {
|
||||||
device.shutdown()
|
device.shutdown()
|
||||||
device.context.close()
|
} catch (ex: Exception) {
|
||||||
|
LoggerFactory.getLogger(javaClass).error("Failed to shutdown application", ex);
|
||||||
|
} finally {
|
||||||
|
device.context.close()
|
||||||
|
super.stop()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ class JFCTest : View("My View") {
|
|||||||
override val root = borderpane {
|
override val root = borderpane {
|
||||||
center {
|
center {
|
||||||
container.plot = plot
|
container.plot = plot
|
||||||
add(container.root)
|
add(container.pane)
|
||||||
}
|
}
|
||||||
bottom {
|
bottom {
|
||||||
add(button)
|
add(button)
|
||||||
|
Loading…
Reference in New Issue
Block a user