diff --git a/numass-control/cryotemp/src/main/kotlin/inr/numass/control/cryotemp/PKT8App.kt b/numass-control/cryotemp/src/main/kotlin/inr/numass/control/cryotemp/PKT8App.kt index bb35be23..d3391cab 100644 --- a/numass-control/cryotemp/src/main/kotlin/inr/numass/control/cryotemp/PKT8App.kt +++ b/numass-control/cryotemp/src/main/kotlin/inr/numass/control/cryotemp/PKT8App.kt @@ -16,6 +16,7 @@ package inr.numass.control.cryotemp import hep.dataforge.meta.Meta +import hep.dataforge.meta.MetaUtils import inr.numass.control.NumassControlApplication import javafx.stage.Stage @@ -32,9 +33,7 @@ class PKT8App : NumassControlApplication() { stage.minWidth = 400.0 } - override fun acceptDevice(meta: Meta): Boolean { - return meta.getString("type") == "PKT8" + override fun getDeviceMeta(config: Meta): Meta { + return MetaUtils.findNode(config,"device"){it.getString("name") == "numass.temp"}.orElseThrow{RuntimeException("Temperature measurement configuration not found")} } - - } diff --git a/numass-control/cryotemp/src/main/kotlin/inr/numass/control/cryotemp/PKT8Device.kt b/numass-control/cryotemp/src/main/kotlin/inr/numass/control/cryotemp/PKT8Device.kt index d646bf7b..383b118d 100644 --- a/numass-control/cryotemp/src/main/kotlin/inr/numass/control/cryotemp/PKT8Device.kt +++ b/numass-control/cryotemp/src/main/kotlin/inr/numass/control/cryotemp/PKT8Device.kt @@ -274,7 +274,7 @@ class PKT8Device(context: Context, meta: Meta) : PortSensor(context, meta) { //send start signal it.send("s") notifyMeasurementState(MeasurementState.IN_PROGRESS) - } ?: notifyError("Not connected") + } } diff --git a/numass-control/magnet/build.gradle b/numass-control/magnet/build.gradle index 6bdcfeba..ea7023b2 100644 --- a/numass-control/magnet/build.gradle +++ b/numass-control/magnet/build.gradle @@ -3,7 +3,7 @@ apply plugin: 'application' version = "0.3.0" if (!hasProperty('mainClass')) { - ext.mainClass = 'inr.numass.control.magnet.fx.MagnetControllerApp' + ext.mainClass = 'inr.numass.control.magnet.fx.MagnetApp' } mainClassName = mainClass @@ -21,4 +21,12 @@ task talkToServer(type: JavaExec) { classpath = sourceSets.main.runtimeClasspath standardInput = System.in standardOutput = System.out +} + +task emulate(type: JavaExec){ + group = "application" + main = mainClassName + description = "Test magnet controller with virtual device configuration" + classpath = sourceSets.main.runtimeClasspath + args = ["--config.resource=debug.xml"] } \ No newline at end of file diff --git a/numass-control/magnet/src/main/kotlin/inr/numass/control/magnet/LambdaHub.kt b/numass-control/magnet/src/main/kotlin/inr/numass/control/magnet/LambdaHub.kt index 7874dc02..4c63010b 100644 --- a/numass-control/magnet/src/main/kotlin/inr/numass/control/magnet/LambdaHub.kt +++ b/numass-control/magnet/src/main/kotlin/inr/numass/control/magnet/LambdaHub.kt @@ -26,16 +26,20 @@ class LambdaHub(context: Context, meta: Meta) : DeviceHub, AbstractDevice(contex init { meta.useEachMeta("magnet") { - magnets.add(LambdaMagnet(context, it, controller)) + magnets.add(LambdaMagnet(controller, it)) + } + + meta.useEachMeta("bind") { + TODO("add binding") } } - private fun buildPort(): Port{ - val portName = meta.getString("port"); - return if(portName.startsWith("virtual")){ - VirtualLambdaPort(meta) + private fun buildPort(): Port { + val portMeta = meta.getMetaOrEmpty("port") + return if(portMeta.getString("type") == "debug"){ + VirtualLambdaPort(portMeta) } else{ - PortFactory.build(portName); + PortFactory.build(portMeta) } } diff --git a/numass-control/magnet/src/main/kotlin/inr/numass/control/magnet/LambdaMagnet.kt b/numass-control/magnet/src/main/kotlin/inr/numass/control/magnet/LambdaMagnet.kt index 98b3d5b3..6b2c10c2 100644 --- a/numass-control/magnet/src/main/kotlin/inr/numass/control/magnet/LambdaMagnet.kt +++ b/numass-control/magnet/src/main/kotlin/inr/numass/control/magnet/LambdaMagnet.kt @@ -22,6 +22,7 @@ import hep.dataforge.control.ports.PortFactory import hep.dataforge.description.ValueDef import hep.dataforge.exceptions.ControlException import hep.dataforge.exceptions.PortException +import hep.dataforge.kodex.buildMeta import hep.dataforge.meta.Meta import hep.dataforge.states.StateDef import hep.dataforge.states.StateDefs @@ -29,9 +30,6 @@ import hep.dataforge.states.valueState import hep.dataforge.utils.DateTimeUtils 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 @@ -41,7 +39,7 @@ import java.util.concurrent.TimeUnit /** * @author Polina */ -@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")), @@ -51,9 +49,10 @@ import java.util.concurrent.TimeUnit 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 = "monitoring", type = arrayOf(BOOLEAN), def = "false", info = "Shows if monitoring task is running"), writable = true), - StateDef(value = ValueDef(name = "speed", type = arrayOf(NUMBER), info = "Current change speed in Amper per minute"), writable = true) + StateDef(value = ValueDef(name = "speed", type = arrayOf(NUMBER), info = "Current change speed in Ampere per minute"), writable = true), + StateDef(ValueDef(name = "state", type = [STRING], def = "INIT", enumeration = LambdaMagnet.MagnetState::class, info = "Current state of magnet operation")) ) -open class LambdaMagnet(context: Context, meta: Meta, private val controller: LambdaPortController) : AbstractDevice(context, meta) { +class LambdaMagnet(private val controller: LambdaPortController, meta: Meta) : AbstractDevice(controller.context, meta) { private var closePortOnShutDown = false @@ -67,25 +66,23 @@ open class LambdaMagnet(context: Context, meta: Meta, private val controller: La //var listener: MagnetStateListener? = null // private volatile double current = 0; - private val timeout: Duration = meta.optString("timeout").map { Duration.parse(it) }.orElse(Duration.ofMillis(200)) + private var monitorTask: Future<*>? = null private var updateTask: Future<*>? = null - var lastUpdate by valueState("lastUpdate", getter = {0}).timeDelegate + var lastUpdate by valueState("lastUpdate", getter = { 0 }).timeDelegate private set // read-only values of current output - val current = valueState("current", getter = { controller.talk(address, timeout) { s2d(getParameter("MC")) } }) -// val current by current.double + val current = valueState("current", getter = { s2d(controller.getParameter(address, "MC")) }) - val voltage = valueState("voltage", getter = { controller.talk(address, timeout) { s2d(getParameter("MV")) } }) -// val voltage by voltage.double + val voltage = valueState("voltage", getter = { s2d(controller.getParameter(address, "MV")) }) 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())) { + private var outCurrent by valueState("outCurrent", getter = { s2d(controller.getParameter(address, "PC")) }) { _, value -> + if (controller.setParameter(address, "PC", value.doubleValue())) { lastUpdate = DateTimeUtils.now() } else { notifyError("Can't set the target current") @@ -93,18 +90,21 @@ open class LambdaMagnet(context: Context, meta: Meta, private val controller: La return@valueState value }.doubleDelegate - private val outVoltage = valueState("outVoltage", getter = { controller.talk(address, timeout) { s2d(getParameter("PV")) } }) { _, value -> - if (!setParameter("PV", value.doubleValue())) { + private val outVoltage = valueState("outVoltage", getter = { s2d(controller.getParameter(address, "PV")) }) { _, value -> + if (!controller.setParameter(address, "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 -> + val output = valueState("output", getter = { controller.talk(address, "OUT?") == "OK" }) { _, value -> setOutputMode(value.booleanValue()) + if (!value.booleanValue()) { + state = MagnetState.OFF + } } - var monitoring =valueState("monitoring", getter = { monitorTask != null }) { _, value -> + var monitoring = valueState("monitoring", getter = { monitorTask != null }) { _, value -> if (value.booleanValue()) { startMonitorTask() } else { @@ -113,6 +113,9 @@ open class LambdaMagnet(context: Context, meta: Meta, private val controller: La return@valueState value } + /** + * + */ var updating = valueState("updating", getter = { updateTask != null }) { _, value -> if (value.booleanValue()) { startUpdateTask() @@ -124,11 +127,20 @@ open class LambdaMagnet(context: Context, meta: Meta, private val controller: La /** - * current change speed in Amper per minute + * current change speed in Ampere per minute * * @param speed */ - var speed = MAX_SPEED + var speed by valueState("speed").doubleDelegate + + + var state by valueState("state").enumDelegate() + private set + + /** + * The binding limit for magnet current + */ + var bound: (Double) -> Boolean = { it < meta.getDouble("maxCurrent") } /** * A setup for single magnet controller @@ -138,10 +150,12 @@ open class LambdaMagnet(context: Context, meta: Meta, private val controller: La * @throws ControlException */ @Throws(ControlException::class) - constructor(context: Context, meta: Meta) : this(context, meta, LambdaPortController(context, PortFactory.build(meta.getString("port")))) { + constructor(context: Context, meta: Meta) : this(LambdaPortController(context, PortFactory.build(meta.getString("port"))), meta) { closePortOnShutDown = true } + constructor(context: Context, port: Port, address: Int) : this(LambdaPortController(context, port), buildMeta { "address" to address }) + @Throws(ControlException::class) override fun init() { super.init() @@ -162,46 +176,6 @@ open class LambdaMagnet(context: Context, meta: Meta, private val controller: La } -// 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 { - return try { - controller.send(request + "\r") - 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") - 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("outCurrent", s2d(value)) -// "MV" -> updateState("voltage", s2d(value)) -// "PV" -> updateState("outVoltage", s2d(value)) -// } -// } - - @Throws(PortException::class) - private fun getParameter(name: String): String = talk("$name?") - - @Throws(PortException::class) - private fun setParameter(key: String, state: String): Boolean = "OK" == talk("$key $state") - - @Throws(PortException::class) - private fun setParameter(key: String, state: Int): Boolean = setParameter(key, state.toString()) - - @Throws(PortException::class) - private fun setParameter(key: String, state: Double): Boolean = setParameter(key, d2s(state)) - /** * Extract number from LAMBDA response * @@ -232,10 +206,15 @@ open class LambdaMagnet(context: Context, meta: Meta, private val controller: La try { val measuredI = current.doubleValue val targetI = target.doubleValue - updateState("current",measuredI) + updateState("current", measuredI) if (Math.abs(measuredI - targetI) > CURRENT_PRECISION) { val nextI = nextI(measuredI, targetI) - outCurrent = nextI + if (bound(nextI)) { + outCurrent = nextI + state = MagnetState.OK + } else { + state = MagnetState.BOUND + } } else { stopUpdateTask() } @@ -253,7 +232,7 @@ open class LambdaMagnet(context: Context, meta: Meta, private val controller: La @Throws(PortException::class) private fun setOutputMode(out: Boolean) { val outState: Int = if (out) 1 else 0 - if (!setParameter("OUT", outState)) { + if (!controller.setParameter(address, "OUT", outState)) { notifyError("Can't set output mode") } else { updateState("output", out) @@ -261,7 +240,6 @@ open class LambdaMagnet(context: Context, meta: Meta, private val controller: La } private fun nextI(measuredI: Double, targetI: Double): Double { -// assert(measuredI != target) var step = if (lastUpdate == Instant.EPOCH) { MIN_UP_STEP_SIZE @@ -325,9 +303,26 @@ open class LambdaMagnet(context: Context, meta: Meta, private val controller: La } + /** + * Add symmetric non-blocking conditions to ensure currents in two magnets have difference within given value. + * @param controller + * @param difference + */ + fun bindTo(controller: LambdaMagnet, difference: Double) { + this.bound = { i -> Math.abs(controller.current.doubleValue - i) <= difference } + controller.bound = { i -> Math.abs(this.current.doubleValue - i) <= difference } + } + + enum class MagnetState { + INIT, // no information + OFF, // Magnet output is off + OK, // Magnet ouput is on + ERROR, // Some error + BOUND // Magnet in bound mode + } + companion object { - private val LAMBDA_FORMAT = DecimalFormat("###.##") const val CURRENT_PRECISION = 0.05 const val DEFAULT_DELAY = 1 const val DEFAULT_MONITOR_DELAY = 2000 @@ -336,13 +331,6 @@ open class LambdaMagnet(context: Context, meta: Meta, private val controller: La const val MIN_DOWN_STEP_SIZE = 0.05 const val MAX_SPEED = 5.0 // 5 A per minute - /** - * Method converts double to LAMBDA string - * - * @param d double that should be converted to string - * @return string - */ - private fun d2s(d: Double): String = LAMBDA_FORMAT.format(d) } } diff --git a/numass-control/magnet/src/main/kotlin/inr/numass/control/magnet/LambdaPortController.kt b/numass-control/magnet/src/main/kotlin/inr/numass/control/magnet/LambdaPortController.kt index eacfe9bf..b55855c7 100644 --- a/numass-control/magnet/src/main/kotlin/inr/numass/control/magnet/LambdaPortController.kt +++ b/numass-control/magnet/src/main/kotlin/inr/numass/control/magnet/LambdaPortController.kt @@ -3,11 +3,17 @@ package inr.numass.control.magnet import hep.dataforge.context.Context import hep.dataforge.control.ports.GenericPortController import hep.dataforge.control.ports.Port +import hep.dataforge.exceptions.PortException +import org.slf4j.LoggerFactory +import java.text.DecimalFormat import java.time.Duration +//@ValueDef(name = "timeout", type = [(ValueType.NUMBER)], def = "400", info = "A timeout for port response") class LambdaPortController(context: Context, port: Port) : GenericPortController(context, port) { private var currentAddress: Int = -1; + private val timeout: Duration = port.meta.optString("timeout").map { Duration.parse(it) }.orElse(Duration.ofMillis(200)) + private fun setAddress(address: Int, timeout: Duration) { val response = sendAndWait("ADR $address\r", timeout) { true }.trim() if (response == "OK") { @@ -20,10 +26,47 @@ class LambdaPortController(context: Context, port: Port) : GenericPortController /** * perform series of synchronous actions ensuring that all of them have the same address */ - fun talk(address: Int, timeout: Duration, action: (GenericPortController) -> R): R { + private fun talk(address: Int, action: GenericPortController.() -> R): R { synchronized(this) { setAddress(address, timeout) - return action(this) + return this.action() } } + + + @Throws(PortException::class) + fun talk(addres: Int, request: String): String { + return talk(addres) { + try { + send(request + "\r") + waitFor(timeout).trim() + } catch (tex: Port.PortTimeoutException) { + //Single retry on timeout + LoggerFactory.getLogger(javaClass).warn("A timeout exception for request '$request'. Making another attempt.") + send(request + "\r") + waitFor(timeout).trim() + } + } + } + + fun getParameter(address: Int, name: String): String = talk(address, "$name?") + + fun setParameter(address: Int, key: String, state: String): Boolean = "OK" == talk(address, "$key $state") + + fun setParameter(address: Int, key: String, state: Int): Boolean = setParameter(address, key, state.toString()) + + fun setParameter(address: Int, key: String, state: Double): Boolean = setParameter(address, key, d2s(state)) + + + companion object { + private val LAMBDA_FORMAT = DecimalFormat("###.##") + /** + * Method converts double to LAMBDA string + * + * @param d double that should be converted to string + * @return string + */ + private fun d2s(d: Double): String = LAMBDA_FORMAT.format(d) + + } } \ No newline at end of file diff --git a/numass-control/magnet/src/main/kotlin/inr/numass/control/magnet/MagnetStateListener.kt b/numass-control/magnet/src/main/kotlin/inr/numass/control/magnet/MagnetStateListener.kt deleted file mode 100644 index 32e43418..00000000 --- a/numass-control/magnet/src/main/kotlin/inr/numass/control/magnet/MagnetStateListener.kt +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package inr.numass.control.magnet - -/** - * - * @author Alexander Nozik - */ -interface MagnetStateListener { - - fun acceptStatus(name: String, state: MagnetStatus) - - fun acceptNextI(name: String, nextI: Double) - - fun acceptMeasuredI(name: String, measuredI: Double) - - open fun displayState(state: String) { - - } - - open fun error(name: String, errorMessage: String, throwable: Throwable?) { - throw RuntimeException(errorMessage, throwable) - } - - open fun monitorTaskStateChanged(name: String, monitorTaskRunning: Boolean) { - - } - - open fun updateTaskStateChanged(name: String, updateTaskRunning: Boolean) { - - } - - open fun outputModeChanged(name: String, out: Boolean) { - - } - - fun addressChanged(name: String, address: Int) { - - } - -} diff --git a/numass-control/magnet/src/main/kotlin/inr/numass/control/magnet/MagnetStatus.kt b/numass-control/magnet/src/main/kotlin/inr/numass/control/magnet/MagnetStatus.kt deleted file mode 100644 index 12d39ed9..00000000 --- a/numass-control/magnet/src/main/kotlin/inr/numass/control/magnet/MagnetStatus.kt +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package inr.numass.control.magnet - -/** - * - * @author Polina - */ -class MagnetStatus( - /** - * @return the isOut - */ - val isOutputOn: Boolean, - /** - * @return the measuredCurrent - */ - val measuredCurrent: Double, - /** - * @return the setCurrent - */ - val setCurrent: Double, - /** - * @return the measuredVoltage - */ - val measuredVoltage: Double, - /** - * @return the setVoltage - */ - val setVoltage: Double) { - - /** - * @return the isOn - */ - var isOn: Boolean = false - private set - - init { - this.isOn = true - } - - companion object { - - fun off(): MagnetStatus { - val res = MagnetStatus(false, 0.0, 0.0, 0.0, 0.0) - res.isOn = false - return res - } - } - -} diff --git a/numass-control/magnet/src/main/kotlin/inr/numass/control/magnet/SafeLambdaMagnet.kt b/numass-control/magnet/src/main/kotlin/inr/numass/control/magnet/SafeLambdaMagnet.kt deleted file mode 100644 index f1e2caf4..00000000 --- a/numass-control/magnet/src/main/kotlin/inr/numass/control/magnet/SafeLambdaMagnet.kt +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package inr.numass.control.magnet - -import hep.dataforge.context.Context -import hep.dataforge.exceptions.PortException -import hep.dataforge.meta.Meta -import org.slf4j.LoggerFactory -import java.util.* - -/** - * - * @author Polina - */ -class SafeLambdaMagnet(context: Context, meta: Meta, controller: LambdaPortController) : - LambdaMagnet(context, meta, controller) { - - private val safeConditions = HashSet() - - // public SafeLambdaMagnet(String name, Port port, int address, int timeout, SafeMagnetCondition... safeConditions) { - // super(name, port, address, timeout); - // this.safeConditions.addAll(Arrays.asList(safeConditions)); - // } - // - // public SafeLambdaMagnet(String name, Port port, int address, SafeMagnetCondition... safeConditions) { - // super(name, port, address); - // this.safeConditions.addAll(Arrays.asList(safeConditions)); - // } - - fun addSafeCondition(isBlocking: Boolean, condition: (Double) -> Boolean) { - this.safeConditions.add(object : SafeMagnetCondition { - - override fun isBlocking(): Boolean = isBlocking - - override fun isSafe(address: Int, current: Double): Boolean = condition(current) - }) - } - - /** - * Add symmetric non-blocking conditions to ensure currents in two magnets have difference within given tolerance. - * @param controller - * @param tolerance - */ - fun bindTo(controller: SafeLambdaMagnet, tolerance: Double) { - this.addSafeCondition(false) { I -> Math.abs(controller.current - I) <= tolerance } - controller.addSafeCondition(false) { I -> Math.abs(this.current - I) <= tolerance } - } - - - @Throws(PortException::class) - override fun setCurrent(current: Double) { - safeConditions - .filterNot { it.isSafe(address, current) } - .forEach { - if (it.isBlocking()) { - it.onFail() - throw RuntimeException("Can't set current. Condition not satisfied.") - } else { - listener?.displayState("BOUND") - } - } - - super.current = current - } - - interface SafeMagnetCondition { - - fun isBlocking(): Boolean = true - - fun isSafe(address: Int, current: Double): Boolean - - fun onFail() { - LoggerFactory.getLogger(javaClass).error("Can't set current. Condition not satisfied.") - } - } - -} diff --git a/numass-control/magnet/src/main/kotlin/inr/numass/control/magnet/TestController.kt b/numass-control/magnet/src/main/kotlin/inr/numass/control/magnet/TestController.kt deleted file mode 100644 index 577a2bec..00000000 --- a/numass-control/magnet/src/main/kotlin/inr/numass/control/magnet/TestController.kt +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package inr.numass.control.magnet - -import hep.dataforge.control.ports.Port -import java.util.* - -/** - * - * @author Alexander Nozik - */ -object TestController { - - /** - * @param args the command line arguments - * @throws java.lang.Exception - */ - @Throws(Exception::class) - @JvmStatic - fun main(args: Array) { - Locale.setDefault(Locale.US)// чтобы отделение десятичных знаков было точкой - // ch.qos.logback.classic.Logger rootLogger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(ch.qos.logback.classic.Logger.ROOT_LOGGER_NAME); - // rootLogger.setLevel(Level.INFO); - - val handler: Port - val firstController: LambdaMagnet - val secondController: LambdaMagnet - - // String comName = "COM12"; - // handler = new ComPort(comName); - handler = VirtualLambdaPort("COM12", 1, 2, 3, 4) - - firstController = LambdaMagnet(handler, 1) - // secondController = new LambdaMagnet(handler, 4); - secondController = SafeLambdaMagnet("TEST", handler, 4, { address: Int, current: Double -> current < 1.0 }) - - val listener = object : MagnetStateListener { - - override fun acceptStatus(name: String, state: MagnetStatus) { - System.out.printf("%s (%s): Im = %f, Um = %f, Is = %f, Us = %f;%n", - name, - state.isOutputOn, - state.measuredCurrent, - state.measuredVoltage, - state.setCurrent, - state.setVoltage - ) - } - - override fun acceptNextI(name: String, nextI: Double) { - System.out.printf("%s: nextI = %f;%n", name, nextI) - } - - override fun acceptMeasuredI(name: String, measuredI: Double) { - System.out.printf("%s: measuredI = %f;%n", name, measuredI) - } - } - - firstController.listener = listener - secondController.listener = listener - - try { - firstController.startMonitorTask(2000) - secondController.startMonitorTask(2000) - secondController.setOutputMode(true) - secondController.startUpdateTask(2.0, 1000) - System.`in`.read() - firstController.stopMonitorTask() - secondController.stopMonitorTask() - secondController.stopUpdateTask() - secondController.setOutputMode(false) - } finally { - // handler.close(); - } - } - -} diff --git a/numass-control/magnet/src/main/kotlin/inr/numass/control/magnet/TestSynch.kt b/numass-control/magnet/src/main/kotlin/inr/numass/control/magnet/TestSynch.kt deleted file mode 100644 index 4325a1b1..00000000 --- a/numass-control/magnet/src/main/kotlin/inr/numass/control/magnet/TestSynch.kt +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package inr.numass.control.magnet - -import ch.qos.logback.classic.Level -import hep.dataforge.control.ports.Port -import org.slf4j.LoggerFactory -import java.util.* - -/** - * - * @author Alexander Nozik - */ -object TestSynch { - - private val firstCurrent = 0.0 - - /** - * @param args the command line arguments - * @throws java.lang.Exception - */ - @Throws(Exception::class) - @JvmStatic - fun main(args: Array) { - Locale.setDefault(Locale.US)// чтобы отделение десятичных знаков было точкой - val rootLogger = LoggerFactory.getLogger(ch.qos.logback.classic.Logger.ROOT_LOGGER_NAME) as ch.qos.logback.classic.Logger - rootLogger.level = Level.INFO - - val handler: Port - val firstController: LambdaMagnet - val secondController: LambdaMagnet - - // String comName = "COM12"; - // handler = new ComPort(comName); - handler = VirtualLambdaPort("COM12", 1, 2, 3, 4) - - firstController = LambdaMagnet(handler, 1) - // secondController = new LambdaMagnet(handler, 2); - secondController = SafeLambdaMagnet("TEST", handler, 2, - object : SafeLambdaMagnet.SafeMagnetCondition { - - // @Override - // public boolean isBlocking() { - // return false; - // } - override fun onFail() { - java.awt.Toolkit.getDefaultToolkit().beep() - - } - - override fun isSafe(address: Int, current: Double): Boolean { - return Math.abs(current - firstCurrent) <= 0.2 - } - }) - - val listener = object : MagnetStateListener { - - override fun acceptStatus(name: String, state: MagnetStatus) { - System.out.printf("%s (%s): Im = %f, Um = %f, Is = %f, Us = %f;%n", - name, - state.isOutputOn, - state.measuredCurrent, - state.measuredVoltage, - state.setCurrent, - state.setVoltage - ) - } - - override fun acceptNextI(name: String, nextI: Double) { - System.out.printf("%s: nextI = %f;%n", name, nextI) - } - - override fun acceptMeasuredI(name: String, measuredI: Double) { - System.out.printf("%s: measuredI = %f;%n", name, measuredI) - } - } - - firstController.listener = listener - secondController.listener = listener - - try { - firstController.startMonitorTask(2000) - secondController.startMonitorTask(2000) - secondController.setOutputMode(true) - firstController.setOutputMode(true) - firstController.startUpdateTask(1.0, 10) - secondController.startUpdateTask(2.0, 10) - System.`in`.read() - firstController.stopMonitorTask() - secondController.stopMonitorTask() - secondController.stopUpdateTask() - firstController.stopUpdateTask() - secondController.setOutputMode(false) - firstController.setOutputMode(false) - System.exit(0) - } finally { - // handler.close(); - } - } - -} diff --git a/numass-control/magnet/src/main/kotlin/inr/numass/control/magnet/VirtualLambdaPort.kt b/numass-control/magnet/src/main/kotlin/inr/numass/control/magnet/VirtualLambdaPort.kt index 47b09a34..2e232a24 100644 --- a/numass-control/magnet/src/main/kotlin/inr/numass/control/magnet/VirtualLambdaPort.kt +++ b/numass-control/magnet/src/main/kotlin/inr/numass/control/magnet/VirtualLambdaPort.kt @@ -16,7 +16,7 @@ package inr.numass.control.magnet import hep.dataforge.control.ports.VirtualPort -import hep.dataforge.exceptions.PortException +import hep.dataforge.kodex.useEachMeta import hep.dataforge.meta.Meta import org.slf4j.LoggerFactory import java.time.Duration @@ -30,29 +30,17 @@ class VirtualLambdaPort(meta: Meta) : VirtualPort(meta) { @Volatile private var currentAddress = -1 private val magnets = HashMap() - private val virtualPortName: String = meta.getString("name", "virtual::numass.lambda") - -// constructor(portName: String, magnets: Map) { -// this.virtualPortName = portName -// magnets.forEach { key, value -> this.magnets.put(key, VirtualMagnetStatus(value)) } -// } -// -// constructor(portName: String, vararg magnets: Int) { -// this.virtualPortName = portName -// for (magnet in magnets) { -// this.magnets.put(magnet, VirtualMagnetStatus(0.01)) -// } -// } + override val name: String = meta.getString("name", "virtual::numass.lambda") init { meta.useEachMeta("magnet") { val num = it.getInt("address", 1) val resistance = it.getDouble("resistance", 1.0) - magnets.put(num, VirtualMagnetStatus(resistance)) + magnets[num] = VirtualMagnetStatus(resistance) } } - override fun toString(): String = virtualPortName + override fun toString(): String = name override fun evaluateRequest(request: String) { val command: String @@ -67,8 +55,7 @@ class VirtualLambdaPort(meta: Meta) : VirtualPort(meta) { try { evaluateRequest(command.trim { it <= ' ' }, value.trim { it <= ' ' }) } catch (ex: RuntimeException) { - - receivePhrase("FAIL")//TODO какая команда правильная? + receive("FAIL".toByteArray())//TODO какая команда правильная? LoggerFactory.getLogger(javaClass).error("Request evaluation failure", ex) } @@ -125,14 +112,14 @@ class VirtualLambdaPort(meta: Meta) : VirtualPort(meta) { return } "PV?" -> { - planResponse(java.lang.Double.toString(currentMagnet().getVoltage()), latency) + planResponse(java.lang.Double.toString(currentMagnet().voltage), latency) return } "MV?" -> { - planResponse(java.lang.Double.toString(currentMagnet().getVoltage()), latency) + planResponse(java.lang.Double.toString(currentMagnet().voltage), latency) return } - else -> LoggerFactory.getLogger(javaClass).warn("Unknown comand {}", comand) + else -> LoggerFactory.getLogger(javaClass).warn("Unknown command {}", comand) } } @@ -143,28 +130,15 @@ class VirtualLambdaPort(meta: Meta) : VirtualPort(meta) { return magnets[currentAddress]!! } - @Throws(Exception::class) - override fun close() { - - } - - @Throws(PortException::class) - override fun open() { - - } - - override fun isOpen(): Boolean = true - private inner class VirtualMagnetStatus(val resistance: Double, var on: Boolean = true, var out: Boolean = false, var current: Double = 0.0) { - fun getVoltage() = current * resistance + val voltage get() = current * resistance } companion object { - private val latency = Duration.ofMillis(50) } } diff --git a/numass-control/magnet/src/main/kotlin/inr/numass/control/magnet/fx/MagnetApp.kt b/numass-control/magnet/src/main/kotlin/inr/numass/control/magnet/fx/MagnetApp.kt new file mode 100644 index 00000000..8c872aaf --- /dev/null +++ b/numass-control/magnet/src/main/kotlin/inr/numass/control/magnet/fx/MagnetApp.kt @@ -0,0 +1,32 @@ +package inr.numass.control.magnet.fx + +import hep.dataforge.context.Context +import hep.dataforge.control.devices.Device +import hep.dataforge.control.devices.DeviceFactory +import hep.dataforge.meta.Meta +import hep.dataforge.meta.MetaUtils +import inr.numass.control.NumassControlApplication +import inr.numass.control.magnet.LambdaHub +import javafx.stage.Stage + +class MagnetApp: NumassControlApplication() { + + override val deviceFactory: DeviceFactory = object :DeviceFactory{ + override fun getType(): String { + return "numass.lambda" + } + + override fun build(context: Context, meta: Meta): Device { + return LambdaHub(context, meta) + } + + } + + override fun setupStage(stage: Stage, device: LambdaHub) { + stage.title = "Numass magnet control" + } + + override fun getDeviceMeta(config: Meta): Meta { + return MetaUtils.findNode(config,"device"){it.getString("name") == "numass.magnets"}.orElseThrow{RuntimeException("Magnet configuration not found")} + } +} \ No newline at end of file diff --git a/numass-control/magnet/src/main/kotlin/inr/numass/control/magnet/fx/MagnetControllerApp.kt b/numass-control/magnet/src/main/kotlin/inr/numass/control/magnet/fx/MagnetControllerApp.kt index a6ca111a..70042c5f 100644 --- a/numass-control/magnet/src/main/kotlin/inr/numass/control/magnet/fx/MagnetControllerApp.kt +++ b/numass-control/magnet/src/main/kotlin/inr/numass/control/magnet/fx/MagnetControllerApp.kt @@ -15,127 +15,109 @@ */ 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.exceptions.ControlException -import hep.dataforge.io.MetaFileReader -import inr.numass.control.magnet.LambdaHub -import javafx.application.Application -import javafx.scene.Scene -import javafx.scene.layout.VBox -import javafx.stage.Stage -import org.slf4j.LoggerFactory -import java.io.IOException -import java.util.* +import tornadofx.* /** * * @author Alexander Nozik */ -class MagnetControllerApp : Application() { +class MagnetControllerApp : App() { -// internal var handler: Port -// internal var sourceController: SafeLambdaMagnet -// internal var pinchController: SafeLambdaMagnet -// internal var conusController: SafeLambdaMagnet -// internal var detectorController: SafeLambdaMagnet -// internal var controllers: MutableList = ArrayList() - - private lateinit var device: LambdaHub - - @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.getOrDefault("logLevel", "INFO") - - rootLogger.level = Level.valueOf(logLevel) - - val logFile = parameters.named["logFile"] - - if (logFile != null) { - val appender = FileAppender() - appender.file = logFile - appender.context = rootLogger.loggerContext - appender.start() - rootLogger.addAppender(appender) - } - - - - val config = MetaFileReader.instance().read(context,) - -// val portName = (parameters.named as java.util.Map).getOrDefault("port", "virtual") // -// if (portName == "virtual") { -// handler = VirtualLambdaPort("COM12", 1, 2, 3, 4) -// } else { -// handler = PortFactory.getPort(portName) -// //TODO add meta reader here +// private lateinit var device: LambdaHub +// +// @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.getOrDefault("logLevel", "INFO") +// +// rootLogger.level = Level.valueOf(logLevel) +// +// val logFile = parameters.named["logFile"] +// +// if (logFile != null) { +// val appender = FileAppender() +// appender.file = logFile +// appender.context = rootLogger.loggerContext +// appender.start() +// rootLogger.addAppender(appender) // } // -// sourceController = SafeLambdaMagnet("SOURCE", handler, 1) -// pinchController = SafeLambdaMagnet("PINCH", handler, 2) -// conusController = SafeLambdaMagnet("CONUS", handler, 3) -// detectorController = SafeLambdaMagnet("DETECTOR", handler, 4) // -// conusController.bindTo(pinchController, 30.0) +// val configFileName = parameters.named +// val config = MetaFileReader.instance().read(context,) // -// controllers.add(sourceController) -// sourceController.speed = 4.0 -// controllers.add(pinchController) -// controllers.add(conusController) -// controllers.add(detectorController) - - - val showConfirmation = java.lang.Boolean.parseBoolean((parameters.named as java.util.Map).getOrDefault("confirmOut", "false")) - - val vbox = VBox(5.0) - var height = 0.0 - var width = 0.0 - for (controller in controllers) { - val comp = MagnetControllerComponent.build(controller) - width = Math.max(width, comp.prefWidth) - height += comp.prefHeight + 5 - if (!showConfirmation) { - comp.setShowConfirmation(showConfirmation) - } - vbox.children.add(comp) - } - - val scene = Scene(vbox, width, height) - - - stage.title = "Numass magnet view" - stage.scene = scene - stage.isResizable = false - stage.show() - } - - @Throws(Exception::class) - override fun stop() { - super.stop() //To change body of generated methods, choose Tools | Templates. - for (magnet in controllers) { - magnet.stopMonitorTask() - magnet.stopUpdateTask() - } - if (handler.isOpen) { - handler.close() - } - System.exit(0) - } - - companion object { - - /** - * @param args the command line arguments - */ - @JvmStatic - fun main(args: Array) { - Application.launch(*args) - } - } +//// val portName = (parameters.named as java.util.Map).getOrDefault("port", "virtual") +//// +//// if (portName == "virtual") { +//// handler = VirtualLambdaPort("COM12", 1, 2, 3, 4) +//// } else { +//// handler = PortFactory.getPort(portName) +//// //TODO add meta reader here +//// } +//// +//// sourceController = SafeLambdaMagnet("SOURCE", handler, 1) +//// pinchController = SafeLambdaMagnet("PINCH", handler, 2) +//// conusController = SafeLambdaMagnet("CONUS", handler, 3) +//// detectorController = SafeLambdaMagnet("DETECTOR", handler, 4) +//// +//// conusController.bindTo(pinchController, 30.0) +//// +//// controllers.add(sourceController) +//// sourceController.speed = 4.0 +//// controllers.add(pinchController) +//// controllers.add(conusController) +//// controllers.add(detectorController) +// +// +// val showConfirmation = java.lang.Boolean.parseBoolean((parameters.named as java.util.Map).getOrDefault("confirmOut", "false")) +// +// val vbox = VBox(5.0) +// var height = 0.0 +// var width = 0.0 +// for (controller in controllers) { +// val comp = MagnetControllerComponent.build(controller) +// width = Math.max(width, comp.prefWidth) +// height += comp.prefHeight + 5 +// if (!showConfirmation) { +// comp.setShowConfirmation(showConfirmation) +// } +// vbox.children.add(comp) +// } +// +// val scene = Scene(vbox, width, height) +// +// +// stage.title = "Numass magnet view" +// stage.scene = scene +// stage.isResizable = false +// stage.show() +// } +// +// @Throws(Exception::class) +// override fun stop() { +// super.stop() //To change body of generated methods, choose Tools | Templates. +// for (magnet in controllers) { +// magnet.stopMonitorTask() +// magnet.stopUpdateTask() +// } +// if (handler.isOpen) { +// handler.close() +// } +// System.exit(0) +// } +// +// companion object { +// +// /** +// * @param args the command line arguments +// */ +// @JvmStatic +// fun main(args: Array) { +// Application.launch(*args) +// } +// } } diff --git a/numass-control/magnet/src/main/kotlin/inr/numass/control/magnet/fx/MagnetControllerComponent.kt b/numass-control/magnet/src/main/kotlin/inr/numass/control/magnet/fx/MagnetDisplay.kt similarity index 71% rename from numass-control/magnet/src/main/kotlin/inr/numass/control/magnet/fx/MagnetControllerComponent.kt rename to numass-control/magnet/src/main/kotlin/inr/numass/control/magnet/fx/MagnetDisplay.kt index 519e7c38..efa2c59e 100644 --- a/numass-control/magnet/src/main/kotlin/inr/numass/control/magnet/fx/MagnetControllerComponent.kt +++ b/numass-control/magnet/src/main/kotlin/inr/numass/control/magnet/fx/MagnetDisplay.kt @@ -20,8 +20,6 @@ import inr.numass.control.DeviceDisplayFX import inr.numass.control.magnet.LambdaMagnet import javafx.application.Platform import javafx.beans.value.ObservableValue -import javafx.event.ActionEvent -import javafx.fxml.FXML import javafx.fxml.Initializable import javafx.scene.control.* import javafx.scene.layout.AnchorPane @@ -40,9 +38,9 @@ class MagnetDisplay : DeviceDisplayFX() { return MagnetControllerComponent(device) } - val current by lazy { valueBinding(device.voltage)} + val current by lazy { valueBinding(device.voltage) } - val voltage by lazy { valueBinding(device.current)} + val voltage by lazy { valueBinding(device.current) } var target by device.target.doubleDelegate @@ -103,7 +101,7 @@ class MagnetDisplay : DeviceDisplayFX() { } } - valueBinding(device.output).onChange{ + valueBinding(device.output).onChange { Platform.runLater { if (it?.booleanValue() == true) { this.statusLabel.text = "OK" @@ -114,22 +112,43 @@ class MagnetDisplay : DeviceDisplayFX() { } } } + + valueBinding(device.updating).onChange { + val updateTaskRunning = it?.booleanValue() ?: false + runLater { + this.setButton.isSelected = updateTaskRunning + targetIField.isDisable = updateTaskRunning + } + } + + valueBinding(device.monitoring).onChange { + runLater { + monitorButton.isScaleShape = it?.booleanValue() ?: false + } + } + + setButton.selectedProperty().onChange { + try { + setOutput(it) + } catch (ex: PortException) { + displayError(this.device.name, null, ex) + } + } + + monitorButton.selectedProperty().onChange { + if (it) { + monitoring = true + } else { + monitoring = false + this.labelU.text = "----" + } + } } 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) - } - - } - @Throws(PortException::class) private fun setOutput(outputOn: Boolean) { if (outputOn) { @@ -178,17 +197,6 @@ class MagnetDisplay : DeviceDisplayFX() { } - @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" @@ -198,57 +206,9 @@ class MagnetDisplay : DeviceDisplayFX() { // 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) { + 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() -// } catch (ex: Exception) { -// LoggerFactory.getLogger("FX").error("Error during fxml initialization", ex) -// throw Error(ex) -// } -// -// component.setLambdaMagnet(lambdaMagnet) -// return component -// } - } } } diff --git a/numass-control/magnet/src/main/kotlin/inr/numass/control/magnet/fx/TestApp.kt b/numass-control/magnet/src/main/kotlin/inr/numass/control/magnet/fx/TestApp.kt deleted file mode 100644 index cd10bd5d..00000000 --- a/numass-control/magnet/src/main/kotlin/inr/numass/control/magnet/fx/TestApp.kt +++ /dev/null @@ -1,87 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -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 -import hep.dataforge.exceptions.PortException -import hep.dataforge.utils.DateTimeUtils -import org.slf4j.LoggerFactory -import java.io.BufferedReader -import java.io.InputStreamReader -import java.time.Duration -import java.util.* - -/** - * - * @author darksnake - */ -object TestApp { - - /** - * @param args the command line arguments - */ - @JvmStatic - fun main(args: Array) { - MagnetControllerApp.main(arrayOf("--port=192.168.111.31:4001")) - //MagnetControllerApp.main(new String[]{"--port=192.168.111.31:4001", "--logLevel=DEBUG"}); - } - -} - -/** - * @author Alexander Nozik - */ -object Talk { - - /** - * @param args the command line arguments - */ - @Throws(Exception::class) - @JvmStatic - fun main(args: Array) { - Locale.setDefault(Locale.US) - val rootLogger = LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME) as ch.qos.logback.classic.Logger - rootLogger.level = Level.INFO - - var portName = "/dev/ttyr00" - - if (args.size > 0) { - portName = args[0] - } - val handler: Port - handler = PortFactory.build(portName) - val controller = GenericPortController(Global,handler,"\r") - - // LambdaMagnet controller = new LambdaMagnet(handler, 1); - val reader = BufferedReader(InputStreamReader(System.`in`)) - - System.out.printf("INPUT > ") - var nextString = reader.readLine() - - while ("exit" != nextString) { - try { - val start = DateTimeUtils.now() - 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) { - ex.printStackTrace() - } - - System.out.printf("INPUT > ") - nextString = reader.readLine() - } - - handler.close() - - } - -} \ No newline at end of file diff --git a/numass-control/magnet/src/main/kotlin/inr/numass/control/magnet/test/CLITest.kt b/numass-control/magnet/src/main/kotlin/inr/numass/control/magnet/test/CLITest.kt new file mode 100644 index 00000000..e73e3305 --- /dev/null +++ b/numass-control/magnet/src/main/kotlin/inr/numass/control/magnet/test/CLITest.kt @@ -0,0 +1,63 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package inr.numass.control.magnet.test + +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 +import hep.dataforge.exceptions.PortException +import hep.dataforge.utils.DateTimeUtils +import org.slf4j.LoggerFactory +import java.io.BufferedReader +import java.io.InputStreamReader +import java.time.Duration +import java.util.* + + +/** + * @param args the command line arguments + */ + +fun main(args: Array) { + Locale.setDefault(Locale.US) + val rootLogger = LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME) as ch.qos.logback.classic.Logger + rootLogger.level = Level.INFO + + var portName = "/dev/ttyr00" + + if (args.isNotEmpty()) { + portName = args[0] + } + val handler: Port + handler = PortFactory.build(portName) + val controller = GenericPortController(Global, handler, "\r") + + // LambdaMagnet controller = new LambdaMagnet(handler, 1); + val reader = BufferedReader(InputStreamReader(System.`in`)) + + System.out.printf("INPUT > ") + var nextString = reader.readLine() + + while ("exit" != nextString) { + try { + val start = DateTimeUtils.now() + 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) { + ex.printStackTrace() + } + + System.out.printf("INPUT > ") + nextString = reader.readLine() + } + + handler.close() + +} diff --git a/numass-control/magnet/src/main/kotlin/inr/numass/control/magnet/SetCurrent.kt b/numass-control/magnet/src/main/kotlin/inr/numass/control/magnet/test/SetCurrent.kt similarity index 70% rename from numass-control/magnet/src/main/kotlin/inr/numass/control/magnet/SetCurrent.kt rename to numass-control/magnet/src/main/kotlin/inr/numass/control/magnet/test/SetCurrent.kt index 8c512d30..4b79cb9b 100644 --- a/numass-control/magnet/src/main/kotlin/inr/numass/control/magnet/SetCurrent.kt +++ b/numass-control/magnet/src/main/kotlin/inr/numass/control/magnet/test/SetCurrent.kt @@ -13,9 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package inr.numass.control.magnet +package inr.numass.control.magnet.test +import hep.dataforge.context.Global import hep.dataforge.control.ports.ComPort +import inr.numass.control.magnet.LambdaMagnet import jssc.SerialPortException /** @@ -34,14 +36,15 @@ object SetCurrent { throw IllegalArgumentException("Wrong number of parameters") } val comName = args[0] - val lambdaaddress = Integer.valueOf(args[1])!! - val current = java.lang.Double.valueOf(args[2]) + val lambdaaddress = args[1].toInt() + val current = args[2].toDouble() - val handler = ComPort(comName) + val port = ComPort.create(comName) - val controller = LambdaMagnet(handler, lambdaaddress) + val magnet = LambdaMagnet(Global, port, lambdaaddress) + magnet.target.set(current) + magnet.output.set(true) - controller.startUpdateTask(current, 500) } } diff --git a/numass-control/magnet/src/main/resources/debug.xml b/numass-control/magnet/src/main/resources/debug.xml index f9c5bbcf..a0e25c4c 100644 --- a/numass-control/magnet/src/main/resources/debug.xml +++ b/numass-control/magnet/src/main/resources/debug.xml @@ -1,7 +1,15 @@ - - - - - - \ No newline at end of file + + + + + + + + + + + + + + \ No newline at end of file diff --git a/numass-control/msp/src/main/kotlin/inr/numass/control/msp/MspApp.kt b/numass-control/msp/src/main/kotlin/inr/numass/control/msp/MspApp.kt index 982d6ef0..873e92b5 100644 --- a/numass-control/msp/src/main/kotlin/inr/numass/control/msp/MspApp.kt +++ b/numass-control/msp/src/main/kotlin/inr/numass/control/msp/MspApp.kt @@ -16,6 +16,7 @@ package inr.numass.control.msp import hep.dataforge.meta.Meta +import hep.dataforge.meta.MetaUtils import inr.numass.control.NumassControlApplication import javafx.stage.Stage @@ -33,9 +34,8 @@ class MspApp : NumassControlApplication() { stage.minWidth = 600.0 } - override fun acceptDevice(meta: Meta): Boolean { - return meta.getString("name") == "msp" + override fun getDeviceMeta(config: Meta): Meta { + return MetaUtils.findNode(config,"device"){it.getString("name") == "numass.msp"}.orElseThrow{RuntimeException("Mass-spectrometer configuration not found")} } - } diff --git a/numass-control/msp/src/main/kotlin/inr/numass/control/msp/MspDisplay.kt b/numass-control/msp/src/main/kotlin/inr/numass/control/msp/MspDisplay.kt index 740f50ec..b85554c7 100644 --- a/numass-control/msp/src/main/kotlin/inr/numass/control/msp/MspDisplay.kt +++ b/numass-control/msp/src/main/kotlin/inr/numass/control/msp/MspDisplay.kt @@ -132,12 +132,12 @@ class MspDisplay() : DeviceDisplayFX(), DeviceListener, NamedValueLis cellFormat { text = "Filament $it" } - disableProperty().bind(getBooleanBinding(PortSensor.CONNECTED_STATE).not()) + disableProperty().bind(booleanBinding(PortSensor.CONNECTED_STATE).not()) } switch { padding = Insets(5.0, 0.0, 0.0, 0.0) disableProperty() - .bind(getBooleanBinding(PortSensor.CONNECTED_STATE)) + .bind(booleanBinding(PortSensor.CONNECTED_STATE)) bindBooleanToState("filamentOn", selectedProperty()) } deviceStateIndicator(this@MspDisplay, "filamentStatus", false) { @@ -152,13 +152,13 @@ class MspDisplay() : DeviceDisplayFX(), DeviceListener, NamedValueLis togglebutton("Measure") { isSelected = false - disableProperty().bind(getBooleanBinding(PortSensor.CONNECTED_STATE).not()) + disableProperty().bind(booleanBinding(PortSensor.CONNECTED_STATE).not()) bindBooleanToState(Sensor.MEASURING_STATE, selectedProperty()) } togglebutton("Store") { isSelected = false - disableProperty().bind(getBooleanBinding(Sensor.MEASURING_STATE).not()) + disableProperty().bind(booleanBinding(Sensor.MEASURING_STATE).not()) bindBooleanToState("storing", selectedProperty()) } separator(Orientation.VERTICAL) diff --git a/numass-control/src/main/kotlin/inr/numass/control/DeviceDisplay.kt b/numass-control/src/main/kotlin/inr/numass/control/DeviceDisplay.kt deleted file mode 100644 index 1c5f7e64..00000000 --- a/numass-control/src/main/kotlin/inr/numass/control/DeviceDisplay.kt +++ /dev/null @@ -1,159 +0,0 @@ -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>) - -/** - * Get existing view connection or create a new one - */ -fun Device.getDisplay(): DeviceDisplay<*> { - val type = (this::class.annotations.find { it is DeviceView } as DeviceView?)?.value ?: DefaultDisplay::class - return optConnection(Roles.VIEW_ROLE, DeviceDisplay::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 DeviceDisplay : Component(), Connection, DeviceListener { - - private val bindings = HashMap>() - - private val deviceProperty = SimpleObjectProperty(this, "device", null) - val device: D by deviceProperty - - // private val viewProperty = SimpleObjectProperty(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) - } - } - - abstract fun buildView(device: D): UIComponent?; - - /** - * Create a binding for specific state and register it in update listener - */ - private fun bindState(state: State): ObjectBinding { - val binding = object : ObjectBinding() { - override fun computeValue(): T { - return state.value - } - } - bindings.putIfAbsent(state.name, binding) - return binding - } - - fun getValueBinding(stateName: String): ObjectBinding { - val state: ValueState = device.states.filterIsInstance(ValueState::class.java).find { it.name == stateName } - ?: throw NameNotFoundException("State with name $stateName not found") - return bindState(state) - } - - fun getBooleanBinding(stateName: String): BooleanBinding{ - return getValueBinding(stateName).booleanBinding{it?.booleanValue()?:false} - } - - /** - * Bind existing boolean property to writable device state - - * @param state - * @param property - */ - protected fun bindBooleanToState(state: String, property: BooleanProperty) { - getValueBinding(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@DeviceDisplay, Device.INITIALIZED_STATE) - deviceStateIndicator(this@DeviceDisplay, PortSensor.CONNECTED_STATE) - deviceStateIndicator(this@DeviceDisplay, Sensor.MEASURING_STATE) - deviceStateIndicator(this@DeviceDisplay, "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() : DeviceDisplay() { - override fun buildView(device: Device): UIComponent? = null -} - diff --git a/numass-control/src/main/kotlin/inr/numass/control/FXExtensions.kt b/numass-control/src/main/kotlin/inr/numass/control/FXExtensions.kt index 937c2246..58abbd15 100644 --- a/numass-control/src/main/kotlin/inr/numass/control/FXExtensions.kt +++ b/numass-control/src/main/kotlin/inr/numass/control/FXExtensions.kt @@ -76,9 +76,9 @@ fun EventTarget.indicator(radius: Double = 10.0, op: (Indicator.() -> Unit) = {} fun Indicator.bind(connection: DeviceDisplayFX<*>, state: String, transform: ((Value) -> Paint)? = null) { tooltip(state) if (transform != null) { - bind(connection.getValueBinding(state), transform); + bind(connection.valueBinding(state), transform); } else { - bind(connection.getValueBinding(state)) { + bind(connection.valueBinding(state)) { when { it.isNull -> Color.GRAY it.booleanValue() -> Color.GREEN @@ -117,7 +117,7 @@ fun Node.deviceStateToggle(connection: DeviceDisplayFX<*>, state: String, title: connection.device.states[state] = newValue } } - connection.getValueBinding(state).onChange { + connection.valueBinding(state).onChange { isSelected = it?.booleanValue() ?: false } } diff --git a/numass-control/src/main/kotlin/inr/numass/control/NumassControlApplication.kt b/numass-control/src/main/kotlin/inr/numass/control/NumassControlApplication.kt index eaf33bdd..c1dd50aa 100644 --- a/numass-control/src/main/kotlin/inr/numass/control/NumassControlApplication.kt +++ b/numass-control/src/main/kotlin/inr/numass/control/NumassControlApplication.kt @@ -17,23 +17,23 @@ import java.util.* * Created by darksnake on 14-May-17. */ abstract class NumassControlApplication : App() { - private var device: D by singleAssign() + private var device: D? = null override fun start(stage: Stage) { Locale.setDefault(Locale.US)// чтобы отделение десятичных знаков было точкой val rootLogger = LoggerFactory.getLogger(ch.qos.logback.classic.Logger.ROOT_LOGGER_NAME) as ch.qos.logback.classic.Logger rootLogger.level = Level.INFO - device = setupDevice() + device = setupDevice().also { + val controller = it.getDisplay() + it.connect(controller, Roles.VIEW_ROLE, Roles.DEVICE_LISTENER_ROLE) + val scene = Scene(controller.view?.root ?: controller.getBoardView()) + stage.scene = scene - val controller = device.getDisplay() - device.connect(controller, Roles.VIEW_ROLE, Roles.DEVICE_LISTENER_ROLE) - val scene = Scene(controller.view?.root ?: controller.getBoardView()) - stage.scene = scene - - stage.show() - setupStage(stage, device) - setDFStageIcon(stage) + stage.show() + setupStage(stage, it) + setDFStageIcon(stage) + } } /** @@ -45,14 +45,14 @@ abstract class NumassControlApplication : App() { protected abstract fun setupStage(stage: Stage, device: D) - protected abstract fun acceptDevice(meta: Meta): Boolean + + abstract fun getDeviceMeta(config: Meta): Meta private fun setupDevice(): D { val config = getConfig(this).optional.orElseGet { readResourceMeta("/config/devices.xml") } val ctx = setupContext(config) - val deviceConfig = findDeviceMeta(config) { this.acceptDevice(it) } - ?: throw RuntimeException("Device configuration not found") + val deviceConfig = getDeviceMeta(config) try { @@ -70,11 +70,10 @@ abstract class NumassControlApplication : App() { override fun stop() { try { - device.shutdown() + device?.shutdown() } catch (ex: Exception) { LoggerFactory.getLogger(javaClass).error("Failed to shutdown application", ex); } finally { - device.context.close() super.stop() } } diff --git a/numass-control/src/main/kotlin/inr/numass/control/NumassControlUtils.kt b/numass-control/src/main/kotlin/inr/numass/control/NumassControlUtils.kt index 193af017..9dcb3591 100644 --- a/numass-control/src/main/kotlin/inr/numass/control/NumassControlUtils.kt +++ b/numass-control/src/main/kotlin/inr/numass/control/NumassControlUtils.kt @@ -16,10 +16,8 @@ import inr.numass.client.ClientUtils import javafx.application.Application import javafx.stage.Stage import org.slf4j.LoggerFactory -import java.io.IOException import java.nio.file.Files import java.nio.file.Paths -import java.text.ParseException /** * Created by darksnake on 08-May-17. @@ -59,16 +57,15 @@ fun connectStorage(device: Device, config: Meta) { } fun readResourceMeta(path: String): Meta { - try { - return XMLMetaReader().read(Global::class.java.getResourceAsStream(path)) - } catch (e: IOException) { - throw RuntimeException(e) - } catch (e: ParseException) { - throw RuntimeException(e) + val resource = Global.io.optResource(path).nullable + if (resource != null) { + return XMLMetaReader().read(resource.stream) + } else { + throw RuntimeException("Resource $path not found") } - } + fun getConfig(app: Application): Meta? { val debugConfig = app.parameters.named["config.resource"] if (debugConfig != null) { diff --git a/numass-control/vac/src/main/kotlin/inr/numass/control/readvac/ReadVac.kt b/numass-control/vac/src/main/kotlin/inr/numass/control/readvac/ReadVac.kt index 86da489c..b9b46ad4 100644 --- a/numass-control/vac/src/main/kotlin/inr/numass/control/readvac/ReadVac.kt +++ b/numass-control/vac/src/main/kotlin/inr/numass/control/readvac/ReadVac.kt @@ -6,6 +6,7 @@ package inr.numass.control.readvac import hep.dataforge.meta.Meta +import hep.dataforge.meta.MetaUtils import inr.numass.control.NumassControlApplication import javafx.stage.Stage @@ -20,8 +21,8 @@ class ReadVac : NumassControlApplication() { stage.title = "Numass vacuum measurements" } - override fun acceptDevice(meta: Meta): Boolean { - return meta.getString("type", "") == "numass:vac" + override fun getDeviceMeta(config: Meta): Meta { + return MetaUtils.findNode(config,"device"){it.getString("name") == "numass.vac"}.orElseThrow{RuntimeException("Vacuum measurement configuration not found")} } }