Control to Kotlin!
This commit is contained in:
parent
abb80ba1aa
commit
c160fcdea4
@ -1,11 +1,35 @@
|
|||||||
|
buildscript {
|
||||||
|
ext.kotlin_version = '1.1.2-2'
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
allprojects{
|
||||||
|
apply plugin: "kotlin"
|
||||||
|
|
||||||
|
compileKotlin {
|
||||||
|
kotlinOptions {
|
||||||
|
jvmTarget = "1.8"
|
||||||
|
javaParameters = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile project(':numass-client')
|
compile project(':numass-client')
|
||||||
compile "hep.dataforge:plots-jfc" // project(':dataforge-plots:plots-jfc')
|
compile "hep.dataforge:plots-jfc" // project(':dataforge-plots:plots-jfc')
|
||||||
compile "hep.dataforge:dataforge-control" //project(':dataforge-control')
|
compile "hep.dataforge:dataforge-control" //project(':dataforge-control')
|
||||||
|
compile "hep.dataforge:kodex"
|
||||||
|
|
||||||
// https://mvnrepository.com/artifact/org.controlsfx/controlsfx
|
//graphics
|
||||||
compile group: 'org.controlsfx', name: 'controlsfx', version: '8.40.12'
|
compile 'org.controlsfx:controlsfx:8.40.12'
|
||||||
|
compile "no.tornado:tornadofx:1.7.4"
|
||||||
}
|
}
|
||||||
|
|
||||||
task installAll(type: Copy) {
|
task installAll(type: Copy) {
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
plugins{
|
plugins{
|
||||||
id "org.jetbrains.kotlin.jvm" version '1.1.2-2'
|
|
||||||
id "application"
|
id "application"
|
||||||
id 'com.github.johnrengelman.shadow' version '2.0.0'
|
id 'com.github.johnrengelman.shadow' version '2.0.0'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (!hasProperty('mainClass')) {
|
if (!hasProperty('mainClass')) {
|
||||||
ext.mainClass = 'inr.numass.control.ServerApp'//"inr.numass.viewer.test.TestApp"
|
ext.mainClass = 'inr.numass.control.ServerApp'//"inr.numass.viewer.test.TestApp"
|
||||||
}
|
}
|
||||||
@ -21,11 +21,6 @@ configurations{
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
//graphics
|
|
||||||
compile 'org.controlsfx:controlsfx:8.40.12'
|
|
||||||
compile "no.tornado:tornadofx:1.7.4"
|
|
||||||
compile "org.jetbrains.kotlin:kotlin-stdlib-jre8"
|
|
||||||
|
|
||||||
//DataForge dependencies
|
//DataForge dependencies
|
||||||
compile project(':numass-control')
|
compile project(':numass-control')
|
||||||
compile project(':numass-server')
|
compile project(':numass-server')
|
||||||
|
@ -1,12 +1,6 @@
|
|||||||
package inr.numass.control
|
package inr.numass.control
|
||||||
|
|
||||||
import hep.dataforge.control.devices.Device
|
|
||||||
import hep.dataforge.control.devices.PortSensor
|
|
||||||
import hep.dataforge.control.devices.Sensor
|
|
||||||
import hep.dataforge.fx.fragments.FXFragment
|
|
||||||
import hep.dataforge.fx.fragments.FragmentWindow
|
|
||||||
import hep.dataforge.storage.filestorage.FileStorage
|
import hep.dataforge.storage.filestorage.FileStorage
|
||||||
import inr.numass.control.NumassControlUtils.getDFIcon
|
|
||||||
import javafx.geometry.Orientation
|
import javafx.geometry.Orientation
|
||||||
import javafx.geometry.Pos
|
import javafx.geometry.Pos
|
||||||
import javafx.scene.control.Hyperlink
|
import javafx.scene.control.Hyperlink
|
||||||
@ -17,7 +11,7 @@ import tornadofx.*
|
|||||||
/**
|
/**
|
||||||
* Created by darksnake on 11-May-17.
|
* Created by darksnake on 11-May-17.
|
||||||
*/
|
*/
|
||||||
class BoardView : View("Numass control board", ImageView(getDFIcon())) {
|
class BoardView : View("Numass control board", ImageView(dfIcon)) {
|
||||||
private val controller: BoardController by inject();
|
private val controller: BoardController by inject();
|
||||||
|
|
||||||
override val root = borderpane {
|
override val root = borderpane {
|
||||||
@ -87,23 +81,11 @@ class BoardView : View("Numass control board", ImageView(getDFIcon())) {
|
|||||||
vbox {
|
vbox {
|
||||||
prefHeight = 40.0
|
prefHeight = 40.0
|
||||||
bindChildren(controller.devices) { connection ->
|
bindChildren(controller.devices) { connection ->
|
||||||
titledpane(title = "Device: " + connection.device.name, collapsible = true) {
|
titledpane(
|
||||||
hbox {
|
title = "Device: " + connection.device.name,
|
||||||
alignment = Pos.CENTER_LEFT
|
collapsible = true,
|
||||||
vgrow = Priority.ALWAYS;
|
node = connection.getBoardView()
|
||||||
deviceStateIndicator(connection, Device.INITIALIZED_STATE)
|
)
|
||||||
deviceStateIndicator(connection, PortSensor.CONNECTED_STATE)
|
|
||||||
deviceStateIndicator(connection, Sensor.MEASURING_STATE)
|
|
||||||
deviceStateIndicator(connection, "storing")
|
|
||||||
pane {
|
|
||||||
hgrow = Priority.ALWAYS
|
|
||||||
}
|
|
||||||
togglebutton("View") {
|
|
||||||
isSelected = false
|
|
||||||
FragmentWindow(FXFragment.buildFromNode(connection.device.name) { connection.fxNode }).bindTo(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ import java.util.Objects;
|
|||||||
public class PKT8App extends NumassControlApplication<PKT8Device> {
|
public class PKT8App extends NumassControlApplication<PKT8Device> {
|
||||||
@Override
|
@Override
|
||||||
protected DeviceViewConnection<PKT8Device> buildView(PKT8Device device) {
|
protected DeviceViewConnection<PKT8Device> buildView(PKT8Device device) {
|
||||||
return PKT8View.build(device.getContext());
|
return PKT8ViewConnection.build(device.getContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -22,6 +22,6 @@ public class PKT8DeviceFactory implements DeviceViewFactory {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DeviceViewConnection buildView(Device device) {
|
public DeviceViewConnection buildView(Device device) {
|
||||||
return PKT8View.build(device.getContext());
|
return PKT8ViewConnection.build(device.getContext());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -125,9 +125,9 @@ public class PKT8PlotView extends DeviceViewConnection<PKT8Device> implements In
|
|||||||
PKT8Result res = PKT8Result.class.cast(result);
|
PKT8Result res = PKT8Result.class.cast(result);
|
||||||
//PENDING replace by connection?
|
//PENDING replace by connection?
|
||||||
if (rawDataButton.isSelected()) {
|
if (rawDataButton.isSelected()) {
|
||||||
plottables.put(res.channel, res.rawValue);
|
plottables.put(res.getChannel(), res.getRawValue());
|
||||||
} else {
|
} else {
|
||||||
plottables.put(res.channel, res.temperature);
|
plottables.put(res.getChannel(), res.getTemperature());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ import java.util.ResourceBundle;
|
|||||||
*/
|
*/
|
||||||
public class PKT8View extends DeviceViewConnection<PKT8Device> implements Initializable, MeasurementListener {
|
public class PKT8View extends DeviceViewConnection<PKT8Device> implements Initializable, MeasurementListener {
|
||||||
|
|
||||||
public static PKT8View build(Context context) {
|
public static PKT8ViewConnection build(Context context) {
|
||||||
try {
|
try {
|
||||||
FXMLLoader loader = new FXMLLoader(context.getClassLoader().getResource("fxml/PKT8Indicator.fxml"));
|
FXMLLoader loader = new FXMLLoader(context.getClassLoader().getResource("fxml/PKT8Indicator.fxml"));
|
||||||
loader.setClassLoader(context.getClassLoader());
|
loader.setClassLoader(context.getClassLoader());
|
||||||
@ -104,9 +104,9 @@ public class PKT8View extends DeviceViewConnection<PKT8Device> implements Initia
|
|||||||
PKT8Result res = PKT8Result.class.cast(result);
|
PKT8Result res = PKT8Result.class.cast(result);
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
lastUpdateLabel.setText(time.toString());
|
lastUpdateLabel.setText(time.toString());
|
||||||
table.getItems().removeIf(it -> it.channel.equals(res.channel));
|
table.getItems().removeIf(it -> it.getChannel().equals(res.getChannel()));
|
||||||
table.getItems().add(res);
|
table.getItems().add(res);
|
||||||
table.getItems().sort(Comparator.comparing(o -> o.channel));
|
table.getItems().sort(Comparator.comparing(PKT8Result::getChannel));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,32 +14,14 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package inr.numass.control.cryotemp;
|
package inr.numass.control.cryotemp
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by darksnake on 28-Sep-16.
|
* Created by darksnake on 28-Sep-16.
|
||||||
*/
|
*/
|
||||||
public class PKT8Result {
|
data class PKT8Result(var channel: String, var rawValue: Double, var temperature: Double) {
|
||||||
|
|
||||||
public String channel;
|
val rawString: String = String.format("%.2f", rawValue)
|
||||||
public double rawValue;
|
|
||||||
public double temperature;
|
|
||||||
|
|
||||||
public PKT8Result(String channel, double rawValue, double temperature) {
|
val temperatureString: String = String.format("%.2f", temperature)
|
||||||
this.channel = channel;
|
|
||||||
this.rawValue = rawValue;
|
|
||||||
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,182 @@
|
|||||||
|
package inr.numass.control.cryotemp
|
||||||
|
|
||||||
|
import hep.dataforge.control.devices.Sensor
|
||||||
|
import hep.dataforge.control.measurements.Measurement
|
||||||
|
import hep.dataforge.control.measurements.MeasurementListener
|
||||||
|
import hep.dataforge.fx.fragments.FragmentWindow
|
||||||
|
import hep.dataforge.fx.fragments.LogFragment
|
||||||
|
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.application.Platform
|
||||||
|
import javafx.beans.property.SimpleObjectProperty
|
||||||
|
import javafx.collections.FXCollections
|
||||||
|
import javafx.collections.ListChangeListener
|
||||||
|
import javafx.collections.transformation.SortedList
|
||||||
|
import javafx.geometry.Orientation
|
||||||
|
import javafx.scene.Node
|
||||||
|
import javafx.scene.Parent
|
||||||
|
import javafx.scene.control.ToggleButton
|
||||||
|
import javafx.scene.layout.Priority
|
||||||
|
import javafx.scene.layout.VBox
|
||||||
|
import javafx.scene.text.Font
|
||||||
|
import tornadofx.*
|
||||||
|
import java.time.Duration
|
||||||
|
import java.time.Instant
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by darksnake on 30-May-17.
|
||||||
|
*/
|
||||||
|
class PKT8ViewConnection : DeviceViewConnection<PKT8Device>(), MeasurementListener {
|
||||||
|
private val view by lazy { CryoView() }
|
||||||
|
internal val table = SortedList(FXCollections.observableArrayList<PKT8Result>()) { r1, r2 ->
|
||||||
|
r1.channel.compareTo(r2.channel)
|
||||||
|
}
|
||||||
|
|
||||||
|
val lastUpdateProperty = SimpleObjectProperty<String>("NEVER")
|
||||||
|
|
||||||
|
|
||||||
|
override fun getBoardView(): Parent {
|
||||||
|
return VBox().apply {
|
||||||
|
this += super.getBoardView()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getFXNode(): Node {
|
||||||
|
return view.root;
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onMeasurementFailed(measurement: Measurement<*>, exception: Throwable) {
|
||||||
|
throw exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onMeasurementResult(measurement: Measurement<*>, result: Any, time: Instant) {
|
||||||
|
if (result is PKT8Result) {
|
||||||
|
Platform.runLater {
|
||||||
|
lastUpdateProperty.set(time.toString())
|
||||||
|
val item = table.find { it.channel == result.channel };
|
||||||
|
if (item == null) {
|
||||||
|
table.add(result);
|
||||||
|
} else {
|
||||||
|
table[table.indexOf(item)] = result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class CryoView() : View() {
|
||||||
|
override val root = borderpane {
|
||||||
|
top {
|
||||||
|
toolbar {
|
||||||
|
togglebutton("Measure") {
|
||||||
|
bindBooleanToState(Sensor.MEASURING_STATE, selectedProperty())
|
||||||
|
}
|
||||||
|
togglebutton("Store") {
|
||||||
|
bindBooleanToState("storing", selectedProperty())
|
||||||
|
}
|
||||||
|
separator(Orientation.VERTICAL)
|
||||||
|
pane {
|
||||||
|
hgrow = Priority.ALWAYS
|
||||||
|
}
|
||||||
|
separator(Orientation.VERTICAL)
|
||||||
|
togglebutton("Plot") {
|
||||||
|
FragmentWindow(CryoPlotView().root).bindTo(this)
|
||||||
|
}
|
||||||
|
togglebutton("Log") {
|
||||||
|
FragmentWindow(LogFragment().apply {
|
||||||
|
addLogHandler(device.logger)
|
||||||
|
}).bindTo(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
center {
|
||||||
|
tableview(table) {
|
||||||
|
column("Sensor", PKT8Result::channel);
|
||||||
|
column("Resistance", PKT8Result::rawValue).cellFormat {
|
||||||
|
text = String.format("%.2f", it)
|
||||||
|
}
|
||||||
|
column("Resistance", PKT8Result::temperature).cellFormat {
|
||||||
|
text = String.format("%.2f", it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bottom {
|
||||||
|
toolbar {
|
||||||
|
label("Last update: ")
|
||||||
|
label(lastUpdateProperty) {
|
||||||
|
font = Font.font("System Bold")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class CryoPlotView : View() {
|
||||||
|
val plotFrameMeta: Meta = device.meta.getMetaOrEmpty("plotConfig")
|
||||||
|
|
||||||
|
val plotFrame: FXPlotFrame by lazy {
|
||||||
|
JFreeChartFrame(plotFrameMeta).apply {
|
||||||
|
PlotUtils.setXAxis(this, "timestamp", null, "time")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var rawDataButton: ToggleButton by singleAssign()
|
||||||
|
|
||||||
|
val plottables: TimePlottableGroup by lazy {
|
||||||
|
TimePlottableGroup().apply {
|
||||||
|
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 {
|
||||||
|
PlotContainer.centerIn(this).plot = plotFrame
|
||||||
|
bottom {
|
||||||
|
rawDataButton = togglebutton("Raw data") {
|
||||||
|
action {
|
||||||
|
plottables.forEach {
|
||||||
|
it.clear()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
val channels = device.chanels
|
||||||
|
|
||||||
|
//plot config from device configuration
|
||||||
|
//Do not use view config here, it is applyed separately
|
||||||
|
channels.stream()
|
||||||
|
.filter { channel -> !plottables.has(channel.name) }
|
||||||
|
.forEachOrdered { channel ->
|
||||||
|
//plot config from device configuration
|
||||||
|
val plottable = TimePlottable(channel.name)
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,7 +4,7 @@
|
|||||||
<?import javafx.scene.layout.*?>
|
<?import javafx.scene.layout.*?>
|
||||||
<?import javafx.scene.text.Font?>
|
<?import javafx.scene.text.Font?>
|
||||||
<BorderPane fx:id="root" xmlns:fx="http://javafx.com/fxml/1" prefHeight="400.0" prefWidth="400.0"
|
<BorderPane fx:id="root" xmlns:fx="http://javafx.com/fxml/1" prefHeight="400.0" prefWidth="400.0"
|
||||||
xmlns="http://javafx.com/javafx/8.0.111" fx:controller="inr.numass.control.cryotemp.PKT8View">
|
xmlns="http://javafx.com/javafx/8.0.111" fx:controller="inr.numass.control.cryotemp.PKT8ViewConnection">
|
||||||
<center>
|
<center>
|
||||||
<TableView fx:id="table" BorderPane.alignment="CENTER">
|
<TableView fx:id="table" BorderPane.alignment="CENTER">
|
||||||
<columns>
|
<columns>
|
||||||
@ -31,14 +31,12 @@
|
|||||||
</top>
|
</top>
|
||||||
<bottom>
|
<bottom>
|
||||||
<ToolBar prefHeight="40.0" prefWidth="200.0" BorderPane.alignment="CENTER">
|
<ToolBar prefHeight="40.0" prefWidth="200.0" BorderPane.alignment="CENTER">
|
||||||
<items>
|
|
||||||
<Label text="Last update: "/>
|
<Label text="Last update: "/>
|
||||||
<Label fx:id="lastUpdateLabel" text="NONE">
|
<Label fx:id="lastUpdateLabel" text="NONE">
|
||||||
<font>
|
<font>
|
||||||
<Font name="System Bold" size="12.0"/>
|
<Font name="System Bold" size="12.0"/>
|
||||||
</font>
|
</font>
|
||||||
</Label>
|
</Label>
|
||||||
</items>
|
|
||||||
</ToolBar>
|
</ToolBar>
|
||||||
</bottom>
|
</bottom>
|
||||||
</BorderPane>
|
</BorderPane>
|
||||||
|
@ -27,12 +27,10 @@ limitations under the License.
|
|||||||
</center>
|
</center>
|
||||||
<top>
|
<top>
|
||||||
<ToolBar BorderPane.alignment="CENTER">
|
<ToolBar BorderPane.alignment="CENTER">
|
||||||
<items>
|
|
||||||
<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"/>
|
||||||
</items>
|
|
||||||
</ToolBar>
|
</ToolBar>
|
||||||
</top>
|
</top>
|
||||||
</BorderPane>
|
</BorderPane>
|
||||||
|
@ -49,7 +49,7 @@ public class MagnetControllerApp extends Application {
|
|||||||
List<SafeMagnetController> controllers = new ArrayList<>();
|
List<SafeMagnetController> controllers = new ArrayList<>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void start(Stage primaryStage) throws IOException, ControlException {
|
public void start(Stage stage) throws IOException, ControlException {
|
||||||
Locale.setDefault(Locale.US);// чтобы отделение десятичных знаков было точкой
|
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);
|
ch.qos.logback.classic.Logger rootLogger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(ch.qos.logback.classic.Logger.ROOT_LOGGER_NAME);
|
||||||
|
|
||||||
@ -108,10 +108,10 @@ public class MagnetControllerApp extends Application {
|
|||||||
Scene scene = new Scene(vbox, width, height);
|
Scene scene = new Scene(vbox, width, height);
|
||||||
|
|
||||||
|
|
||||||
primaryStage.setTitle("Numass magnet view");
|
stage.setTitle("Numass magnet view");
|
||||||
primaryStage.setScene(scene);
|
stage.setScene(scene);
|
||||||
primaryStage.setResizable(false);
|
stage.setResizable(false);
|
||||||
primaryStage.show();
|
stage.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1,31 +0,0 @@
|
|||||||
package inr.numass.control;
|
|
||||||
|
|
||||||
import hep.dataforge.control.devices.Device;
|
|
||||||
import hep.dataforge.control.devices.DeviceListener;
|
|
||||||
import hep.dataforge.fx.fragments.FXFragment;
|
|
||||||
import javafx.scene.Parent;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by darksnake on 20-Oct-16.
|
|
||||||
*/
|
|
||||||
public abstract class DeviceFragment<T extends Device> extends FXFragment implements DeviceListener {
|
|
||||||
|
|
||||||
private final T device;
|
|
||||||
|
|
||||||
protected DeviceFragment(T device) {
|
|
||||||
this.device = device;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Parent buildRoot() {
|
|
||||||
return buildRoot(device);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract Parent buildRoot(T device);
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void evaluateDeviceException(Device device, String message, Throwable exception) {
|
|
||||||
//do something pretty
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,72 +0,0 @@
|
|||||||
package inr.numass.control;
|
|
||||||
|
|
||||||
import hep.dataforge.control.connections.DeviceConnection;
|
|
||||||
import hep.dataforge.control.devices.Device;
|
|
||||||
import hep.dataforge.control.devices.DeviceListener;
|
|
||||||
import hep.dataforge.fx.FXObject;
|
|
||||||
import hep.dataforge.values.Value;
|
|
||||||
import javafx.beans.binding.ObjectBinding;
|
|
||||||
import javafx.beans.property.BooleanProperty;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by darksnake on 14-May-17.
|
|
||||||
*/
|
|
||||||
public abstract class DeviceViewConnection<D extends Device> extends DeviceConnection<D> implements DeviceListener, FXObject {
|
|
||||||
private Map<String, ObjectBinding<Value>> bindings = new HashMap<>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get binding for a given device state
|
|
||||||
*
|
|
||||||
* @param state
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public ObjectBinding<Value> getStateBinding(String state) {
|
|
||||||
return bindings.computeIfAbsent(state, stateName ->
|
|
||||||
new ObjectBinding<Value>() {
|
|
||||||
@Override
|
|
||||||
protected Value computeValue() {
|
|
||||||
if(isOpen()) {
|
|
||||||
return getDevice().getState(stateName);
|
|
||||||
} else {
|
|
||||||
return Value.NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Bind existing boolean property to writable device state
|
|
||||||
*
|
|
||||||
* @param state
|
|
||||||
* @param property
|
|
||||||
*/
|
|
||||||
protected void bindBooleanToState(String state, BooleanProperty property) {
|
|
||||||
getStateBinding(state).addListener((observable, oldValue, newValue) -> {
|
|
||||||
if (isOpen() && oldValue != newValue) {
|
|
||||||
property.setValue(newValue.booleanValue());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
property.addListener((observable, oldValue, newValue) -> {
|
|
||||||
if (isOpen() && oldValue != newValue) {
|
|
||||||
getDevice().setState(state, newValue);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void notifyDeviceStateChanged(Device device, String name, Value state) {
|
|
||||||
if (bindings.containsKey(name)) {
|
|
||||||
bindings.get(name).invalidate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// /**
|
|
||||||
// * The small view for
|
|
||||||
// * @return
|
|
||||||
// */
|
|
||||||
// public abstract Optional<Parent> getBoardView();
|
|
||||||
}
|
|
@ -1,12 +0,0 @@
|
|||||||
package inr.numass.control;
|
|
||||||
|
|
||||||
import hep.dataforge.control.devices.Device;
|
|
||||||
import hep.dataforge.control.devices.DeviceFactory;
|
|
||||||
|
|
||||||
public interface DeviceViewFactory extends DeviceFactory {
|
|
||||||
/**
|
|
||||||
* Create but do not connect view connection for the device
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
DeviceViewConnection buildView(Device device);
|
|
||||||
}
|
|
@ -1,94 +0,0 @@
|
|||||||
package inr.numass.control;
|
|
||||||
|
|
||||||
import ch.qos.logback.classic.Level;
|
|
||||||
import hep.dataforge.context.Context;
|
|
||||||
import hep.dataforge.control.connections.Roles;
|
|
||||||
import hep.dataforge.control.devices.Device;
|
|
||||||
import hep.dataforge.control.devices.DeviceFactory;
|
|
||||||
import hep.dataforge.exceptions.ControlException;
|
|
||||||
import hep.dataforge.meta.Meta;
|
|
||||||
import javafx.application.Application;
|
|
||||||
import javafx.application.Platform;
|
|
||||||
import javafx.scene.Scene;
|
|
||||||
import javafx.stage.Stage;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by darksnake on 14-May-17.
|
|
||||||
*/
|
|
||||||
public abstract class NumassControlApplication<D extends Device> extends Application {
|
|
||||||
private D device;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void start(Stage primaryStage) throws Exception {
|
|
||||||
Locale.setDefault(Locale.US);// чтобы отделение десятичных знаков было точкой
|
|
||||||
ch.qos.logback.classic.Logger rootLogger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(ch.qos.logback.classic.Logger.ROOT_LOGGER_NAME);
|
|
||||||
rootLogger.setLevel(Level.INFO);
|
|
||||||
|
|
||||||
device = setupDevice();
|
|
||||||
DeviceViewConnection<D> controller = buildView(device);
|
|
||||||
|
|
||||||
Scene scene = new Scene(controller.getPane());
|
|
||||||
primaryStage.setScene(scene);
|
|
||||||
Platform.runLater(() -> {
|
|
||||||
device.connect(controller, Roles.VIEW_ROLE, Roles.DEVICE_LISTENER_ROLE);
|
|
||||||
});
|
|
||||||
|
|
||||||
primaryStage.show();
|
|
||||||
|
|
||||||
|
|
||||||
setupStage(primaryStage, device);
|
|
||||||
NumassControlUtils.setDFStageIcon(primaryStage);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Build a view connection
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
protected abstract DeviceViewConnection<D> buildView(D device);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a device factory for given device
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
protected abstract DeviceFactory getDeviceFactory();
|
|
||||||
|
|
||||||
protected abstract void setupStage(Stage stage, D device);
|
|
||||||
|
|
||||||
protected abstract boolean acceptDevice(Meta meta);
|
|
||||||
|
|
||||||
private D setupDevice() {
|
|
||||||
Meta config = NumassControlUtils.getConfig(this)
|
|
||||||
.orElseGet(() -> NumassControlUtils.readResourceMeta("/config/devices.xml"));
|
|
||||||
|
|
||||||
Context ctx = NumassControlUtils.setupContext(config);
|
|
||||||
Meta deviceConfig = NumassControlUtils.findDeviceMeta(config, this::acceptDevice)
|
|
||||||
.orElseThrow(() -> new RuntimeException("Device configuration not found"));
|
|
||||||
|
|
||||||
|
|
||||||
try {
|
|
||||||
@SuppressWarnings("unchecked") D d = (D) getDeviceFactory().build(ctx, deviceConfig);
|
|
||||||
d.init();
|
|
||||||
NumassControlUtils.connectStorage(d, config);
|
|
||||||
|
|
||||||
return d;
|
|
||||||
} catch (ControlException e) {
|
|
||||||
throw new RuntimeException("Failed to build device", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void stop() throws Exception {
|
|
||||||
super.stop();
|
|
||||||
if (device != null) {
|
|
||||||
device.shutdown();
|
|
||||||
device.getContext().close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
@ -1,115 +0,0 @@
|
|||||||
package inr.numass.control;
|
|
||||||
|
|
||||||
import hep.dataforge.context.Context;
|
|
||||||
import hep.dataforge.context.Global;
|
|
||||||
import hep.dataforge.control.connections.Roles;
|
|
||||||
import hep.dataforge.control.connections.StorageConnection;
|
|
||||||
import hep.dataforge.control.devices.Device;
|
|
||||||
import hep.dataforge.exceptions.StorageException;
|
|
||||||
import hep.dataforge.io.MetaFileReader;
|
|
||||||
import hep.dataforge.io.XMLMetaReader;
|
|
||||||
import hep.dataforge.meta.Meta;
|
|
||||||
import hep.dataforge.storage.api.Storage;
|
|
||||||
import hep.dataforge.storage.commons.StorageFactory;
|
|
||||||
import hep.dataforge.storage.commons.StorageManager;
|
|
||||||
import inr.numass.client.ClientUtils;
|
|
||||||
import javafx.application.Application;
|
|
||||||
import javafx.scene.image.Image;
|
|
||||||
import javafx.stage.Stage;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.text.ParseException;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.function.Predicate;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by darksnake on 08-May-17.
|
|
||||||
*/
|
|
||||||
public class NumassControlUtils {
|
|
||||||
public static final String DEFAULT_CONFIG_LOCATION = "./numass-control.xml";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a single or multiple storage connections for a device
|
|
||||||
*
|
|
||||||
* @param device
|
|
||||||
* @param config
|
|
||||||
*/
|
|
||||||
public static void connectStorage(Device device, Meta config) {
|
|
||||||
//TODO add on reset listener
|
|
||||||
if (config.hasMeta("storage") && device.acceptsRole(Roles.STORAGE_ROLE)) {
|
|
||||||
String numassRun = ClientUtils.getRunName(config);
|
|
||||||
config.getMetaList("storage").forEach(node -> {
|
|
||||||
device.getContext().getLogger().info("Creating storage for device with meta: {}", node);
|
|
||||||
//building storage in a separate thread
|
|
||||||
new Thread(() -> {
|
|
||||||
Storage storage = StorageFactory.buildStorage(device.getContext(), node);
|
|
||||||
if (!numassRun.isEmpty()) {
|
|
||||||
try {
|
|
||||||
storage = storage.buildShelf(numassRun, Meta.empty());
|
|
||||||
} catch (StorageException e) {
|
|
||||||
device.getContext().getLogger().error("Failed to build shelf", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
device.connect(new StorageConnection(storage), Roles.STORAGE_ROLE);
|
|
||||||
}).start();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Meta readResourceMeta(String path) {
|
|
||||||
try {
|
|
||||||
return new XMLMetaReader().read(NumassControlUtils.class.getResourceAsStream(path));
|
|
||||||
} catch (IOException | ParseException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Optional<Meta> getConfig(Application app) {
|
|
||||||
String debugConfig = app.getParameters().getNamed().get("config.resource");
|
|
||||||
if (debugConfig != null) {
|
|
||||||
return Optional.ofNullable(readResourceMeta(debugConfig));
|
|
||||||
}
|
|
||||||
|
|
||||||
String configFileName = app.getParameters().getNamed().get("config");
|
|
||||||
Logger logger = LoggerFactory.getLogger(app.getClass());
|
|
||||||
if (configFileName == null) {
|
|
||||||
logger.info("Configuration path not defined. Loading configuration from {}", DEFAULT_CONFIG_LOCATION);
|
|
||||||
configFileName = DEFAULT_CONFIG_LOCATION;
|
|
||||||
}
|
|
||||||
File configFile = new File(configFileName);
|
|
||||||
|
|
||||||
if (configFile.exists()) {
|
|
||||||
try {
|
|
||||||
Meta config = MetaFileReader.read(configFile).build();
|
|
||||||
return Optional.of(config);
|
|
||||||
} catch (IOException | ParseException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
logger.warn("Configuration file not found");
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static Optional<Meta> findDeviceMeta(Meta config, Predicate<Meta> criterion) {
|
|
||||||
return config.getMetaList("device").stream().filter(criterion).findFirst().map(it -> it);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Context setupContext(Meta meta) {
|
|
||||||
Context ctx = Global.getContext("NUMASS-CONTROL");
|
|
||||||
ctx.pluginManager().getOrLoad(StorageManager.class);
|
|
||||||
return ctx;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setDFStageIcon(Stage stage) {
|
|
||||||
stage.getIcons().add(getDFIcon());
|
|
||||||
}
|
|
||||||
public static Image getDFIcon(){
|
|
||||||
return new Image(NumassControlUtils.class.getResourceAsStream("/img/df.png"));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,51 +0,0 @@
|
|||||||
package inr.numass.control;
|
|
||||||
|
|
||||||
import hep.dataforge.control.connections.StorageConnection;
|
|
||||||
import hep.dataforge.control.devices.AbstractDevice;
|
|
||||||
import hep.dataforge.exceptions.StorageException;
|
|
||||||
import hep.dataforge.storage.api.PointLoader;
|
|
||||||
import hep.dataforge.tables.DataPoint;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A helper to store points in multiple loaders
|
|
||||||
* Created by darksnake on 16-May-17.
|
|
||||||
*/
|
|
||||||
public class StorageHelper implements AutoCloseable {
|
|
||||||
private final AbstractDevice device;
|
|
||||||
private final Map<StorageConnection, PointLoader> loaderMap = new HashMap<>();
|
|
||||||
private final Function<StorageConnection, PointLoader> loaderFactory;
|
|
||||||
|
|
||||||
public StorageHelper(AbstractDevice device, Function<StorageConnection, PointLoader> loaderFactory) {
|
|
||||||
this.device = device;
|
|
||||||
this.loaderFactory = loaderFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void push(DataPoint point) {
|
|
||||||
if (!device.hasState("storing") || device.getState("storing").booleanValue()) {
|
|
||||||
device.forEachConnection("storage", StorageConnection.class, connection -> {
|
|
||||||
PointLoader pl = loaderMap.computeIfAbsent(connection, loaderFactory);
|
|
||||||
try {
|
|
||||||
pl.push(point);
|
|
||||||
} catch (StorageException ex) {
|
|
||||||
device.getLogger().error("Push to loader failed", ex);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() {
|
|
||||||
loaderMap.values().forEach(it -> {
|
|
||||||
try {
|
|
||||||
it.close();
|
|
||||||
} catch (Exception ex) {
|
|
||||||
device.getLogger().error("Failed to close Loader", ex);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,89 @@
|
|||||||
|
package inr.numass.control
|
||||||
|
|
||||||
|
import hep.dataforge.control.connections.DeviceConnection
|
||||||
|
import hep.dataforge.control.devices.Device
|
||||||
|
import hep.dataforge.control.devices.DeviceListener
|
||||||
|
import hep.dataforge.control.devices.PortSensor
|
||||||
|
import hep.dataforge.control.devices.Sensor
|
||||||
|
import hep.dataforge.fx.FXObject
|
||||||
|
import hep.dataforge.fx.fragments.FXFragment
|
||||||
|
import hep.dataforge.fx.fragments.FragmentWindow
|
||||||
|
import hep.dataforge.values.Value
|
||||||
|
import javafx.beans.binding.ObjectBinding
|
||||||
|
import javafx.beans.property.BooleanProperty
|
||||||
|
import javafx.geometry.Pos
|
||||||
|
import javafx.scene.Parent
|
||||||
|
import javafx.scene.layout.HBox
|
||||||
|
import javafx.scene.layout.Priority
|
||||||
|
import tornadofx.*
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by darksnake on 14-May-17.
|
||||||
|
*/
|
||||||
|
abstract class DeviceViewConnection<D : Device> : DeviceConnection<D>(), DeviceListener, FXObject {
|
||||||
|
private val bindings = HashMap<String, ObjectBinding<Value>>()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get binding for a given device state
|
||||||
|
|
||||||
|
* @param state
|
||||||
|
* *
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
fun getStateBinding(state: String): ObjectBinding<Value> {
|
||||||
|
return bindings.computeIfAbsent(state) { stateName ->
|
||||||
|
object : ObjectBinding<Value>() {
|
||||||
|
override fun computeValue(): Value {
|
||||||
|
if (isOpen) {
|
||||||
|
return device.getState(stateName)
|
||||||
|
} else {
|
||||||
|
return Value.NULL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bind existing boolean property to writable device state
|
||||||
|
|
||||||
|
* @param state
|
||||||
|
* *
|
||||||
|
* @param property
|
||||||
|
*/
|
||||||
|
protected fun bindBooleanToState(state: String, property: BooleanProperty) {
|
||||||
|
getStateBinding(state).addListener { observable, oldValue, newValue ->
|
||||||
|
if (isOpen && oldValue !== newValue) {
|
||||||
|
property.value = newValue.booleanValue()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
property.addListener { observable, oldValue, newValue ->
|
||||||
|
if (isOpen && oldValue != newValue) {
|
||||||
|
device.setState(state, newValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun notifyDeviceStateChanged(device: Device, name: String, state: Value) {
|
||||||
|
bindings[name]?.invalidate()
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun getBoardView(): Parent {
|
||||||
|
return HBox().apply {
|
||||||
|
alignment = Pos.CENTER_LEFT
|
||||||
|
vgrow = Priority.ALWAYS;
|
||||||
|
deviceStateIndicator(this@DeviceViewConnection, Device.INITIALIZED_STATE)
|
||||||
|
deviceStateIndicator(this@DeviceViewConnection, PortSensor.CONNECTED_STATE)
|
||||||
|
deviceStateIndicator(this@DeviceViewConnection, Sensor.MEASURING_STATE)
|
||||||
|
deviceStateIndicator(this@DeviceViewConnection, "storing")
|
||||||
|
pane {
|
||||||
|
hgrow = Priority.ALWAYS
|
||||||
|
}
|
||||||
|
togglebutton("View") {
|
||||||
|
isSelected = false
|
||||||
|
FragmentWindow(FXFragment.buildFromNode(device.name) { fxNode }).bindTo(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
package inr.numass.control
|
||||||
|
|
||||||
|
import hep.dataforge.control.devices.Device
|
||||||
|
import hep.dataforge.control.devices.DeviceFactory
|
||||||
|
|
||||||
|
interface DeviceViewFactory : DeviceFactory {
|
||||||
|
/**
|
||||||
|
* Create but do not connect view connection for the device
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
fun buildView(device: Device): DeviceViewConnection<*>
|
||||||
|
}
|
@ -0,0 +1,89 @@
|
|||||||
|
package inr.numass.control
|
||||||
|
|
||||||
|
import ch.qos.logback.classic.Level
|
||||||
|
import hep.dataforge.control.connections.Roles
|
||||||
|
import hep.dataforge.control.devices.Device
|
||||||
|
import hep.dataforge.control.devices.DeviceFactory
|
||||||
|
import hep.dataforge.exceptions.ControlException
|
||||||
|
import hep.dataforge.meta.Meta
|
||||||
|
import javafx.application.Platform
|
||||||
|
import javafx.scene.Scene
|
||||||
|
import javafx.stage.Stage
|
||||||
|
import org.slf4j.LoggerFactory
|
||||||
|
import tornadofx.*
|
||||||
|
import java.util.*
|
||||||
|
import java.util.function.Predicate
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by darksnake on 14-May-17.
|
||||||
|
*/
|
||||||
|
abstract class NumassControlApplication<D : Device> : App() {
|
||||||
|
private var device: D by singleAssign()
|
||||||
|
|
||||||
|
override fun start(stage: Stage) {
|
||||||
|
Locale.setDefault(Locale.US)// чтобы отделение десятичных знаков было точкой
|
||||||
|
val rootLogger = LoggerFactory.getLogger(ch.qos.logback.classic.Logger.ROOT_LOGGER_NAME) as ch.qos.logback.classic.Logger
|
||||||
|
rootLogger.level = Level.INFO
|
||||||
|
|
||||||
|
device = setupDevice()
|
||||||
|
val controller = buildView(device)
|
||||||
|
|
||||||
|
val scene = Scene(controller.pane)
|
||||||
|
stage.scene = scene
|
||||||
|
Platform.runLater { device.connect(controller, Roles.VIEW_ROLE, Roles.DEVICE_LISTENER_ROLE) }
|
||||||
|
|
||||||
|
stage.show()
|
||||||
|
|
||||||
|
|
||||||
|
setupStage(stage, device)
|
||||||
|
setDFStageIcon(stage)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build a view connection
|
||||||
|
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
protected abstract fun buildView(device: D): DeviceViewConnection<D>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a device factory for given device
|
||||||
|
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
protected abstract val deviceFactory: DeviceFactory
|
||||||
|
|
||||||
|
protected abstract fun setupStage(stage: Stage, device: D)
|
||||||
|
|
||||||
|
protected abstract fun acceptDevice(meta: Meta): Boolean
|
||||||
|
|
||||||
|
private fun setupDevice(): D {
|
||||||
|
val config = getConfig(this)
|
||||||
|
.orElseGet { readResourceMeta("/config/devices.xml") }
|
||||||
|
|
||||||
|
val ctx = setupContext(config)
|
||||||
|
val deviceConfig = findDeviceMeta(config, Predicate<Meta> { this.acceptDevice(it) })
|
||||||
|
.orElseThrow { RuntimeException("Device configuration not found") }
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
val d = deviceFactory.build(ctx, deviceConfig) as D
|
||||||
|
d.init()
|
||||||
|
connectStorage(d, config)
|
||||||
|
|
||||||
|
return d
|
||||||
|
} catch (e: ControlException) {
|
||||||
|
throw RuntimeException("Failed to build device", e)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun stop() {
|
||||||
|
super.stop()
|
||||||
|
device.shutdown()
|
||||||
|
device.context.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,117 @@
|
|||||||
|
package inr.numass.control
|
||||||
|
|
||||||
|
import hep.dataforge.context.Context
|
||||||
|
import hep.dataforge.context.Global
|
||||||
|
import hep.dataforge.control.connections.Roles
|
||||||
|
import hep.dataforge.control.connections.StorageConnection
|
||||||
|
import hep.dataforge.control.devices.Device
|
||||||
|
import hep.dataforge.exceptions.StorageException
|
||||||
|
import hep.dataforge.io.MetaFileReader
|
||||||
|
import hep.dataforge.io.XMLMetaReader
|
||||||
|
import hep.dataforge.meta.Meta
|
||||||
|
import hep.dataforge.storage.commons.StorageFactory
|
||||||
|
import hep.dataforge.storage.commons.StorageManager
|
||||||
|
import inr.numass.client.ClientUtils
|
||||||
|
import javafx.application.Application
|
||||||
|
import javafx.scene.image.Image
|
||||||
|
import javafx.stage.Stage
|
||||||
|
import org.slf4j.LoggerFactory
|
||||||
|
import java.io.File
|
||||||
|
import java.io.IOException
|
||||||
|
import java.text.ParseException
|
||||||
|
import java.util.*
|
||||||
|
import java.util.function.Predicate
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by darksnake on 08-May-17.
|
||||||
|
*/
|
||||||
|
val DEFAULT_CONFIG_LOCATION = "./numass-control.xml"
|
||||||
|
val dfIcon: Image = Image(Global::class.java.getResourceAsStream("/img/df.png"))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a single or multiple storage connections for a device
|
||||||
|
|
||||||
|
* @param device
|
||||||
|
* *
|
||||||
|
* @param config
|
||||||
|
*/
|
||||||
|
fun connectStorage(device: Device, config: Meta) {
|
||||||
|
//TODO add on reset listener
|
||||||
|
if (config.hasMeta("storage") && device.acceptsRole(Roles.STORAGE_ROLE)) {
|
||||||
|
val numassRun = ClientUtils.getRunName(config)
|
||||||
|
config.getMetaList("storage").forEach { node ->
|
||||||
|
device.context.logger.info("Creating storage for device with meta: {}", node)
|
||||||
|
//building storage in a separate thread
|
||||||
|
Thread {
|
||||||
|
var storage = StorageFactory.buildStorage(device.context, node)
|
||||||
|
if (!numassRun.isEmpty()) {
|
||||||
|
try {
|
||||||
|
storage = storage.buildShelf(numassRun, Meta.empty())
|
||||||
|
} catch (e: StorageException) {
|
||||||
|
device.context.logger.error("Failed to build shelf", e)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
device.connect(StorageConnection(storage), Roles.STORAGE_ROLE)
|
||||||
|
}.start()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun readResourceMeta(path: String): Meta {
|
||||||
|
try {
|
||||||
|
return XMLMetaReader().read(Global::class.java.getResourceAsStream(path))
|
||||||
|
} catch (e: IOException) {
|
||||||
|
throw RuntimeException(e)
|
||||||
|
} catch (e: ParseException) {
|
||||||
|
throw RuntimeException(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getConfig(app: Application): Optional<Meta> {
|
||||||
|
val debugConfig = app.parameters.named["config.resource"]
|
||||||
|
if (debugConfig != null) {
|
||||||
|
return Optional.ofNullable(readResourceMeta(debugConfig))
|
||||||
|
}
|
||||||
|
|
||||||
|
var configFileName: String? = app.parameters.named["config"]
|
||||||
|
val logger = LoggerFactory.getLogger(app.javaClass)
|
||||||
|
if (configFileName == null) {
|
||||||
|
logger.info("Configuration path not defined. Loading configuration from {}", DEFAULT_CONFIG_LOCATION)
|
||||||
|
configFileName = DEFAULT_CONFIG_LOCATION
|
||||||
|
}
|
||||||
|
val configFile = File(configFileName)
|
||||||
|
|
||||||
|
if (configFile.exists()) {
|
||||||
|
try {
|
||||||
|
val config = MetaFileReader.read(configFile).build()
|
||||||
|
return Optional.of(config)
|
||||||
|
} catch (e: IOException) {
|
||||||
|
throw RuntimeException(e)
|
||||||
|
} catch (e: ParseException) {
|
||||||
|
throw RuntimeException(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
logger.warn("Configuration file not found")
|
||||||
|
return Optional.empty<Meta>()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun findDeviceMeta(config: Meta, criterion: Predicate<Meta>): Optional<Meta> {
|
||||||
|
return config.getMetaList("device").stream().filter(criterion).findFirst().map { it -> it }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setupContext(meta: Meta): Context {
|
||||||
|
val ctx = Global.getContext("NUMASS-CONTROL")
|
||||||
|
ctx.pluginManager().getOrLoad(StorageManager::class.java)
|
||||||
|
return ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setDFStageIcon(stage: Stage) {
|
||||||
|
stage.icons.add(dfIcon)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,41 @@
|
|||||||
|
package inr.numass.control
|
||||||
|
|
||||||
|
import hep.dataforge.control.connections.StorageConnection
|
||||||
|
import hep.dataforge.control.devices.AbstractDevice
|
||||||
|
import hep.dataforge.exceptions.StorageException
|
||||||
|
import hep.dataforge.storage.api.PointLoader
|
||||||
|
import hep.dataforge.tables.DataPoint
|
||||||
|
import java.util.*
|
||||||
|
import java.util.function.Function
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A helper to store points in multiple loaders
|
||||||
|
* Created by darksnake on 16-May-17.
|
||||||
|
*/
|
||||||
|
class StorageHelper(private val device: AbstractDevice, private val loaderFactory: Function<StorageConnection, PointLoader>) : AutoCloseable {
|
||||||
|
private val loaderMap = HashMap<StorageConnection, PointLoader>()
|
||||||
|
|
||||||
|
fun push(point: DataPoint) {
|
||||||
|
if (!device.hasState("storing") || device.getState("storing").booleanValue()) {
|
||||||
|
device.forEachConnection("storage", StorageConnection::class.java) { connection ->
|
||||||
|
val pl = loaderMap.computeIfAbsent(connection, loaderFactory)
|
||||||
|
try {
|
||||||
|
pl.push(point)
|
||||||
|
} catch (ex: StorageException) {
|
||||||
|
device.logger.error("Push to loader failed", ex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun close() {
|
||||||
|
loaderMap.values.forEach { it ->
|
||||||
|
try {
|
||||||
|
it.close()
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
device.logger.error("Failed to close Loader", ex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -25,7 +25,7 @@ public class TestVac extends Application {
|
|||||||
VacCollectorView controller;
|
VacCollectorView controller;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void start(Stage primaryStage) {
|
public void start(Stage stage) {
|
||||||
try {
|
try {
|
||||||
Sensor<Double> sensor1 = Virtual.randomDoubleSensor("vac1", Duration.ofMillis(200), 1e-5, 2e-6);
|
Sensor<Double> sensor1 = Virtual.randomDoubleSensor("vac1", Duration.ofMillis(200), 1e-5, 2e-6);
|
||||||
Sensor<Double> sensor2 = Virtual.randomDoubleSensor("vac2", Duration.ofMillis(200), 2e-5, 2e-6);
|
Sensor<Double> sensor2 = Virtual.randomDoubleSensor("vac2", Duration.ofMillis(200), 2e-5, 2e-6);
|
||||||
@ -65,9 +65,9 @@ public class TestVac extends Application {
|
|||||||
|
|
||||||
Scene scene = new Scene(loader.getRoot(), 800, 600);
|
Scene scene = new Scene(loader.getRoot(), 800, 600);
|
||||||
|
|
||||||
primaryStage.setTitle("Vacuum measurement test");
|
stage.setTitle("Vacuum measurement test");
|
||||||
primaryStage.setScene(scene);
|
stage.setScene(scene);
|
||||||
primaryStage.show();
|
stage.show();
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
throw new Error(ex);
|
throw new Error(ex);
|
||||||
}
|
}
|
||||||
|
@ -67,7 +67,7 @@ public class TestModels {
|
|||||||
double A = meta.getDouble("resolution", meta.getDouble("resolution.width", 8.3e-5));//8.3e-5
|
double A = meta.getDouble("resolution", meta.getDouble("resolution.width", 8.3e-5));//8.3e-5
|
||||||
double from = meta.getDouble("from", 13900d);
|
double from = meta.getDouble("from", 13900d);
|
||||||
double to = meta.getDouble("to", 18700d);
|
double to = meta.getDouble("to", 18700d);
|
||||||
context.getLog().report("Setting up tritium model with real transmission function");
|
context.getChronicle().report("Setting up tritium model with real transmission function");
|
||||||
BivariateFunction resolutionTail;
|
BivariateFunction resolutionTail;
|
||||||
if (meta.hasValue("resolution.tailAlpha")) {
|
if (meta.hasValue("resolution.tailAlpha")) {
|
||||||
resolutionTail = ResolutionFunction.getAngledTail(meta.getDouble("resolution.tailAlpha"), meta.getDouble("resolution.tailBeta", 0));
|
resolutionTail = ResolutionFunction.getAngledTail(meta.getDouble("resolution.tailAlpha"), meta.getDouble("resolution.tailBeta", 0));
|
||||||
@ -78,7 +78,7 @@ public class TestModels {
|
|||||||
RangedNamedSetSpectrum beta = new BetaSpectrum();
|
RangedNamedSetSpectrum beta = new BetaSpectrum();
|
||||||
ModularSpectrum sp = new ModularSpectrum(beta, new ResolutionFunction(A, resolutionTail), from, to);
|
ModularSpectrum sp = new ModularSpectrum(beta, new ResolutionFunction(A, resolutionTail), from, to);
|
||||||
if (meta.getBoolean("caching", false)) {
|
if (meta.getBoolean("caching", false)) {
|
||||||
context.getLog().report("Caching turned on");
|
context.getChronicle().report("Caching turned on");
|
||||||
sp.setCaching(true);
|
sp.setCaching(true);
|
||||||
}
|
}
|
||||||
//Adding trapping energy dependence
|
//Adding trapping energy dependence
|
||||||
|
@ -31,7 +31,7 @@ import java.io.IOException;
|
|||||||
public class TestDirectoryViewer extends Application {
|
public class TestDirectoryViewer extends Application {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void start(Stage primaryStage) throws IOException {
|
public void start(Stage stage) throws IOException {
|
||||||
new StorageManager().startGlobal();
|
new StorageManager().startGlobal();
|
||||||
|
|
||||||
NumassDataLoader reader = NumassDataLoader.fromLocalDir(null, new File("C:\\Users\\darksnake\\Dropbox\\PlayGround\\data-test\\20150703143643_1\\"));
|
NumassDataLoader reader = NumassDataLoader.fromLocalDir(null, new File("C:\\Users\\darksnake\\Dropbox\\PlayGround\\data-test\\20150703143643_1\\"));
|
||||||
@ -49,13 +49,13 @@ public class TestDirectoryViewer extends Application {
|
|||||||
|
|
||||||
Scene scene = new Scene(comp.getRoot(), 800, 600);
|
Scene scene = new Scene(comp.getRoot(), 800, 600);
|
||||||
|
|
||||||
primaryStage.setTitle("Detector Visualisation test");
|
stage.setTitle("Detector Visualisation test");
|
||||||
primaryStage.setScene(scene);
|
stage.setScene(scene);
|
||||||
primaryStage.setMinHeight(600);
|
stage.setMinHeight(600);
|
||||||
primaryStage.setMinWidth(800);
|
stage.setMinWidth(800);
|
||||||
// primaryStage.setResizable(false);
|
// primaryStage.setResizable(false);
|
||||||
|
|
||||||
primaryStage.show();
|
stage.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user