Fix of config editor refresh. Multiple fixes in control.
This commit is contained in:
parent
0085ff3142
commit
af54525d41
@ -79,11 +79,11 @@ class PKT8Device(context: Context, meta: Meta) : PortSensor(context, meta) {
|
|||||||
tableFormatBuilder.build()
|
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"))
|
private val duration = Duration.parse(meta.getString("averagingDuration", "PT30S"))
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ import hep.dataforge.plots.PlotFrame
|
|||||||
import hep.dataforge.plots.PlotUtils
|
import hep.dataforge.plots.PlotUtils
|
||||||
import hep.dataforge.plots.data.TimePlot
|
import hep.dataforge.plots.data.TimePlot
|
||||||
import hep.dataforge.plots.jfreechart.JFreeChartFrame
|
import hep.dataforge.plots.jfreechart.JFreeChartFrame
|
||||||
import inr.numass.control.DeviceDisplay
|
import inr.numass.control.DeviceDisplayFX
|
||||||
import javafx.beans.binding.ListBinding
|
import javafx.beans.binding.ListBinding
|
||||||
import javafx.beans.property.SimpleObjectProperty
|
import javafx.beans.property.SimpleObjectProperty
|
||||||
import javafx.collections.FXCollections
|
import javafx.collections.FXCollections
|
||||||
@ -30,7 +30,7 @@ import java.time.Instant
|
|||||||
/**
|
/**
|
||||||
* Created by darksnake on 30-May-17.
|
* Created by darksnake on 30-May-17.
|
||||||
*/
|
*/
|
||||||
class PKT8Display : DeviceDisplay<PKT8Device>(), PKT8ValueListener {
|
class PKT8Display : DeviceDisplayFX<PKT8Device>(), PKT8ValueListener {
|
||||||
|
|
||||||
override fun buildView(device: PKT8Device) = CryoView()
|
override fun buildView(device: PKT8Device) = CryoView()
|
||||||
|
|
||||||
|
@ -17,9 +17,7 @@ package inr.numass.control.magnet
|
|||||||
|
|
||||||
import hep.dataforge.context.Context
|
import hep.dataforge.context.Context
|
||||||
import hep.dataforge.control.devices.AbstractDevice
|
import hep.dataforge.control.devices.AbstractDevice
|
||||||
import hep.dataforge.control.devices.booleanState
|
import hep.dataforge.control.ports.Port
|
||||||
import hep.dataforge.control.devices.doubleState
|
|
||||||
import hep.dataforge.control.devices.timeState
|
|
||||||
import hep.dataforge.control.ports.PortFactory
|
import hep.dataforge.control.ports.PortFactory
|
||||||
import hep.dataforge.description.ValueDef
|
import hep.dataforge.description.ValueDef
|
||||||
import hep.dataforge.exceptions.ControlException
|
import hep.dataforge.exceptions.ControlException
|
||||||
@ -27,12 +25,14 @@ import hep.dataforge.exceptions.PortException
|
|||||||
import hep.dataforge.meta.Meta
|
import hep.dataforge.meta.Meta
|
||||||
import hep.dataforge.states.StateDef
|
import hep.dataforge.states.StateDef
|
||||||
import hep.dataforge.states.StateDefs
|
import hep.dataforge.states.StateDefs
|
||||||
|
import hep.dataforge.states.valueState
|
||||||
import hep.dataforge.utils.DateTimeUtils
|
import hep.dataforge.utils.DateTimeUtils
|
||||||
import hep.dataforge.values.Value
|
|
||||||
import hep.dataforge.values.ValueType.*
|
import hep.dataforge.values.ValueType.*
|
||||||
|
import kotlinx.coroutines.experimental.runBlocking
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import java.text.DecimalFormat
|
import java.text.DecimalFormat
|
||||||
import java.time.Duration
|
import java.time.Duration
|
||||||
|
import java.time.Instant
|
||||||
import java.time.temporal.ChronoUnit
|
import java.time.temporal.ChronoUnit
|
||||||
import java.util.concurrent.Future
|
import java.util.concurrent.Future
|
||||||
import java.util.concurrent.ScheduledThreadPoolExecutor
|
import java.util.concurrent.ScheduledThreadPoolExecutor
|
||||||
@ -41,12 +41,12 @@ import java.util.concurrent.TimeUnit
|
|||||||
/**
|
/**
|
||||||
* @author Polina
|
* @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(
|
@StateDefs(
|
||||||
StateDef(value = ValueDef(name = "current", type = arrayOf(NUMBER), def = "0", info = "Current current")),
|
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 = "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 = "outCurrent", 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 = "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 = "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 = "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),
|
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 var closePortOnShutDown = false
|
||||||
|
|
||||||
private val name: String = meta.getString("name", "LAMBDA")
|
|
||||||
/**
|
/**
|
||||||
* @return the address
|
* @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)
|
private val scheduler = ScheduledThreadPoolExecutor(1)
|
||||||
|
|
||||||
var listener: MagnetStateListener? = null
|
//var listener: MagnetStateListener? = null
|
||||||
// private volatile double current = 0;
|
// private volatile double current = 0;
|
||||||
private val timeout: Duration = meta.optString("timeout").map<Duration> { Duration.parse(it) }.orElse(Duration.ofMillis(200))
|
private val timeout: Duration = meta.optString("timeout").map<Duration> { Duration.parse(it) }.orElse(Duration.ofMillis(200))
|
||||||
private var monitorTask: Future<*>? = null
|
private var monitorTask: Future<*>? = null
|
||||||
private var updateTask: Future<*>? = null
|
private var updateTask: Future<*>? = null
|
||||||
|
|
||||||
var lastUpdate by timeState()
|
var lastUpdate by valueState("lastUpdate", getter = {0}).timeDelegate
|
||||||
private set
|
private set
|
||||||
|
|
||||||
val current by doubleState()
|
// read-only values of current output
|
||||||
val voltage by doubleState()
|
val current = valueState("current", getter = { controller.talk(address, timeout) { s2d(getParameter("MC")) } })
|
||||||
var targetCurrent by doubleState()
|
// val current by current.double
|
||||||
var targetVoltage by doubleState()
|
|
||||||
var output by booleanState()
|
val voltage = valueState("voltage", getter = { controller.talk(address, timeout) { s2d(getParameter("MV")) } })
|
||||||
var monitoring by booleanState()
|
// 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
|
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)
|
@Throws(ControlException::class)
|
||||||
override fun init() {
|
override fun init() {
|
||||||
super.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?) {
|
// private fun reportError(errorMessage: String, error: Throwable?) {
|
||||||
listener?.error(getName(), errorMessage, error) ?: LoggerFactory.getLogger(javaClass).error(errorMessage, error)
|
// listener?.error(name, errorMessage, error) ?: LoggerFactory.getLogger(javaClass).error(errorMessage, error)
|
||||||
|
//
|
||||||
}
|
// }
|
||||||
|
|
||||||
@Throws(PortException::class)
|
@Throws(PortException::class)
|
||||||
private fun talk(request: String): String {
|
private fun talk(request: String): String {
|
||||||
try {
|
return try {
|
||||||
controller.send(request + "\r")
|
controller.send(request + "\r")
|
||||||
return controller.waitFor(timeout).trim()
|
controller.waitFor(timeout).trim()
|
||||||
} catch (tex: PortTimeoutException) {
|
} catch (tex: Port.PortTimeoutException) {
|
||||||
//Single retry on timeout
|
//Single retry on timeout
|
||||||
LoggerFactory.getLogger(javaClass).warn("A timeout exception for request '$request'. Making another attempt.")
|
LoggerFactory.getLogger(javaClass).warn("A timeout exception for request '$request'. Making another attempt.")
|
||||||
controller.send(request + "\r")
|
controller.send(request + "\r")
|
||||||
return controller.waitFor(timeout).trim()
|
controller.waitFor(timeout).trim()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun update(key: String, value: String) {
|
// private fun update(key: String, value: String) {
|
||||||
when (key) {
|
// when (key) {
|
||||||
"OUT" -> updateState("output", value == "ON")
|
// "OUT" -> updateState("output", value == "ON")
|
||||||
"MC" -> updateState("current", s2d(value))
|
// "MC" -> updateState("current", s2d(value))
|
||||||
"PC" -> updateState("targetCurrent", s2d(value))
|
// "PC" -> updateState("outCurrent", s2d(value))
|
||||||
"MV" -> updateState("voltage", s2d(value))
|
// "MV" -> updateState("voltage", s2d(value))
|
||||||
"PV" -> updateState("targetVoltage", s2d(value))
|
// "PV" -> updateState("outVoltage", s2d(value))
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
@Throws(PortException::class)
|
@Throws(PortException::class)
|
||||||
private fun getParameter(name: String): String = talk(name + "?")
|
private fun getParameter(name: String): String = talk("$name?")
|
||||||
|
|
||||||
@Throws(PortException::class)
|
@Throws(PortException::class)
|
||||||
private fun setParameter(key: String, state: String): Boolean = "OK" == talk("$key $state")
|
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
|
* Cancel current update task
|
||||||
*/
|
*/
|
||||||
fun stopUpdateTask() {
|
fun stopUpdateTask() {
|
||||||
updateTask?.let {
|
updateTask?.cancel(false)
|
||||||
it.cancel(false)
|
|
||||||
lastUpdate = null
|
|
||||||
listener?.updateTaskStateChanged(getName(), false)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -268,48 +230,44 @@ open class LambdaMagnet(context: Context, meta: Meta, private val controller: La
|
|||||||
stopUpdateTask()
|
stopUpdateTask()
|
||||||
val call = {
|
val call = {
|
||||||
try {
|
try {
|
||||||
val measuredI = current ?: 0.0
|
val measuredI = current.doubleValue
|
||||||
val targetI = targetCurrent ?: 0.0
|
val targetI = target.doubleValue
|
||||||
listener?.acceptMeasuredI(getName(), measuredI)
|
updateState("current",measuredI)
|
||||||
if (Math.abs(measuredI - targetI) > CURRENT_PRECISION) {
|
if (Math.abs(measuredI - targetI) > CURRENT_PRECISION) {
|
||||||
val nextI = nextI(measuredI, targetI)
|
val nextI = nextI(measuredI, targetI)
|
||||||
listener?.acceptNextI(getName(), nextI)
|
outCurrent = nextI
|
||||||
targetCurrent = nextI
|
|
||||||
} else {
|
} else {
|
||||||
stopUpdateTask()
|
stopUpdateTask()
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (ex: PortException) {
|
} catch (ex: PortException) {
|
||||||
reportError("Error in update task", ex)
|
notifyError("Error in update task", ex)
|
||||||
stopUpdateTask()
|
stopUpdateTask()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateTask = scheduler.scheduleWithFixedDelay(call, 0, delay.toLong(), TimeUnit.MILLISECONDS)
|
updateTask = scheduler.scheduleWithFixedDelay(call, 0, delay.toLong(), TimeUnit.MILLISECONDS)
|
||||||
listener?.updateTaskStateChanged(getName(), true)
|
updateState("updating", true)
|
||||||
updateState("updating", Value.of(true))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(PortException::class)
|
@Throws(PortException::class)
|
||||||
private fun setOutputMode(out: Boolean) {
|
private fun setOutputMode(out: Boolean) {
|
||||||
val outState: Int = if (out) 1 else 0
|
val outState: Int = if (out) 1 else 0
|
||||||
if (!setParameter("OUT", outState)) {
|
if (!setParameter("OUT", outState)) {
|
||||||
listener?.error(getName(), "Can't set output mode", null)
|
notifyError("Can't set output mode")
|
||||||
} else {
|
} else {
|
||||||
requestStateChange("output", Value.of(out))
|
updateState("output", out)
|
||||||
listener?.outputModeChanged(getName(), out)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun nextI(measuredI: Double, targetI: Double): Double {
|
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
|
MIN_UP_STEP_SIZE
|
||||||
} else {
|
} else {
|
||||||
//Choose optimal speed but do not exceed maximum speed
|
//Choose optimal speed but do not exceed maximum speed
|
||||||
Math.min(MAX_STEP_SIZE,
|
Math.min(MAX_STEP_SIZE, lastUpdate.until(DateTimeUtils.now(), ChronoUnit.MILLIS).toDouble() / 60000.0 * speed)
|
||||||
lastUpdate!!.until(DateTimeUtils.now(), ChronoUnit.MILLIS).toDouble() / 60000.0 * speed)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val res = if (targetI > measuredI) {
|
val res = if (targetI > measuredI) {
|
||||||
@ -336,18 +294,8 @@ open class LambdaMagnet(context: Context, meta: Meta, private val controller: La
|
|||||||
private fun stopMonitorTask() {
|
private fun stopMonitorTask() {
|
||||||
monitorTask?.let {
|
monitorTask?.let {
|
||||||
it.cancel(true)
|
it.cancel(true)
|
||||||
listener?.monitorTaskStateChanged(getName(), false)
|
|
||||||
monitorTask = null
|
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
|
* @param delay an interval between scans in milliseconds
|
||||||
*/
|
*/
|
||||||
@JvmOverloads
|
private fun startMonitorTask(delay: Int = DEFAULT_MONITOR_DELAY) {
|
||||||
fun startMonitorTask(delay: Int = DEFAULT_MONITOR_DELAY) {
|
|
||||||
assert(delay >= 1000)
|
assert(delay >= 1000)
|
||||||
stopMonitorTask()
|
stopMonitorTask()
|
||||||
|
|
||||||
|
|
||||||
val call = Runnable {
|
val call = Runnable {
|
||||||
try {
|
try {
|
||||||
status
|
runBlocking {
|
||||||
|
states["voltage"]?.read()
|
||||||
|
states["current"]?.read()
|
||||||
|
}
|
||||||
} catch (ex: PortException) {
|
} catch (ex: PortException) {
|
||||||
reportError("Port connection exception during status measurement", ex)
|
notifyError("Port connection exception during status measurement", ex)
|
||||||
stopMonitorTask()
|
stopMonitorTask()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
monitorTask = scheduler.scheduleWithFixedDelay(call, 0, delay.toLong(), TimeUnit.MILLISECONDS)
|
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 {
|
companion object {
|
||||||
|
|
||||||
private val LAMBDA_FORMAT = DecimalFormat("###.##")
|
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)
|
private fun d2s(d: Double): String = LAMBDA_FORMAT.format(d)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,8 +55,8 @@ class SafeLambdaMagnet(context: Context, meta: Meta, controller: LambdaPortContr
|
|||||||
* @param tolerance
|
* @param tolerance
|
||||||
*/
|
*/
|
||||||
fun bindTo(controller: SafeLambdaMagnet, tolerance: Double) {
|
fun bindTo(controller: SafeLambdaMagnet, tolerance: Double) {
|
||||||
this.addSafeCondition(false) { I -> Math.abs(controller.getCurrent() - I) <= tolerance }
|
this.addSafeCondition(false) { I -> Math.abs(controller.current - I) <= tolerance }
|
||||||
controller.addSafeCondition(false) { I -> Math.abs(this.getCurrent() - 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 {
|
interface SafeMagnetCondition {
|
||||||
|
@ -18,7 +18,6 @@ package inr.numass.control.magnet.fx
|
|||||||
import ch.qos.logback.classic.Level
|
import ch.qos.logback.classic.Level
|
||||||
import ch.qos.logback.classic.spi.ILoggingEvent
|
import ch.qos.logback.classic.spi.ILoggingEvent
|
||||||
import ch.qos.logback.core.FileAppender
|
import ch.qos.logback.core.FileAppender
|
||||||
import hep.dataforge.context.Global
|
|
||||||
import hep.dataforge.exceptions.ControlException
|
import hep.dataforge.exceptions.ControlException
|
||||||
import hep.dataforge.io.MetaFileReader
|
import hep.dataforge.io.MetaFileReader
|
||||||
import inr.numass.control.magnet.LambdaHub
|
import inr.numass.control.magnet.LambdaHub
|
||||||
@ -44,14 +43,13 @@ class MagnetControllerApp : Application() {
|
|||||||
// internal var controllers: MutableList<SafeLambdaMagnet> = ArrayList()
|
// internal var controllers: MutableList<SafeLambdaMagnet> = ArrayList()
|
||||||
|
|
||||||
private lateinit var device: LambdaHub
|
private lateinit var device: LambdaHub
|
||||||
val context = Global.instance()
|
|
||||||
|
|
||||||
@Throws(IOException::class, ControlException::class)
|
@Throws(IOException::class, ControlException::class)
|
||||||
override fun start(stage: Stage) {
|
override fun start(stage: Stage) {
|
||||||
Locale.setDefault(Locale.US)// чтобы отделение десятичных знаков было точкой
|
Locale.setDefault(Locale.US)// чтобы отделение десятичных знаков было точкой
|
||||||
val rootLogger = LoggerFactory.getLogger(ch.qos.logback.classic.Logger.ROOT_LOGGER_NAME) as ch.qos.logback.classic.Logger
|
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)
|
rootLogger.level = Level.valueOf(logLevel)
|
||||||
|
|
||||||
@ -69,8 +67,6 @@ class MagnetControllerApp : Application() {
|
|||||||
|
|
||||||
val config = MetaFileReader.instance().read(context,)
|
val config = MetaFileReader.instance().read(context,)
|
||||||
|
|
||||||
device =
|
|
||||||
|
|
||||||
// val portName = (parameters.named as java.util.Map<String, String>).getOrDefault("port", "virtual")
|
// val portName = (parameters.named as java.util.Map<String, String>).getOrDefault("port", "virtual")
|
||||||
//
|
//
|
||||||
// if (portName == "virtual") {
|
// if (portName == "virtual") {
|
||||||
|
@ -16,20 +16,17 @@
|
|||||||
package inr.numass.control.magnet.fx
|
package inr.numass.control.magnet.fx
|
||||||
|
|
||||||
import hep.dataforge.exceptions.PortException
|
import hep.dataforge.exceptions.PortException
|
||||||
|
import inr.numass.control.DeviceDisplayFX
|
||||||
import inr.numass.control.magnet.LambdaMagnet
|
import inr.numass.control.magnet.LambdaMagnet
|
||||||
import inr.numass.control.magnet.MagnetStateListener
|
|
||||||
import inr.numass.control.magnet.MagnetStatus
|
|
||||||
import javafx.application.Platform
|
import javafx.application.Platform
|
||||||
import javafx.beans.value.ObservableValue
|
import javafx.beans.value.ObservableValue
|
||||||
import javafx.event.ActionEvent
|
import javafx.event.ActionEvent
|
||||||
import javafx.fxml.FXML
|
import javafx.fxml.FXML
|
||||||
import javafx.fxml.FXMLLoader
|
|
||||||
import javafx.fxml.Initializable
|
import javafx.fxml.Initializable
|
||||||
import javafx.scene.control.*
|
import javafx.scene.control.*
|
||||||
import javafx.scene.layout.AnchorPane
|
import javafx.scene.layout.AnchorPane
|
||||||
import javafx.scene.paint.Color
|
import javafx.scene.paint.Color
|
||||||
import org.slf4j.Logger
|
import tornadofx.*
|
||||||
import org.slf4j.LoggerFactory
|
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@ -38,250 +35,221 @@ import java.util.*
|
|||||||
*
|
*
|
||||||
* @author Alexander Nozik
|
* @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
|
val current by lazy { valueBinding(device.voltage)}
|
||||||
/**
|
|
||||||
* @return the logger
|
|
||||||
*/
|
|
||||||
var logger: Logger? = null
|
|
||||||
private set
|
|
||||||
|
|
||||||
private var showConfirmation = true
|
val voltage by lazy { valueBinding(device.current)}
|
||||||
|
|
||||||
@FXML
|
var target by device.target.doubleDelegate
|
||||||
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
|
|
||||||
|
|
||||||
private val targetI: Double
|
var output by device.output.booleanDelegate
|
||||||
get() = java.lang.Double.parseDouble(targetIField!!.text)
|
|
||||||
|
|
||||||
// public MagnetControllerComponent(LambdaMagnet lambdaMagnet) {
|
var monitoring by device.monitoring.booleanDelegate
|
||||||
// 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) {
|
|
||||||
|
|
||||||
targetIField!!.textProperty().addListener { observable: ObservableValue<out String>, oldValue: String, newValue: String ->
|
var updating by device.updating.booleanDelegate
|
||||||
if (!newValue.matches("\\d*(\\.)?\\d*".toRegex())) {
|
|
||||||
targetIField.text = oldValue
|
|
||||||
|
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 ->
|
fun setShowConfirmation(showConfirmation: Boolean) {
|
||||||
if (!newValue.matches("\\d*(\\.)?\\d*".toRegex())) {
|
this.showConfirmation = showConfirmation
|
||||||
magnetSpeedField.text = oldValue
|
}
|
||||||
|
|
||||||
|
@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)
|
if (alert.showAndWait().orElse(ButtonType.CANCEL) == ButtonType.YES) {
|
||||||
private fun setOutput(outputOn: Boolean) {
|
startCurrentChange()
|
||||||
if (outputOn) {
|
} else {
|
||||||
if (showConfirmation) {
|
setButton.isSelected = false
|
||||||
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()
|
|
||||||
} else {
|
} else {
|
||||||
setButton!!.isSelected = false
|
startCurrentChange()
|
||||||
}
|
}
|
||||||
} else {
|
} 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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
@Throws(PortException::class)
|
||||||
|
private fun startCurrentChange() {
|
||||||
@FXML
|
val speed = java.lang.Double.parseDouble(magnetSpeedField.text)
|
||||||
private fun onMonitorToggle(event: ActionEvent) {
|
if (speed > 0 && speed <= 7) {
|
||||||
if (monitorButton!!.isSelected) {
|
device.speed = speed
|
||||||
getLambdaMagnet().startMonitorTask()
|
magnetSpeedField.isDisable = true
|
||||||
} else {
|
target = targetIField.text.toDouble()
|
||||||
getLambdaMagnet().stopMonitorTask()
|
output = true
|
||||||
this.labelU!!.text = "----"
|
updating = true
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
} else {
|
} else {
|
||||||
this.statusLabel!!.text = "OFF"
|
val alert = Alert(Alert.AlertType.ERROR)
|
||||||
this.statusLabel.textFill = Color.BLACK
|
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ package inr.numass.control.magnet.fx
|
|||||||
|
|
||||||
import ch.qos.logback.classic.Level
|
import ch.qos.logback.classic.Level
|
||||||
import ch.qos.logback.classic.Logger
|
import ch.qos.logback.classic.Logger
|
||||||
|
import hep.dataforge.context.Global
|
||||||
import hep.dataforge.control.ports.GenericPortController
|
import hep.dataforge.control.ports.GenericPortController
|
||||||
import hep.dataforge.control.ports.Port
|
import hep.dataforge.control.ports.Port
|
||||||
import hep.dataforge.control.ports.PortFactory
|
import hep.dataforge.control.ports.PortFactory
|
||||||
@ -57,7 +58,7 @@ object Talk {
|
|||||||
}
|
}
|
||||||
val handler: Port
|
val handler: Port
|
||||||
handler = PortFactory.build(portName)
|
handler = PortFactory.build(portName)
|
||||||
handler.setPhraseCondition { str: String -> str.endsWith("\r") }
|
val controller = GenericPortController(Global,handler,"\r")
|
||||||
|
|
||||||
// LambdaMagnet controller = new LambdaMagnet(handler, 1);
|
// LambdaMagnet controller = new LambdaMagnet(handler, 1);
|
||||||
val reader = BufferedReader(InputStreamReader(System.`in`))
|
val reader = BufferedReader(InputStreamReader(System.`in`))
|
||||||
@ -68,7 +69,7 @@ object Talk {
|
|||||||
while ("exit" != nextString) {
|
while ("exit" != nextString) {
|
||||||
try {
|
try {
|
||||||
val start = DateTimeUtils.now()
|
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);
|
//String answer = controller.request(nextString);
|
||||||
System.out.printf("ANSWER (latency = %s): %s;%n", Duration.between(start, DateTimeUtils.now()), answer.trim { it <= ' ' })
|
System.out.printf("ANSWER (latency = %s): %s;%n", Duration.between(start, DateTimeUtils.now()), answer.trim { it <= ' ' })
|
||||||
} catch (ex: PortException) {
|
} catch (ex: PortException) {
|
||||||
|
@ -62,21 +62,21 @@ class MspDevice(context: Context, meta: Meta) : PortSensor(context, meta) {
|
|||||||
|
|
||||||
// private var measurementDelegate: Consumer<MspResponse>? = null
|
// 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 ->
|
var controlled: Boolean by valueState("controlled") { _, value ->
|
||||||
control(value.booleanValue())
|
control(value.booleanValue())
|
||||||
}.boolean
|
}.booleanDelegate
|
||||||
|
|
||||||
var filament by valueState("filament") { old, value ->
|
var filament by valueState("filament") { old, value ->
|
||||||
selectFilament(value.intValue())
|
selectFilament(value.intValue())
|
||||||
}.int
|
}.intDelegate
|
||||||
|
|
||||||
var filamentOn: Boolean by valueState("filamentOn") { _, value ->
|
var filamentOn: Boolean by valueState("filamentOn") { _, value ->
|
||||||
setFilamentOn(value.booleanValue())
|
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"))
|
private val averagingDuration: Duration = Duration.parse(meta.getString("averagingDuration", "PT30S"))
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ import hep.dataforge.plots.data.TimePlot.Companion.setMaxItems
|
|||||||
import hep.dataforge.plots.data.TimePlot.Companion.setPrefItems
|
import hep.dataforge.plots.data.TimePlot.Companion.setPrefItems
|
||||||
import hep.dataforge.plots.jfreechart.JFreeChartFrame
|
import hep.dataforge.plots.jfreechart.JFreeChartFrame
|
||||||
import hep.dataforge.values.Value
|
import hep.dataforge.values.Value
|
||||||
import inr.numass.control.DeviceDisplay
|
import inr.numass.control.DeviceDisplayFX
|
||||||
import inr.numass.control.deviceStateIndicator
|
import inr.numass.control.deviceStateIndicator
|
||||||
import inr.numass.control.deviceStateToggle
|
import inr.numass.control.deviceStateToggle
|
||||||
import inr.numass.control.switch
|
import inr.numass.control.switch
|
||||||
@ -53,7 +53,7 @@ import tornadofx.*
|
|||||||
|
|
||||||
* @author darksnake
|
* @author darksnake
|
||||||
*/
|
*/
|
||||||
class MspDisplay() : DeviceDisplay<MspDevice>(), DeviceListener, NamedValueListener {
|
class MspDisplay() : DeviceDisplayFX<MspDevice>(), DeviceListener, NamedValueListener {
|
||||||
|
|
||||||
private val table = FXCollections.observableHashMap<String, Value>()
|
private val table = FXCollections.observableHashMap<String, Value>()
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
|
@ -2,8 +2,8 @@ package inr.numass.control
|
|||||||
|
|
||||||
import hep.dataforge.fx.plots.PlotContainer
|
import hep.dataforge.fx.plots.PlotContainer
|
||||||
import hep.dataforge.kodex.KMetaBuilder
|
import hep.dataforge.kodex.KMetaBuilder
|
||||||
import hep.dataforge.plots.Plot
|
|
||||||
import hep.dataforge.plots.PlotFrame
|
import hep.dataforge.plots.PlotFrame
|
||||||
|
import hep.dataforge.plots.Plottable
|
||||||
import hep.dataforge.plots.jfreechart.JFreeChartFrame
|
import hep.dataforge.plots.jfreechart.JFreeChartFrame
|
||||||
import hep.dataforge.values.Value
|
import hep.dataforge.values.Value
|
||||||
import javafx.beans.value.ObservableValue
|
import javafx.beans.value.ObservableValue
|
||||||
@ -17,7 +17,6 @@ import javafx.scene.shape.Circle
|
|||||||
import javafx.scene.shape.StrokeType
|
import javafx.scene.shape.StrokeType
|
||||||
import org.controlsfx.control.ToggleSwitch
|
import org.controlsfx.control.ToggleSwitch
|
||||||
import tornadofx.*
|
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 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)
|
tooltip(state)
|
||||||
if (transform != null) {
|
if (transform != null) {
|
||||||
bind(connection.getValueBinding(state), transform);
|
bind(connection.getValueBinding(state), transform);
|
||||||
@ -92,7 +91,7 @@ fun Indicator.bind(connection: DeviceDisplay<*>, state: String, transform: ((Val
|
|||||||
/**
|
/**
|
||||||
* State name + indicator
|
* 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 (connection.device.stateNames.contains(state)) {
|
||||||
if (showName) {
|
if (showName) {
|
||||||
text("${state.toUpperCase()}: ")
|
text("${state.toUpperCase()}: ")
|
||||||
@ -109,7 +108,7 @@ fun EventTarget.deviceStateIndicator(connection: DeviceDisplay<*>, state: String
|
|||||||
/**
|
/**
|
||||||
* A togglebutton + indicator for boolean state
|
* 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)) {
|
if (connection.device.stateNames.contains(state)) {
|
||||||
togglebutton(title) {
|
togglebutton(title) {
|
||||||
isSelected = false
|
isSelected = false
|
||||||
@ -136,11 +135,11 @@ fun EventTarget.switch(text: String = "", op: (ToggleSwitch.() -> Unit) = {}): T
|
|||||||
/**
|
/**
|
||||||
* Add frame
|
* 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");
|
val meta = KMetaBuilder("plotFrame");
|
||||||
metaTransform?.invoke(meta)
|
metaTransform?.invoke(meta)
|
||||||
val plot = JFreeChartFrame(meta)
|
val frame = JFreeChartFrame(meta)
|
||||||
plot.addAll(plottables)
|
frame.add(plottable)
|
||||||
center = PlotContainer(plot).root
|
center = PlotContainer(frame).root
|
||||||
return plot;
|
return frame;
|
||||||
}
|
}
|
@ -34,25 +34,21 @@ class CM32Device(context: Context, meta: Meta) : PortSensor(context, meta) {
|
|||||||
|
|
||||||
override fun startMeasurement(oldMeta: Meta?, newMeta: Meta) {
|
override fun startMeasurement(oldMeta: Meta?, newMeta: Meta) {
|
||||||
measurement {
|
measurement {
|
||||||
doMeasure()
|
val answer = sendAndWait("MES R PM 1\r\n")
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun doMeasure(): Meta{
|
if (answer.isEmpty()) {
|
||||||
val answer = sendAndWait("MES R PM 1\r\n")
|
updateState(PortSensor.CONNECTED_STATE, false)
|
||||||
|
notifyError("No signal")
|
||||||
return if (answer.isEmpty()) {
|
} else if (!answer.contains("PM1:mbar")) {
|
||||||
updateState(PortSensor.CONNECTED_STATE, false)
|
updateState(PortSensor.CONNECTED_STATE, false)
|
||||||
produceError("No signal")
|
notifyError("Wrong answer: $answer")
|
||||||
} else if (!answer.contains("PM1:mbar")) {
|
} else if (answer.substring(14, 17) == "OFF") {
|
||||||
updateState(PortSensor.CONNECTED_STATE, false)
|
updateState(PortSensor.CONNECTED_STATE, true)
|
||||||
produceError("Wrong answer: $answer")
|
notifyError("Off")
|
||||||
} else if (answer.substring(14, 17) == "OFF") {
|
} else {
|
||||||
updateState(PortSensor.CONNECTED_STATE, true)
|
updateState(PortSensor.CONNECTED_STATE, true)
|
||||||
produceError("Off")
|
notifyResult(answer.substring(14, 17) + answer.substring(19, 23))
|
||||||
} else {
|
}
|
||||||
updateState(PortSensor.CONNECTED_STATE, true)
|
|
||||||
produceResult(answer.substring(14, 17) + answer.substring(19, 23))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package inr.numass.control.readvac
|
package inr.numass.control.readvac
|
||||||
|
|
||||||
import hep.dataforge.control.devices.Sensor
|
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.DefaultParser
|
||||||
import org.apache.commons.cli.HelpFormatter
|
import org.apache.commons.cli.HelpFormatter
|
||||||
import org.apache.commons.cli.Options
|
import org.apache.commons.cli.Options
|
||||||
@ -12,9 +14,9 @@ import java.time.Instant
|
|||||||
* Created by darksnake on 06-Dec-16.
|
* Created by darksnake on 06-Dec-16.
|
||||||
*/
|
*/
|
||||||
object ConsoleVac {
|
object ConsoleVac {
|
||||||
private fun Sensor.read():Double{
|
private fun Sensor.read(): Double {
|
||||||
this.measure()
|
this.measure()
|
||||||
|
return runBlocking { resultState.future.await().getDouble(RESULT_VALUE)}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(Exception::class)
|
@Throws(Exception::class)
|
||||||
|
@ -13,6 +13,7 @@ import hep.dataforge.control.ports.PortFactory
|
|||||||
import hep.dataforge.description.ValueDef
|
import hep.dataforge.description.ValueDef
|
||||||
import hep.dataforge.meta.Meta
|
import hep.dataforge.meta.Meta
|
||||||
import hep.dataforge.states.StateDef
|
import hep.dataforge.states.StateDef
|
||||||
|
import hep.dataforge.states.valueState
|
||||||
import hep.dataforge.values.ValueType
|
import hep.dataforge.values.ValueType
|
||||||
import inr.numass.control.DeviceView
|
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)
|
@StateDef(value = ValueDef(name = "channel", type = [ValueType.NUMBER], def = "2"), writable = true)
|
||||||
class MKSBaratronDevice(context: Context, meta: Meta) : PortSensor(context, meta) {
|
class MKSBaratronDevice(context: Context, meta: Meta) : PortSensor(context, meta) {
|
||||||
|
|
||||||
var channel by intState("channel")
|
var channel by valueState("channel").intDelegate
|
||||||
|
|
||||||
override fun getType(): String {
|
override fun getType(): String {
|
||||||
return meta.getString("type", "numass.vac.baratron")
|
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) {
|
override fun startMeasurement(oldMeta: Meta?, newMeta: Meta) {
|
||||||
measurement {
|
measurement {
|
||||||
doMeasure()
|
val answer = sendAndWait("AV$channel\r")
|
||||||
}
|
if (answer.isEmpty()) {
|
||||||
}
|
// invalidateState("connection");
|
||||||
|
updateState(PortSensor.CONNECTED_STATE, false)
|
||||||
private fun doMeasure(): Meta {
|
notifyError("No connection")
|
||||||
val answer = sendAndWait("AV$channel\r")
|
} else {
|
||||||
if (answer.isEmpty()) {
|
updateState(PortSensor.CONNECTED_STATE, true)
|
||||||
// invalidateState("connection");
|
}
|
||||||
updateState(PortSensor.CONNECTED_STATE, false)
|
val res = java.lang.Double.parseDouble(answer)
|
||||||
return produceError("No connection")
|
if (res <= 0) {
|
||||||
} else {
|
notifyError("Non positive")
|
||||||
updateState(PortSensor.CONNECTED_STATE, true)
|
} else {
|
||||||
}
|
notifyResult(res)
|
||||||
val res = java.lang.Double.parseDouble(answer)
|
}
|
||||||
return if (res <= 0) {
|
|
||||||
produceError("Non positive")
|
|
||||||
} else {
|
|
||||||
produceResult(res)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,7 @@ class MKSVacDevice(context: Context, meta: Meta) : PortSensor(context, meta) {
|
|||||||
if (old != value) {
|
if (old != value) {
|
||||||
setPowerOn(value.booleanValue())
|
setPowerOn(value.booleanValue())
|
||||||
}
|
}
|
||||||
}.boolean
|
}.booleanDelegate
|
||||||
|
|
||||||
|
|
||||||
@Throws(ControlException::class)
|
@Throws(ControlException::class)
|
||||||
|
@ -13,6 +13,7 @@ import hep.dataforge.control.ports.PortFactory
|
|||||||
import hep.dataforge.description.ValueDef
|
import hep.dataforge.description.ValueDef
|
||||||
import hep.dataforge.meta.Meta
|
import hep.dataforge.meta.Meta
|
||||||
import hep.dataforge.states.StateDef
|
import hep.dataforge.states.StateDef
|
||||||
|
import hep.dataforge.states.valueState
|
||||||
import hep.dataforge.values.ValueType.NUMBER
|
import hep.dataforge.values.ValueType.NUMBER
|
||||||
import java.math.BigDecimal
|
import java.math.BigDecimal
|
||||||
import java.math.BigInteger
|
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)
|
@StateDef(value = ValueDef(name = "address", type = [NUMBER], def = "1", info = "A modbus address"), writable = true)
|
||||||
class MeradatVacDevice(context: Context, meta: Meta) : PortSensor(context, meta) {
|
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 {
|
override fun connect(meta: Meta): GenericPortController {
|
||||||
val port: Port = PortFactory.build(meta)
|
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) {
|
override fun startMeasurement(oldMeta: Meta?, newMeta: Meta) {
|
||||||
measurement{
|
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 {
|
if (answer.isEmpty()) {
|
||||||
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 {
|
|
||||||
updateState(PortSensor.CONNECTED_STATE, false)
|
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 {
|
companion object {
|
||||||
private const val REQUEST = "0300000002"
|
private const val REQUEST = "0300000002"
|
||||||
|
|
||||||
|
@ -49,20 +49,16 @@ class VacCollectorDevice(context: Context, meta: Meta, val sensors: Collection<S
|
|||||||
private val helper = StorageHelper(this, this::buildLoader)
|
private val helper = StorageHelper(this, this::buildLoader)
|
||||||
|
|
||||||
private val collector = object : DeviceListener {
|
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"))
|
val averagingDuration: Duration = Duration.parse(meta.getString("averagingDuration", "PT30S"))
|
||||||
private val collector = RegularPointCollector(averagingDuration) {
|
private val collector = RegularPointCollector(averagingDuration) {
|
||||||
notifyResult(it)
|
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)
|
helper.push(values)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStateChange(stateName: String, oldState: Value?, newState: Value) {
|
|
||||||
|
|
||||||
|
override fun onStateChange(stateName: String, value: Any) {
|
||||||
if (stateName == MEASURING_STATE) {
|
if (stateName == MEASURING_STATE) {
|
||||||
if (!newState.booleanValue()) {
|
if (!(value as Value).booleanValue()) {
|
||||||
notifyResult(terminator())
|
notifyResult(terminator())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -135,7 +133,7 @@ class VacCollectorDevice(context: Context, meta: Meta, val sensors: Collection<S
|
|||||||
while (true) {
|
while (true) {
|
||||||
notifyMeasurementState(MeasurementState.IN_PROGRESS)
|
notifyMeasurementState(MeasurementState.IN_PROGRESS)
|
||||||
sensors.forEach { sensor ->
|
sensors.forEach { sensor ->
|
||||||
if (sensor.optBooleanState(CONNECTED_STATE).orElse(false)) {
|
if (sensor.states.getBoolean(CONNECTED_STATE,false)) {
|
||||||
sensor.measure()
|
sensor.measure()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,9 +12,10 @@ import hep.dataforge.control.measurements.Measurement
|
|||||||
import hep.dataforge.control.measurements.MeasurementListener
|
import hep.dataforge.control.measurements.MeasurementListener
|
||||||
import hep.dataforge.fx.bindWindow
|
import hep.dataforge.fx.bindWindow
|
||||||
import hep.dataforge.fx.fragments.LogFragment
|
import hep.dataforge.fx.fragments.LogFragment
|
||||||
|
import hep.dataforge.plots.PlotGroup
|
||||||
import hep.dataforge.plots.data.TimePlot
|
import hep.dataforge.plots.data.TimePlot
|
||||||
import hep.dataforge.values.Value
|
import hep.dataforge.values.Value
|
||||||
import inr.numass.control.DeviceDisplay
|
import inr.numass.control.DeviceDisplayFX
|
||||||
import inr.numass.control.deviceStateToggle
|
import inr.numass.control.deviceStateToggle
|
||||||
import inr.numass.control.plot
|
import inr.numass.control.plot
|
||||||
import javafx.collections.FXCollections
|
import javafx.collections.FXCollections
|
||||||
@ -30,7 +31,7 @@ import java.time.Instant
|
|||||||
|
|
||||||
* @author [Alexander Nozik](mailto:altavir@gmail.com)
|
* @author [Alexander Nozik](mailto:altavir@gmail.com)
|
||||||
*/
|
*/
|
||||||
class VacCollectorDisplay : DeviceDisplay<VacCollectorDevice>() {
|
class VacCollectorDisplay : DeviceDisplayFX<VacCollectorDevice>() {
|
||||||
|
|
||||||
private val table = FXCollections.observableHashMap<String, Double>()
|
private val table = FXCollections.observableHashMap<String, Double>()
|
||||||
|
|
||||||
@ -48,7 +49,7 @@ class VacCollectorDisplay : DeviceDisplay<VacCollectorDevice>() {
|
|||||||
|
|
||||||
private val viewList = FXCollections.observableArrayList<VacDisplay>();
|
private val viewList = FXCollections.observableArrayList<VacDisplay>();
|
||||||
|
|
||||||
override fun buildView(device: VacCollectorDevice): View {
|
override fun buildView(device: VacCollectorDevice): UIComponent {
|
||||||
return VacCollectorView();
|
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 {
|
viewList.forEach {
|
||||||
val plot = TimePlot(it.getTitle(), it.device.name)
|
val plot = TimePlot(it.getTitle(), it.device.name)
|
||||||
plot.configure(it.device.meta)
|
plot.configure(it.device.meta)
|
||||||
add(plot)
|
add(plot)
|
||||||
}
|
}
|
||||||
setValue("thickness", 3)
|
configureValue("thickness", 3)
|
||||||
}
|
}
|
||||||
|
|
||||||
// private val logWindow = FragmentWindow(LogFragment().apply {
|
// private val logWindow = FragmentWindow(LogFragment().apply {
|
||||||
@ -127,13 +128,13 @@ class VacCollectorDisplay : DeviceDisplay<VacCollectorDevice>() {
|
|||||||
init {
|
init {
|
||||||
table.addListener { change: MapChangeListener.Change<out String, out Double> ->
|
table.addListener { change: MapChangeListener.Change<out String, out Double> ->
|
||||||
if (change.wasAdded()) {
|
if (change.wasAdded()) {
|
||||||
val pl = plottables.get(change.key)
|
val pl = plottables[change.key]
|
||||||
val value = change.valueAdded
|
val value = change.valueAdded
|
||||||
if (pl != null) {
|
(pl as? TimePlot)?.let {
|
||||||
if (value > 0) {
|
if (value > 0) {
|
||||||
pl.put(Value.of(value))
|
it.put(Value.of(value))
|
||||||
} else {
|
} else {
|
||||||
pl.put(Value.NULL)
|
it.put(Value.NULL)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ class VacDeviceFactory : DeviceFactory {
|
|||||||
return VacCollectorDevice(context, config, sensors)
|
return VacCollectorDevice(context, config, sensors)
|
||||||
}
|
}
|
||||||
|
|
||||||
// override fun buildView(device: Device): DeviceDisplay<VacCollectorDevice> {
|
// override fun buildView(device: Device): DeviceDisplayFX<VacCollectorDevice> {
|
||||||
// return VacCollectorDisplay();
|
// return VacCollectorDisplay();
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ package inr.numass.control.readvac
|
|||||||
|
|
||||||
import hep.dataforge.control.devices.PortSensor.Companion.CONNECTED_STATE
|
import hep.dataforge.control.devices.PortSensor.Companion.CONNECTED_STATE
|
||||||
import hep.dataforge.control.devices.Sensor
|
import hep.dataforge.control.devices.Sensor
|
||||||
import inr.numass.control.DeviceDisplay
|
import inr.numass.control.DeviceDisplayFX
|
||||||
import inr.numass.control.switch
|
import inr.numass.control.switch
|
||||||
import javafx.application.Platform
|
import javafx.application.Platform
|
||||||
import javafx.beans.property.SimpleObjectProperty
|
import javafx.beans.property.SimpleObjectProperty
|
||||||
@ -28,7 +28,7 @@ import java.time.format.DateTimeFormatter
|
|||||||
/**
|
/**
|
||||||
* @author [Alexander Nozik](mailto:altavir@gmail.com)
|
* @author [Alexander Nozik](mailto:altavir@gmail.com)
|
||||||
*/
|
*/
|
||||||
open class VacDisplay : DeviceDisplay<Sensor>() {
|
open class VacDisplay : DeviceDisplayFX<Sensor>() {
|
||||||
|
|
||||||
val statusProperty = SimpleStringProperty("")
|
val statusProperty = SimpleStringProperty("")
|
||||||
var status: String by statusProperty
|
var status: String by statusProperty
|
||||||
|
Loading…
Reference in New Issue
Block a user