Fix of config editor refresh. Multiple fixes in control.

This commit is contained in:
Alexander Nozik 2018-04-04 20:37:04 +03:00
parent 0085ff3142
commit af54525d41
20 changed files with 568 additions and 515 deletions

View File

@ -79,11 +79,11 @@ class PKT8Device(context: Context, meta: Meta) : PortSensor(context, meta) {
tableFormatBuilder.build()
}
val sps: String by valueState(SPS).string
val sps: String by valueState(SPS).stringDelegate
val pga: String by valueState(PGA).string
val pga: String by valueState(PGA).stringDelegate
val abuf: String by valueState(ABUF).string
val abuf: String by valueState(ABUF).stringDelegate
private val duration = Duration.parse(meta.getString("averagingDuration", "PT30S"))

View File

@ -12,7 +12,7 @@ import hep.dataforge.plots.PlotFrame
import hep.dataforge.plots.PlotUtils
import hep.dataforge.plots.data.TimePlot
import hep.dataforge.plots.jfreechart.JFreeChartFrame
import inr.numass.control.DeviceDisplay
import inr.numass.control.DeviceDisplayFX
import javafx.beans.binding.ListBinding
import javafx.beans.property.SimpleObjectProperty
import javafx.collections.FXCollections
@ -30,7 +30,7 @@ import java.time.Instant
/**
* Created by darksnake on 30-May-17.
*/
class PKT8Display : DeviceDisplay<PKT8Device>(), PKT8ValueListener {
class PKT8Display : DeviceDisplayFX<PKT8Device>(), PKT8ValueListener {
override fun buildView(device: PKT8Device) = CryoView()

View File

@ -17,9 +17,7 @@ package inr.numass.control.magnet
import hep.dataforge.context.Context
import hep.dataforge.control.devices.AbstractDevice
import hep.dataforge.control.devices.booleanState
import hep.dataforge.control.devices.doubleState
import hep.dataforge.control.devices.timeState
import hep.dataforge.control.ports.Port
import hep.dataforge.control.ports.PortFactory
import hep.dataforge.description.ValueDef
import hep.dataforge.exceptions.ControlException
@ -27,12 +25,14 @@ import hep.dataforge.exceptions.PortException
import hep.dataforge.meta.Meta
import hep.dataforge.states.StateDef
import hep.dataforge.states.StateDefs
import hep.dataforge.states.valueState
import hep.dataforge.utils.DateTimeUtils
import hep.dataforge.values.Value
import hep.dataforge.values.ValueType.*
import kotlinx.coroutines.experimental.runBlocking
import org.slf4j.LoggerFactory
import java.text.DecimalFormat
import java.time.Duration
import java.time.Instant
import java.time.temporal.ChronoUnit
import java.util.concurrent.Future
import java.util.concurrent.ScheduledThreadPoolExecutor
@ -41,12 +41,12 @@ import java.util.concurrent.TimeUnit
/**
* @author Polina
*/
@ValueDef(name = "timeout", type = arrayOf(NUMBER), def = "400", info = "A timeout for port response")
@ValueDef(name = "timeout", type = [NUMBER], def = "400", info = "A timeout for port response")
@StateDefs(
StateDef(value = ValueDef(name = "current", type = arrayOf(NUMBER), def = "0", info = "Current current")),
StateDef(value = ValueDef(name = "voltage", type = arrayOf(NUMBER), def = "0", info = "Current voltage")),
StateDef(value = ValueDef(name = "targetCurrent", type = arrayOf(NUMBER), def = "0", info = "Target current"), writable = true),
StateDef(value = ValueDef(name = "targetVoltage", type = arrayOf(NUMBER), def = "5.0", info = "Target voltage"), writable = true),
StateDef(value = ValueDef(name = "outCurrent", type = arrayOf(NUMBER), def = "0", info = "Target current"), writable = true),
StateDef(value = ValueDef(name = "outVoltage", type = arrayOf(NUMBER), def = "5.0", info = "Target voltage"), writable = true),
StateDef(value = ValueDef(name = "output", type = arrayOf(BOOLEAN), def = "false", info = "Weather output on or off"), writable = true),
StateDef(value = ValueDef(name = "lastUpdate", type = arrayOf(TIME), def = "0", info = "Time of the last update"), writable = true),
StateDef(value = ValueDef(name = "updating", type = arrayOf(BOOLEAN), def = "false", info = "Shows if current ramping in progress"), writable = true),
@ -57,28 +57,70 @@ open class LambdaMagnet(context: Context, meta: Meta, private val controller: La
private var closePortOnShutDown = false
private val name: String = meta.getString("name", "LAMBDA")
/**
* @return the address
*/
val address: Int = meta.getInt("address", 1)!!
val address: Int = meta.getInt("address", 1)
override val name: String = meta.getString("name", "LAMBDA_$address")
private val scheduler = ScheduledThreadPoolExecutor(1)
var listener: MagnetStateListener? = null
//var listener: MagnetStateListener? = null
// private volatile double current = 0;
private val timeout: Duration = meta.optString("timeout").map<Duration> { Duration.parse(it) }.orElse(Duration.ofMillis(200))
private var monitorTask: Future<*>? = null
private var updateTask: Future<*>? = null
var lastUpdate by timeState()
var lastUpdate by valueState("lastUpdate", getter = {0}).timeDelegate
private set
val current by doubleState()
val voltage by doubleState()
var targetCurrent by doubleState()
var targetVoltage by doubleState()
var output by booleanState()
var monitoring by booleanState()
// read-only values of current output
val current = valueState("current", getter = { controller.talk(address, timeout) { s2d(getParameter("MC")) } })
// val current by current.double
val voltage = valueState("voltage", getter = { controller.talk(address, timeout) { s2d(getParameter("MV")) } })
// val voltage by voltage.double
var target = valueState("target")
//output values of current and voltage
private var outCurrent by valueState("outCurrent", getter = { controller.talk(address, timeout) { s2d(getParameter("PC")) } }) { _, value ->
if (setParameter("PC", value.doubleValue())) {
lastUpdate = DateTimeUtils.now()
} else {
notifyError("Can't set the target current")
}
return@valueState value
}.doubleDelegate
private val outVoltage = valueState("outVoltage", getter = { controller.talk(address, timeout) { s2d(getParameter("PV")) } }) { _, value ->
if (!setParameter("PV", value.doubleValue())) {
notifyError("Can't set the target voltage")
}
return@valueState value
}
val output = valueState("output", getter = { controller.talk(address, timeout) { talk("OUT?") == "OK" } }) { _, value ->
setOutputMode(value.booleanValue())
}
var monitoring =valueState("monitoring", getter = { monitorTask != null }) { _, value ->
if (value.booleanValue()) {
startMonitorTask()
} else {
stopMonitorTask()
}
return@valueState value
}
var updating = valueState("updating", getter = { updateTask != null }) { _, value ->
if (value.booleanValue()) {
startUpdateTask()
} else {
stopUpdateTask()
}
return@valueState value
}
/**
@ -100,82 +142,6 @@ open class LambdaMagnet(context: Context, meta: Meta, private val controller: La
closePortOnShutDown = true
}
override fun computeState(stateName: String): Any {
return when (stateName) {
"current" -> controller.talk(address, timeout) { s2d(getParameter("MC")) }
"voltage" -> controller.talk(address, timeout) { s2d(getParameter("MV")) }
"targetCurrent" -> controller.talk(address, timeout) { s2d(getParameter("PC")) }
"targetVoltage" -> controller.talk(address, timeout) { s2d(getParameter("PV")) }
"output" -> controller.talk(address, timeout) { talk("OUT?") == "OK" }
"monitoring" -> monitorTask != null
"updating" -> updateTask != null
else -> getLogicalState(stateName)
}
}
override fun requestStateChange(stateName: String, value: Value) {
when (stateName) {
"targetCurrent" -> {
if (setParameter("PC", value.doubleValue())) {
lastUpdate = DateTimeUtils.now()
} else {
reportError("Can't set the target current", null)
}
}
"targetVoltage" -> {
if (!setParameter("PV", value.doubleValue())) {
reportError("Can't set the target voltage", null)
}
}
"updating" -> if (value.booleanValue()) {
startUpdateTask()
} else {
stopUpdateTask()
}
"monitoring" -> if (value.booleanValue()) {
startMonitorTask()
} else {
stopMonitorTask()
}
"output" -> setOutputMode(value.booleanValue())
else -> setLogicalState(stateName, value);
}
}
// protected open fun setCurrent(current: Double) {
//
// if (!setParameter("PC", current)) {
// reportError("Can't set the current", null)
// } else {
// lastUpdate = DateTimeUtils.now()
// }
// }
/**
// * Gets status of magnet for current moment
// *
// * @return status of magnet
// */
// private val status: MagnetStatus
// @Throws(PortException::class)
// get() {
// return controller.talk(address, timeout) {
// val out: Boolean = "ON" == talk("OUT?")
//
// val measuredCurrent = s2d(getParameter("MC"))
// updateState("current", measuredCurrent)
// val setCurrent = s2d(getParameter("PC"))
// val measuredVoltage = s2d(getParameter("MV"))
// val setVoltage = s2d(getParameter("PV"))
//
// MagnetStatus(out, measuredCurrent, setCurrent, measuredVoltage, setVoltage).also {
// listener?.acceptStatus(getName(), it)
// }
// }
// }
//
@Throws(ControlException::class)
override fun init() {
super.init()
@ -196,36 +162,36 @@ open class LambdaMagnet(context: Context, meta: Meta, private val controller: La
}
private fun reportError(errorMessage: String, error: Throwable?) {
listener?.error(getName(), errorMessage, error) ?: LoggerFactory.getLogger(javaClass).error(errorMessage, error)
}
// private fun reportError(errorMessage: String, error: Throwable?) {
// listener?.error(name, errorMessage, error) ?: LoggerFactory.getLogger(javaClass).error(errorMessage, error)
//
// }
@Throws(PortException::class)
private fun talk(request: String): String {
try {
return try {
controller.send(request + "\r")
return controller.waitFor(timeout).trim()
} catch (tex: PortTimeoutException) {
controller.waitFor(timeout).trim()
} catch (tex: Port.PortTimeoutException) {
//Single retry on timeout
LoggerFactory.getLogger(javaClass).warn("A timeout exception for request '$request'. Making another attempt.")
controller.send(request + "\r")
return controller.waitFor(timeout).trim()
controller.waitFor(timeout).trim()
}
}
private fun update(key: String, value: String) {
when (key) {
"OUT" -> updateState("output", value == "ON")
"MC" -> updateState("current", s2d(value))
"PC" -> updateState("targetCurrent", s2d(value))
"MV" -> updateState("voltage", s2d(value))
"PV" -> updateState("targetVoltage", s2d(value))
}
}
// private fun update(key: String, value: String) {
// when (key) {
// "OUT" -> updateState("output", value == "ON")
// "MC" -> updateState("current", s2d(value))
// "PC" -> updateState("outCurrent", s2d(value))
// "MV" -> updateState("voltage", s2d(value))
// "PV" -> updateState("outVoltage", s2d(value))
// }
// }
@Throws(PortException::class)
private fun getParameter(name: String): String = talk(name + "?")
private fun getParameter(name: String): String = talk("$name?")
@Throws(PortException::class)
private fun setParameter(key: String, state: String): Boolean = "OK" == talk("$key $state")
@ -248,11 +214,7 @@ open class LambdaMagnet(context: Context, meta: Meta, private val controller: La
* Cancel current update task
*/
fun stopUpdateTask() {
updateTask?.let {
it.cancel(false)
lastUpdate = null
listener?.updateTaskStateChanged(getName(), false)
}
updateTask?.cancel(false)
}
/**
@ -268,48 +230,44 @@ open class LambdaMagnet(context: Context, meta: Meta, private val controller: La
stopUpdateTask()
val call = {
try {
val measuredI = current ?: 0.0
val targetI = targetCurrent ?: 0.0
listener?.acceptMeasuredI(getName(), measuredI)
val measuredI = current.doubleValue
val targetI = target.doubleValue
updateState("current",measuredI)
if (Math.abs(measuredI - targetI) > CURRENT_PRECISION) {
val nextI = nextI(measuredI, targetI)
listener?.acceptNextI(getName(), nextI)
targetCurrent = nextI
outCurrent = nextI
} else {
stopUpdateTask()
}
} catch (ex: PortException) {
reportError("Error in update task", ex)
notifyError("Error in update task", ex)
stopUpdateTask()
}
}
updateTask = scheduler.scheduleWithFixedDelay(call, 0, delay.toLong(), TimeUnit.MILLISECONDS)
listener?.updateTaskStateChanged(getName(), true)
updateState("updating", Value.of(true))
updateState("updating", true)
}
@Throws(PortException::class)
private fun setOutputMode(out: Boolean) {
val outState: Int = if (out) 1 else 0
if (!setParameter("OUT", outState)) {
listener?.error(getName(), "Can't set output mode", null)
notifyError("Can't set output mode")
} else {
requestStateChange("output", Value.of(out))
listener?.outputModeChanged(getName(), out)
updateState("output", out)
}
}
private fun nextI(measuredI: Double, targetI: Double): Double {
// assert(measuredI != targetI)
// assert(measuredI != target)
var step = if (lastUpdate == null) {
var step = if (lastUpdate == Instant.EPOCH) {
MIN_UP_STEP_SIZE
} else {
//Choose optimal speed but do not exceed maximum speed
Math.min(MAX_STEP_SIZE,
lastUpdate!!.until(DateTimeUtils.now(), ChronoUnit.MILLIS).toDouble() / 60000.0 * speed)
Math.min(MAX_STEP_SIZE, lastUpdate.until(DateTimeUtils.now(), ChronoUnit.MILLIS).toDouble() / 60000.0 * speed)
}
val res = if (targetI > measuredI) {
@ -336,18 +294,8 @@ open class LambdaMagnet(context: Context, meta: Meta, private val controller: La
private fun stopMonitorTask() {
monitorTask?.let {
it.cancel(true)
listener?.monitorTaskStateChanged(getName(), false)
monitorTask = null
}
updateState("output", Value.of(false))
}
override fun getName(): String {
return if (this.name.isEmpty()) {
"LAMBDA " + address
} else {
this.name
}
}
/**
@ -356,38 +304,27 @@ open class LambdaMagnet(context: Context, meta: Meta, private val controller: La
*
* @param delay an interval between scans in milliseconds
*/
@JvmOverloads
fun startMonitorTask(delay: Int = DEFAULT_MONITOR_DELAY) {
private fun startMonitorTask(delay: Int = DEFAULT_MONITOR_DELAY) {
assert(delay >= 1000)
stopMonitorTask()
val call = Runnable {
try {
status
runBlocking {
states["voltage"]?.read()
states["current"]?.read()
}
} catch (ex: PortException) {
reportError("Port connection exception during status measurement", ex)
notifyError("Port connection exception during status measurement", ex)
stopMonitorTask()
}
}
monitorTask = scheduler.scheduleWithFixedDelay(call, 0, delay.toLong(), TimeUnit.MILLISECONDS)
listener?.monitorTaskStateChanged(getName(), true)
}
// fun request(message: String): String? {
// try {
// if (!setADR()) {
// throw RuntimeException("F")
// }
// return talk(message)
// } catch (ex: PortException) {
// reportError("Can not send message to the port", ex)
// return null
// }
//
// }
companion object {
private val LAMBDA_FORMAT = DecimalFormat("###.##")
@ -407,5 +344,5 @@ open class LambdaMagnet(context: Context, meta: Meta, private val controller: La
*/
private fun d2s(d: Double): String = LAMBDA_FORMAT.format(d)
}
}

View File

@ -55,8 +55,8 @@ class SafeLambdaMagnet(context: Context, meta: Meta, controller: LambdaPortContr
* @param tolerance
*/
fun bindTo(controller: SafeLambdaMagnet, tolerance: Double) {
this.addSafeCondition(false) { I -> Math.abs(controller.getCurrent() - I) <= tolerance }
controller.addSafeCondition(false) { I -> Math.abs(this.getCurrent() - I) <= tolerance }
this.addSafeCondition(false) { I -> Math.abs(controller.current - I) <= tolerance }
controller.addSafeCondition(false) { I -> Math.abs(this.current - I) <= tolerance }
}
@ -73,7 +73,7 @@ class SafeLambdaMagnet(context: Context, meta: Meta, controller: LambdaPortContr
}
}
super.setCurrent(current)
super.current = current
}
interface SafeMagnetCondition {

View File

@ -18,7 +18,6 @@ package inr.numass.control.magnet.fx
import ch.qos.logback.classic.Level
import ch.qos.logback.classic.spi.ILoggingEvent
import ch.qos.logback.core.FileAppender
import hep.dataforge.context.Global
import hep.dataforge.exceptions.ControlException
import hep.dataforge.io.MetaFileReader
import inr.numass.control.magnet.LambdaHub
@ -44,14 +43,13 @@ class MagnetControllerApp : Application() {
// internal var controllers: MutableList<SafeLambdaMagnet> = ArrayList()
private lateinit var device: LambdaHub
val context = Global.instance()
@Throws(IOException::class, ControlException::class)
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
val logLevel = (parameters.named as java.util.Map<String, String>).getOrDefault("logLevel", "INFO")
val logLevel = parameters.named.getOrDefault("logLevel", "INFO")
rootLogger.level = Level.valueOf(logLevel)
@ -69,8 +67,6 @@ class MagnetControllerApp : Application() {
val config = MetaFileReader.instance().read(context,)
device =
// val portName = (parameters.named as java.util.Map<String, String>).getOrDefault("port", "virtual")
//
// if (portName == "virtual") {

View File

@ -16,20 +16,17 @@
package inr.numass.control.magnet.fx
import hep.dataforge.exceptions.PortException
import inr.numass.control.DeviceDisplayFX
import inr.numass.control.magnet.LambdaMagnet
import inr.numass.control.magnet.MagnetStateListener
import inr.numass.control.magnet.MagnetStatus
import javafx.application.Platform
import javafx.beans.value.ObservableValue
import javafx.event.ActionEvent
import javafx.fxml.FXML
import javafx.fxml.FXMLLoader
import javafx.fxml.Initializable
import javafx.scene.control.*
import javafx.scene.layout.AnchorPane
import javafx.scene.paint.Color
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import tornadofx.*
import java.net.URL
import java.util.*
@ -38,250 +35,221 @@ import java.util.*
*
* @author Alexander Nozik
*/
class MagnetControllerComponent : AnchorPane(), Initializable, MagnetStateListener {
class MagnetDisplay : DeviceDisplayFX<LambdaMagnet>() {
override fun buildView(device: LambdaMagnet): MagnetControllerComponent? {
return MagnetControllerComponent(device)
}
private var lambdaMagnet: LambdaMagnet? = null
/**
* @return the logger
*/
var logger: Logger? = null
private set
val current by lazy { valueBinding(device.voltage)}
private var showConfirmation = true
val voltage by lazy { valueBinding(device.current)}
@FXML
private val labelI: Label? = null
@FXML
private val labelU: Label? = null
@FXML
private val targetIField: TextField? = null
@FXML
private val magnetName: Label? = null
@FXML
private val monitorButton: ToggleButton? = null
@FXML
private val statusLabel: Label? = null
@FXML
private val setButton: ToggleButton? = null
@FXML
private val magnetSpeedField: TextField? = null
var target by device.target.doubleDelegate
private val targetI: Double
get() = java.lang.Double.parseDouble(targetIField!!.text)
var output by device.output.booleanDelegate
// public MagnetControllerComponent(LambdaMagnet lambdaMagnet) {
// FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/SingleMagnet.fxml"));
//
// loader.setRoot(this);
// loader.setController(this);
//
// try {
// loader.load();
// } catch (IOException ex) {
// throw new RuntimeException(ex);
// }
// setLambdaMagnet(lambdaMagnet);
// }
/**
* Initializes the controller class.
*
* @param url
* @param rb
*/
override fun initialize(url: URL, rb: ResourceBundle) {
var monitoring by device.monitoring.booleanDelegate
targetIField!!.textProperty().addListener { observable: ObservableValue<out String>, oldValue: String, newValue: String ->
if (!newValue.matches("\\d*(\\.)?\\d*".toRegex())) {
targetIField.text = oldValue
var updating by device.updating.booleanDelegate
inner class MagnetControllerComponent(val device: LambdaMagnet) : Fragment(), Initializable {
override val root: AnchorPane by fxml("/fxml/SingleMagnet.fxml")
private var showConfirmation = true
val labelI: Label by fxml()
val labelU: Label by fxml()
val targetIField: TextField by fxml()
val magnetName: Label by fxml()
val monitorButton: ToggleButton by fxml()
val statusLabel: Label by fxml()
val setButton: ToggleButton by fxml()
val magnetSpeedField: TextField by fxml()
/**
* Initializes the controller class.
*
* @param url
* @param rb
*/
override fun initialize(url: URL, rb: ResourceBundle) {
targetIField.textProperty().addListener { observable: ObservableValue<out String>, oldValue: String, newValue: String ->
if (!newValue.matches("\\d*(\\.)?\\d*".toRegex())) {
targetIField.text = oldValue
}
}
magnetSpeedField.textProperty().addListener { observable: ObservableValue<out String>, oldValue: String, newValue: String ->
if (!newValue.matches("\\d*(\\.)?\\d*".toRegex())) {
magnetSpeedField.text = oldValue
}
}
magnetName.text = device.name
magnetSpeedField.text = device.speed.toString()
current.onChange {
runLater {
labelI.text = it?.stringValue()
}
}
voltage.onChange {
runLater {
labelU.text = it?.stringValue()
}
}
valueBinding(device.output).onChange{
Platform.runLater {
if (it?.booleanValue() == true) {
this.statusLabel.text = "OK"
this.statusLabel.textFill = Color.BLUE
} else {
this.statusLabel.text = "OFF"
this.statusLabel.textFill = Color.BLACK
}
}
}
}
magnetSpeedField!!.textProperty().addListener { observable: ObservableValue<out String>, oldValue: String, newValue: String ->
if (!newValue.matches("\\d*(\\.)?\\d*".toRegex())) {
magnetSpeedField.text = oldValue
fun setShowConfirmation(showConfirmation: Boolean) {
this.showConfirmation = showConfirmation
}
@FXML
private fun onOutToggle(event: ActionEvent) {
try {
setOutput(setButton.isSelected)
} catch (ex: PortException) {
displayError(this.device.name, null, ex)
}
}
}
fun setShowConfirmation(showConfirmation: Boolean) {
this.showConfirmation = showConfirmation
}
@FXML
private fun onOutToggle(event: ActionEvent) {
try {
setOutput(setButton!!.isSelected)
} catch (ex: PortException) {
error(this.lambdaMagnet!!.name, null, ex)
}
}
@Throws(PortException::class)
private fun setOutput(outputOn: Boolean) {
if (outputOn) {
if (showConfirmation) {
val alert = Alert(Alert.AlertType.WARNING)
alert.contentText = "Изменение токов в сверхпроводящих магнитах можно производить только при выключенном напряжении на спектрометре." + "\nВы уверены что напряжение выключено?"
alert.headerText = "Проверьте напряжение на спектрометре!"
alert.height = 150.0
alert.title = "Внимание!"
alert.buttonTypes.clear()
alert.buttonTypes.addAll(ButtonType.YES, ButtonType.CANCEL)
@Throws(PortException::class)
private fun setOutput(outputOn: Boolean) {
if (outputOn) {
if (showConfirmation) {
val alert = Alert(Alert.AlertType.WARNING)
alert.contentText = "Изменение токов в сверхпроводящих магнитах можно производить только при выключенном напряжении на спектрометре." + "\nВы уверены что напряжение выключено?"
alert.headerText = "Проверьте напряжение на спектрометре!"
alert.height = 150.0
alert.title = "Внимание!"
alert.buttonTypes.clear()
alert.buttonTypes.addAll(ButtonType.YES, ButtonType.CANCEL)
if (alert.showAndWait().orElse(ButtonType.CANCEL) == ButtonType.YES) {
startCurrentChange()
if (alert.showAndWait().orElse(ButtonType.CANCEL) == ButtonType.YES) {
startCurrentChange()
} else {
setButton.isSelected = false
}
} else {
setButton!!.isSelected = false
startCurrentChange()
}
} else {
startCurrentChange()
device.stopUpdateTask()
targetIField.isDisable = false
magnetSpeedField.isDisable = false
}
} else {
getLambdaMagnet().stopUpdateTask()
targetIField!!.isDisable = false
magnetSpeedField!!.isDisable = false
}
}
@Throws(PortException::class)
private fun startCurrentChange() {
val speed = java.lang.Double.parseDouble(magnetSpeedField!!.text)
if (speed > 0 && speed <= 7) {
lambdaMagnet!!.speed = speed
magnetSpeedField.isDisable = true
getLambdaMagnet().setOutputMode(true)
getLambdaMagnet().startUpdateTask(targetI)
} else {
val alert = Alert(Alert.AlertType.ERROR)
alert.contentText = null
alert.headerText = "Недопустимое значение скорости изменения тока"
alert.title = "Ошибка!"
alert.show()
setButton!!.isSelected = false
magnetSpeedField.text = java.lang.Double.toString(lambdaMagnet!!.speed)
}
}
@FXML
private fun onMonitorToggle(event: ActionEvent) {
if (monitorButton!!.isSelected) {
getLambdaMagnet().startMonitorTask()
} else {
getLambdaMagnet().stopMonitorTask()
this.labelU!!.text = "----"
}
}
override fun error(name: String, errorMessage: String?, throwable: Throwable) {
Platform.runLater {
this.statusLabel!!.text = "ERROR"
this.statusLabel.textFill = Color.RED
}
this.logger!!.error("ERROR: {}", errorMessage, throwable)
// MagnetStateListener.super.error(address, errorMessage, throwable); //To change body of generated methods, choose Tools | Templates.
}
/**
* @return the lambdaMagnet
*/
fun getLambdaMagnet(): LambdaMagnet {
if (lambdaMagnet == null) {
throw RuntimeException("Magnet controller not defined")
}
return lambdaMagnet
}
/**
* @param lambdaMagnet the lambdaMagnet to set
*/
private fun setLambdaMagnet(lambdaMagnet: LambdaMagnet) {
this.lambdaMagnet = lambdaMagnet
logger = LoggerFactory.getLogger("lambda." + lambdaMagnet.name)
lambdaMagnet.listener = this
magnetName!!.text = lambdaMagnet.name
magnetSpeedField!!.text = java.lang.Double.toString(this.lambdaMagnet!!.speed)
}
override fun acceptStatus(name: String, state: MagnetStatus) {
Platform.runLater {
this.labelI!!.text = java.lang.Double.toString(state.measuredCurrent)
this.labelU!!.text = java.lang.Double.toString(state.measuredVoltage)
outputModeChanged(name, state.isOutputOn)
logger!!.info(String.format("%s (%s): Im = %f, Um = %f, Is = %f, Us = %f;",
name,
state.isOutputOn,
state.measuredCurrent,
state.measuredVoltage,
state.setCurrent,
state.setVoltage
))
}
}
override fun acceptNextI(name: String, nextI: Double) {
logger!!.debug("{}: nextI = {};", name, nextI)
}
override fun acceptMeasuredI(name: String, measuredI: Double) {
logger!!.debug("{}: measuredI = {};", name, measuredI)
Platform.runLater { this.labelI!!.text = java.lang.Double.toString(measuredI) }
}
override fun outputModeChanged(name: String, out: Boolean) {
Platform.runLater {
if (out) {
this.statusLabel!!.text = "OK"
this.statusLabel.textFill = Color.BLUE
@Throws(PortException::class)
private fun startCurrentChange() {
val speed = java.lang.Double.parseDouble(magnetSpeedField.text)
if (speed > 0 && speed <= 7) {
device.speed = speed
magnetSpeedField.isDisable = true
target = targetIField.text.toDouble()
output = true
updating = true
} else {
this.statusLabel!!.text = "OFF"
this.statusLabel.textFill = Color.BLACK
val alert = Alert(Alert.AlertType.ERROR)
alert.contentText = null
alert.headerText = "Недопустимое значение скорости изменения тока"
alert.title = "Ошибка!"
alert.show()
setButton.isSelected = false
magnetSpeedField.text = java.lang.Double.toString(device.speed)
}
}
@FXML
private fun onMonitorToggle(event: ActionEvent) {
device
if (monitorButton.isSelected) {
monitoring = true
} else {
monitoring = false
this.labelU.text = "----"
}
}
fun displayError(name: String, errorMessage: String?, throwable: Throwable) {
Platform.runLater {
this.statusLabel.text = "ERROR"
this.statusLabel.textFill = Color.RED
}
device.logger.error("ERROR: {}", errorMessage, throwable)
// MagnetStateListener.super.error(address, errorMessage, throwable); //To change body of generated methods, choose Tools | Templates.
}
// /**
// * @param lambdaMagnet the device to set
// */
// private fun setLambdaMagnet(lambdaMagnet: LambdaMagnet) {
// this.device = lambdaMagnet
// lambdaMagnet.listener = this
// magnetName.text = lambdaMagnet.name
//
// magnetSpeedField.text = java.lang.Double.toString(this.device.speed)
//
// }
override fun updateTaskStateChanged(name: String, updateTaskRunning: Boolean) {
this.setButton.isSelected = updateTaskRunning
targetIField.isDisable = updateTaskRunning
}
override fun monitorTaskStateChanged(name: String, monitorTaskRunning: Boolean) {
this.monitorButton.isScaleShape = monitorTaskRunning
}
// /**
// * @param logger the logger to set
// */
// public void setLogger(PrintStream logger) {
// this.logger = logger;
// }
override fun displayState(state: String) {
Platform.runLater { this.statusLabel.text = state }
}
companion object {
// fun build(lambdaMagnet: LambdaMagnet): MagnetControllerComponent {
// val component = MagnetControllerComponent()
// val loader = FXMLLoader(lambdaMagnet.javaClass.getResource("/fxml/SingleMagnet.fxml"))
//
// loader.setRoot(component)
// loader.setController(component)
//
// try {
// loader.load<Any>()
// } catch (ex: Exception) {
// LoggerFactory.getLogger("FX").error("Error during fxml initialization", ex)
// throw Error(ex)
// }
//
// component.setLambdaMagnet(lambdaMagnet)
// return component
// }
}
}
override fun updateTaskStateChanged(name: String, updateTaskRunning: Boolean) {
this.setButton!!.isSelected = updateTaskRunning
targetIField!!.isDisable = updateTaskRunning
}
override fun monitorTaskStateChanged(name: String, monitorTaskRunning: Boolean) {
this.monitorButton!!.isScaleShape = monitorTaskRunning
}
// /**
// * @param logger the logger to set
// */
// public void setLogger(PrintStream logger) {
// this.logger = logger;
// }
override fun displayState(state: String) {
Platform.runLater { this.statusLabel!!.text = state }
}
companion object {
fun build(lambdaMagnet: LambdaMagnet): MagnetControllerComponent {
val component = MagnetControllerComponent()
val loader = FXMLLoader(lambdaMagnet.javaClass.getResource("/fxml/SingleMagnet.fxml"))
loader.setRoot(component)
loader.setController(component)
try {
loader.load<Any>()
} catch (ex: Exception) {
LoggerFactory.getLogger("FX").error("Error during fxml initialization", ex)
throw Error(ex)
}
component.setLambdaMagnet(lambdaMagnet)
return component
}
}
}

View File

@ -7,6 +7,7 @@ package inr.numass.control.magnet.fx
import ch.qos.logback.classic.Level
import ch.qos.logback.classic.Logger
import hep.dataforge.context.Global
import hep.dataforge.control.ports.GenericPortController
import hep.dataforge.control.ports.Port
import hep.dataforge.control.ports.PortFactory
@ -57,7 +58,7 @@ object Talk {
}
val handler: Port
handler = PortFactory.build(portName)
handler.setPhraseCondition { str: String -> str.endsWith("\r") }
val controller = GenericPortController(Global,handler,"\r")
// LambdaMagnet controller = new LambdaMagnet(handler, 1);
val reader = BufferedReader(InputStreamReader(System.`in`))
@ -68,7 +69,7 @@ object Talk {
while ("exit" != nextString) {
try {
val start = DateTimeUtils.now()
val answer = GenericPortController.sendAndWait(handler, nextString + "\r", Duration.ofSeconds(1))
val answer = controller.sendAndWait(nextString + "\r", Duration.ofSeconds(1))
//String answer = controller.request(nextString);
System.out.printf("ANSWER (latency = %s): %s;%n", Duration.between(start, DateTimeUtils.now()), answer.trim { it <= ' ' })
} catch (ex: PortException) {

View File

@ -62,21 +62,21 @@ class MspDevice(context: Context, meta: Meta) : PortSensor(context, meta) {
// private var measurementDelegate: Consumer<MspResponse>? = null
val selected: Boolean by valueState("selected").boolean
val selected: Boolean by valueState("selected").booleanDelegate
var controlled: Boolean by valueState("controlled") { _, value ->
control(value.booleanValue())
}.boolean
}.booleanDelegate
var filament by valueState("filament") { old, value ->
selectFilament(value.intValue())
}.int
}.intDelegate
var filamentOn: Boolean by valueState("filamentOn") { _, value ->
setFilamentOn(value.booleanValue())
}.boolean
}.booleanDelegate
var peakJumpZero: Double by valueState("peakJump.zero").double
var peakJumpZero: Double by valueState("peakJump.zero").doubleDelegate
private val averagingDuration: Duration = Duration.parse(meta.getString("averagingDuration", "PT30S"))

View File

@ -32,7 +32,7 @@ import hep.dataforge.plots.data.TimePlot.Companion.setMaxItems
import hep.dataforge.plots.data.TimePlot.Companion.setPrefItems
import hep.dataforge.plots.jfreechart.JFreeChartFrame
import hep.dataforge.values.Value
import inr.numass.control.DeviceDisplay
import inr.numass.control.DeviceDisplayFX
import inr.numass.control.deviceStateIndicator
import inr.numass.control.deviceStateToggle
import inr.numass.control.switch
@ -53,7 +53,7 @@ import tornadofx.*
* @author darksnake
*/
class MspDisplay() : DeviceDisplay<MspDevice>(), DeviceListener, NamedValueListener {
class MspDisplay() : DeviceDisplayFX<MspDevice>(), DeviceListener, NamedValueListener {
private val table = FXCollections.observableHashMap<String, Value>()

View File

@ -0,0 +1,163 @@
package inr.numass.control
import hep.dataforge.connections.Connection
import hep.dataforge.control.connections.Roles
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.exceptions.NameNotFoundException
import hep.dataforge.fx.bindWindow
import hep.dataforge.states.State
import hep.dataforge.states.ValueState
import hep.dataforge.values.Value
import javafx.beans.binding.BooleanBinding
import javafx.beans.binding.ObjectBinding
import javafx.beans.property.BooleanProperty
import javafx.beans.property.SimpleObjectProperty
import javafx.geometry.Pos
import javafx.scene.Parent
import javafx.scene.layout.HBox
import javafx.scene.layout.Priority
import tornadofx.*
import java.util.*
import kotlin.reflect.KClass
import kotlin.reflect.full.createInstance
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
annotation class DeviceView(val value: KClass<out DeviceDisplayFX<*>>)
/**
* Get existing view connection or create a new one
*/
fun Device.getDisplay(): DeviceDisplayFX<*> {
val type = (this::class.annotations.find { it is DeviceView } as DeviceView?)?.value ?: DefaultDisplay::class
return optConnection(Roles.VIEW_ROLE, DeviceDisplayFX::class.java).orElseGet {
type.createInstance().also {
connect(it, Roles.VIEW_ROLE, Roles.DEVICE_LISTENER_ROLE);
}
}
}
/**
*
* An FX View to represent the device
* Created by darksnake on 14-May-17.
*/
abstract class DeviceDisplayFX<D : Device> : Component(), Connection, DeviceListener {
private val bindings = HashMap<String, ObjectBinding<*>>()
private val deviceProperty = SimpleObjectProperty<D>(this, "device", null)
val device: D by deviceProperty
// private val viewProperty = SimpleObjectProperty<UIComponent>(this, "view", null)
val view: UIComponent? by lazy {
buildView(device)
}
override fun isOpen(): Boolean = this.deviceProperty.get() != null
override fun open(obj: Any) {
if (!isOpen) {
@Suppress("UNCHECKED_CAST")
deviceProperty.set(obj as D)
} else {
log.warning("Connection already opened")
}
}
override fun close() {
if (isOpen) {
view?.close()
deviceProperty.set(null)
}
}
protected abstract fun buildView(device: D): UIComponent?;
/**
* Create a binding for specific state and register it in update listener
*/
private fun <T : Any> bindState(state: State<T>): ObjectBinding<T> {
val binding = object : ObjectBinding<T>() {
override fun computeValue(): T {
return state.value
}
}
bindings.putIfAbsent(state.name, binding)
return binding
}
fun valueBinding(state: ValueState): ObjectBinding<Value>{
return bindState(state)
}
fun valueBinding(stateName: String): ObjectBinding<Value> {
val state: ValueState = device.states.filterIsInstance(ValueState::class.java).find { it.name == stateName }
?: throw NameNotFoundException("State with name $stateName not found")
return valueBinding(state)
}
fun booleanBinding(stateName: String): BooleanBinding {
return valueBinding(stateName).booleanBinding { it?.booleanValue() ?: false }
}
/**
* Bind existing boolean property to writable device state
* @param state
* @param property
*/
protected fun bindBooleanToState(state: String, property: BooleanProperty) {
valueBinding(state).addListener { _, oldValue, newValue ->
if (isOpen && oldValue != newValue) {
runLater { property.value = newValue.booleanValue() }
}
}
property.addListener { _, oldValue, newValue ->
if (isOpen && oldValue != newValue) {
device.states[state] = newValue
}
}
}
override fun notifyStateChanged(device: Device, name: String, state: Any) {
bindings[name]?.invalidate()
}
open fun getBoardView(): Parent {
return HBox().apply {
alignment = Pos.CENTER_LEFT
vgrow = Priority.ALWAYS;
deviceStateIndicator(this@DeviceDisplayFX, Device.INITIALIZED_STATE)
deviceStateIndicator(this@DeviceDisplayFX, PortSensor.CONNECTED_STATE)
deviceStateIndicator(this@DeviceDisplayFX, Sensor.MEASURING_STATE)
deviceStateIndicator(this@DeviceDisplayFX, "storing")
pane {
hgrow = Priority.ALWAYS
}
togglebutton("View") {
isSelected = false
if (view == null) {
isDisable = true
}
view?.bindWindow(selectedProperty())
}
}
}
}
/**
* Default display shows only board pane and nothing else
*/
class DefaultDisplay : DeviceDisplayFX<Device>() {
override fun buildView(device: Device): UIComponent? = null
}

View File

@ -2,8 +2,8 @@ package inr.numass.control
import hep.dataforge.fx.plots.PlotContainer
import hep.dataforge.kodex.KMetaBuilder
import hep.dataforge.plots.Plot
import hep.dataforge.plots.PlotFrame
import hep.dataforge.plots.Plottable
import hep.dataforge.plots.jfreechart.JFreeChartFrame
import hep.dataforge.values.Value
import javafx.beans.value.ObservableValue
@ -17,7 +17,6 @@ import javafx.scene.shape.Circle
import javafx.scene.shape.StrokeType
import org.controlsfx.control.ToggleSwitch
import tornadofx.*
import java.util.*
/**
@ -74,7 +73,7 @@ class Indicator(radius: Double = 10.0) : Circle(radius, Color.GRAY) {
fun EventTarget.indicator(radius: Double = 10.0, op: (Indicator.() -> Unit) = {}): Indicator = opcr(this, Indicator(radius), op)
fun Indicator.bind(connection: DeviceDisplay<*>, state: String, transform: ((Value) -> Paint)? = null) {
fun Indicator.bind(connection: DeviceDisplayFX<*>, state: String, transform: ((Value) -> Paint)? = null) {
tooltip(state)
if (transform != null) {
bind(connection.getValueBinding(state), transform);
@ -92,7 +91,7 @@ fun Indicator.bind(connection: DeviceDisplay<*>, state: String, transform: ((Val
/**
* State name + indicator
*/
fun EventTarget.deviceStateIndicator(connection: DeviceDisplay<*>, state: String, showName: Boolean = true, transform: ((Value) -> Paint)? = null) {
fun EventTarget.deviceStateIndicator(connection: DeviceDisplayFX<*>, state: String, showName: Boolean = true, transform: ((Value) -> Paint)? = null) {
if (connection.device.stateNames.contains(state)) {
if (showName) {
text("${state.toUpperCase()}: ")
@ -109,7 +108,7 @@ fun EventTarget.deviceStateIndicator(connection: DeviceDisplay<*>, state: String
/**
* A togglebutton + indicator for boolean state
*/
fun Node.deviceStateToggle(connection: DeviceDisplay<*>, state: String, title: String = state) {
fun Node.deviceStateToggle(connection: DeviceDisplayFX<*>, state: String, title: String = state) {
if (connection.device.stateNames.contains(state)) {
togglebutton(title) {
isSelected = false
@ -136,11 +135,11 @@ fun EventTarget.switch(text: String = "", op: (ToggleSwitch.() -> Unit) = {}): T
/**
* Add frame
*/
fun BorderPane.plot(plottables: Iterable<Plot> = Collections.emptyList(), metaTransform: (KMetaBuilder.() -> Unit)? = null): PlotFrame {
fun BorderPane.plot(plottable: Plottable, metaTransform: (KMetaBuilder.() -> Unit)? = null): PlotFrame {
val meta = KMetaBuilder("plotFrame");
metaTransform?.invoke(meta)
val plot = JFreeChartFrame(meta)
plot.addAll(plottables)
center = PlotContainer(plot).root
return plot;
val frame = JFreeChartFrame(meta)
frame.add(plottable)
center = PlotContainer(frame).root
return frame;
}

View File

@ -34,25 +34,21 @@ class CM32Device(context: Context, meta: Meta) : PortSensor(context, meta) {
override fun startMeasurement(oldMeta: Meta?, newMeta: Meta) {
measurement {
doMeasure()
}
}
val answer = sendAndWait("MES R PM 1\r\n")
private fun doMeasure(): Meta{
val answer = sendAndWait("MES R PM 1\r\n")
return if (answer.isEmpty()) {
updateState(PortSensor.CONNECTED_STATE, false)
produceError("No signal")
} else if (!answer.contains("PM1:mbar")) {
updateState(PortSensor.CONNECTED_STATE, false)
produceError("Wrong answer: $answer")
} else if (answer.substring(14, 17) == "OFF") {
updateState(PortSensor.CONNECTED_STATE, true)
produceError("Off")
} else {
updateState(PortSensor.CONNECTED_STATE, true)
produceResult(answer.substring(14, 17) + answer.substring(19, 23))
if (answer.isEmpty()) {
updateState(PortSensor.CONNECTED_STATE, false)
notifyError("No signal")
} else if (!answer.contains("PM1:mbar")) {
updateState(PortSensor.CONNECTED_STATE, false)
notifyError("Wrong answer: $answer")
} else if (answer.substring(14, 17) == "OFF") {
updateState(PortSensor.CONNECTED_STATE, true)
notifyError("Off")
} else {
updateState(PortSensor.CONNECTED_STATE, true)
notifyResult(answer.substring(14, 17) + answer.substring(19, 23))
}
}
}

View File

@ -1,6 +1,8 @@
package inr.numass.control.readvac
import hep.dataforge.control.devices.Sensor
import hep.dataforge.control.devices.Sensor.Companion.RESULT_VALUE
import kotlinx.coroutines.experimental.runBlocking
import org.apache.commons.cli.DefaultParser
import org.apache.commons.cli.HelpFormatter
import org.apache.commons.cli.Options
@ -12,9 +14,9 @@ import java.time.Instant
* Created by darksnake on 06-Dec-16.
*/
object ConsoleVac {
private fun Sensor.read():Double{
private fun Sensor.read(): Double {
this.measure()
return runBlocking { resultState.future.await().getDouble(RESULT_VALUE)}
}
@Throws(Exception::class)

View File

@ -13,6 +13,7 @@ import hep.dataforge.control.ports.PortFactory
import hep.dataforge.description.ValueDef
import hep.dataforge.meta.Meta
import hep.dataforge.states.StateDef
import hep.dataforge.states.valueState
import hep.dataforge.values.ValueType
import inr.numass.control.DeviceView
@ -24,7 +25,7 @@ import inr.numass.control.DeviceView
@StateDef(value = ValueDef(name = "channel", type = [ValueType.NUMBER], def = "2"), writable = true)
class MKSBaratronDevice(context: Context, meta: Meta) : PortSensor(context, meta) {
var channel by intState("channel")
var channel by valueState("channel").intDelegate
override fun getType(): String {
return meta.getString("type", "numass.vac.baratron")
@ -38,24 +39,20 @@ class MKSBaratronDevice(context: Context, meta: Meta) : PortSensor(context, meta
override fun startMeasurement(oldMeta: Meta?, newMeta: Meta) {
measurement {
doMeasure()
}
}
private fun doMeasure(): Meta {
val answer = sendAndWait("AV$channel\r")
if (answer.isEmpty()) {
// invalidateState("connection");
updateState(PortSensor.CONNECTED_STATE, false)
return produceError("No connection")
} else {
updateState(PortSensor.CONNECTED_STATE, true)
}
val res = java.lang.Double.parseDouble(answer)
return if (res <= 0) {
produceError("Non positive")
} else {
produceResult(res)
val answer = sendAndWait("AV$channel\r")
if (answer.isEmpty()) {
// invalidateState("connection");
updateState(PortSensor.CONNECTED_STATE, false)
notifyError("No connection")
} else {
updateState(PortSensor.CONNECTED_STATE, true)
}
val res = java.lang.Double.parseDouble(answer)
if (res <= 0) {
notifyError("Non positive")
} else {
notifyResult(res)
}
}
}
}

View File

@ -43,7 +43,7 @@ class MKSVacDevice(context: Context, meta: Meta) : PortSensor(context, meta) {
if (old != value) {
setPowerOn(value.booleanValue())
}
}.boolean
}.booleanDelegate
@Throws(ControlException::class)

View File

@ -13,6 +13,7 @@ import hep.dataforge.control.ports.PortFactory
import hep.dataforge.description.ValueDef
import hep.dataforge.meta.Meta
import hep.dataforge.states.StateDef
import hep.dataforge.states.valueState
import hep.dataforge.values.ValueType.NUMBER
import java.math.BigDecimal
import java.math.BigInteger
@ -25,7 +26,7 @@ import java.util.regex.Pattern
@StateDef(value = ValueDef(name = "address", type = [NUMBER], def = "1", info = "A modbus address"), writable = true)
class MeradatVacDevice(context: Context, meta: Meta) : PortSensor(context, meta) {
var address by intState("address")
var address by valueState("address").intDelegate
override fun connect(meta: Meta): GenericPortController {
val port: Port = PortFactory.build(meta)
@ -40,43 +41,37 @@ class MeradatVacDevice(context: Context, meta: Meta) : PortSensor(context, meta)
override fun startMeasurement(oldMeta: Meta?, newMeta: Meta) {
measurement{
doMeasure()
}
}
val requestBase: String = String.format(":%02d", address)
val dataStr = requestBase.substring(1) + REQUEST
val query = requestBase + REQUEST + calculateLRC(dataStr) + "\r\n" // ":010300000002FA\r\n";
val response: Pattern = Pattern.compile(requestBase + "0304(\\w{4})(\\w{4})..\r\n")
val answer = sendAndWait(query) { phrase -> phrase.startsWith(requestBase) }
private fun doMeasure(): Meta {
val requestBase: String = String.format(":%02d", address)
val dataStr = requestBase.substring(1) + REQUEST
val query = requestBase + REQUEST + calculateLRC(dataStr) + "\r\n" // ":010300000002FA\r\n";
val response: Pattern = Pattern.compile(requestBase + "0304(\\w{4})(\\w{4})..\r\n")
val answer = sendAndWait(query) { phrase -> phrase.startsWith(requestBase) }
if (answer.isEmpty()) {
updateState(PortSensor.CONNECTED_STATE, false)
return produceError("No signal")
} else {
val match = response.matcher(answer)
return if (match.matches()) {
val base = Integer.parseInt(match.group(1), 16).toDouble() / 10.0
var exp = Integer.parseInt(match.group(2), 16)
if (exp > 32766) {
exp -= 65536
}
var res = BigDecimal.valueOf(base * Math.pow(10.0, exp.toDouble()))
res = res.setScale(4, RoundingMode.CEILING)
updateState(PortSensor.CONNECTED_STATE, true)
produceResult(res)
} else {
if (answer.isEmpty()) {
updateState(PortSensor.CONNECTED_STATE, false)
produceError("Wrong answer: $answer")
notifyError("No signal")
} else {
val match = response.matcher(answer)
if (match.matches()) {
val base = Integer.parseInt(match.group(1), 16).toDouble() / 10.0
var exp = Integer.parseInt(match.group(2), 16)
if (exp > 32766) {
exp -= 65536
}
var res = BigDecimal.valueOf(base * Math.pow(10.0, exp.toDouble()))
res = res.setScale(4, RoundingMode.CEILING)
updateState(PortSensor.CONNECTED_STATE, true)
notifyResult(res)
} else {
updateState(PortSensor.CONNECTED_STATE, false)
notifyError("Wrong answer: $answer")
}
}
}
}
companion object {
private const val REQUEST = "0300000002"

View File

@ -49,20 +49,16 @@ class VacCollectorDevice(context: Context, meta: Meta, val sensors: Collection<S
private val helper = StorageHelper(this, this::buildLoader)
private val collector = object : DeviceListener {
override fun notifyStateChanged(device: Device, name: String, state: Any) {
if (name == MEASUREMENT_RESULT_STATE) {
collector.put(device.name, (state as Meta).getValue("value"))
}
}
val averagingDuration: Duration = Duration.parse(meta.getString("averagingDuration", "PT30S"))
private val collector = RegularPointCollector(averagingDuration) {
notifyResult(it)
}
override fun notifyStateChanged(device: Device, name: String, state: Value) {
}
override fun notifyMetaStateChanged(device: Device, name: String, state: Meta) {
if (name == MEASUREMENT_RESULT_STATE) {
collector.put(device.name, state.getValue("value"))
}
}
}
@ -116,9 +112,11 @@ class VacCollectorDevice(context: Context, meta: Meta, val sensors: Collection<S
helper.push(values)
}
override fun onStateChange(stateName: String, oldState: Value?, newState: Value) {
override fun onStateChange(stateName: String, value: Any) {
if (stateName == MEASURING_STATE) {
if (!newState.booleanValue()) {
if (!(value as Value).booleanValue()) {
notifyResult(terminator())
}
}
@ -135,7 +133,7 @@ class VacCollectorDevice(context: Context, meta: Meta, val sensors: Collection<S
while (true) {
notifyMeasurementState(MeasurementState.IN_PROGRESS)
sensors.forEach { sensor ->
if (sensor.optBooleanState(CONNECTED_STATE).orElse(false)) {
if (sensor.states.getBoolean(CONNECTED_STATE,false)) {
sensor.measure()
}
}

View File

@ -12,9 +12,10 @@ import hep.dataforge.control.measurements.Measurement
import hep.dataforge.control.measurements.MeasurementListener
import hep.dataforge.fx.bindWindow
import hep.dataforge.fx.fragments.LogFragment
import hep.dataforge.plots.PlotGroup
import hep.dataforge.plots.data.TimePlot
import hep.dataforge.values.Value
import inr.numass.control.DeviceDisplay
import inr.numass.control.DeviceDisplayFX
import inr.numass.control.deviceStateToggle
import inr.numass.control.plot
import javafx.collections.FXCollections
@ -30,7 +31,7 @@ import java.time.Instant
* @author [Alexander Nozik](mailto:altavir@gmail.com)
*/
class VacCollectorDisplay : DeviceDisplay<VacCollectorDevice>() {
class VacCollectorDisplay : DeviceDisplayFX<VacCollectorDevice>() {
private val table = FXCollections.observableHashMap<String, Double>()
@ -48,7 +49,7 @@ class VacCollectorDisplay : DeviceDisplay<VacCollectorDevice>() {
private val viewList = FXCollections.observableArrayList<VacDisplay>();
override fun buildView(device: VacCollectorDevice): View {
override fun buildView(device: VacCollectorDevice): UIComponent {
return VacCollectorView();
}
@ -62,15 +63,15 @@ class VacCollectorDisplay : DeviceDisplay<VacCollectorDevice>() {
}
}
inner class VacCollectorView : View("Numass vacuum view") {
inner class VacCollectorView : Fragment("Numass vacuum view") {
private val plottables = TimePlottableGroup().apply {
private val plottables = PlotGroup.typed<TimePlot>("vac").apply {
viewList.forEach {
val plot = TimePlot(it.getTitle(), it.device.name)
plot.configure(it.device.meta)
add(plot)
}
setValue("thickness", 3)
configureValue("thickness", 3)
}
// private val logWindow = FragmentWindow(LogFragment().apply {
@ -127,13 +128,13 @@ class VacCollectorDisplay : DeviceDisplay<VacCollectorDevice>() {
init {
table.addListener { change: MapChangeListener.Change<out String, out Double> ->
if (change.wasAdded()) {
val pl = plottables.get(change.key)
val pl = plottables[change.key]
val value = change.valueAdded
if (pl != null) {
(pl as? TimePlot)?.let {
if (value > 0) {
pl.put(Value.of(value))
it.put(Value.of(value))
} else {
pl.put(Value.NULL)
it.put(Value.NULL)
}
}
}

View File

@ -34,7 +34,7 @@ class VacDeviceFactory : DeviceFactory {
return VacCollectorDevice(context, config, sensors)
}
// override fun buildView(device: Device): DeviceDisplay<VacCollectorDevice> {
// override fun buildView(device: Device): DeviceDisplayFX<VacCollectorDevice> {
// return VacCollectorDisplay();
// }
}

View File

@ -7,7 +7,7 @@ package inr.numass.control.readvac
import hep.dataforge.control.devices.PortSensor.Companion.CONNECTED_STATE
import hep.dataforge.control.devices.Sensor
import inr.numass.control.DeviceDisplay
import inr.numass.control.DeviceDisplayFX
import inr.numass.control.switch
import javafx.application.Platform
import javafx.beans.property.SimpleObjectProperty
@ -28,7 +28,7 @@ import java.time.format.DateTimeFormatter
/**
* @author [Alexander Nozik](mailto:altavir@gmail.com)
*/
open class VacDisplay : DeviceDisplay<Sensor>() {
open class VacDisplay : DeviceDisplayFX<Sensor>() {
val statusProperty = SimpleStringProperty("")
var status: String by statusProperty