Control update

This commit is contained in:
Alexander Nozik 2018-03-09 10:09:55 +03:00
parent 069c5422e0
commit 0fe0c1f1e1
7 changed files with 197 additions and 262 deletions

View File

@ -223,7 +223,7 @@ class PKT8Device(context: Context, meta: Meta) : PortSensor<PKT8Result>(context,
}
override fun startMeasurement(oldMeta: Meta, newMeta: Meta) {
fun setMeasurement(oldMeta: Meta, newMeta: Meta) {
if (!oldMeta.isEmpty) {
logger.warn("Trying to start measurement which is already started")
}
@ -317,7 +317,7 @@ class PKT8Device(context: Context, meta: Meta) : PortSensor<PKT8Result>(context,
// }
//
// @Throws(MeasurementException::class)
// override fun startMeasurement(): Measurement<PKT8Result> {
// override fun setMeasurement(): Measurement<PKT8Result> {
// //clearing PKT queue
// try {
// send("p")
@ -327,7 +327,7 @@ class PKT8Device(context: Context, meta: Meta) : PortSensor<PKT8Result>(context,
// // throw new MeasurementException(e);
// }
//
// return super.startMeasurement()
// return super.setMeasurement()
// }

View File

@ -1,6 +1,7 @@
package inr.numass.control
import hep.dataforge.control.devices.AbstractDevice
import hep.dataforge.kodex.nullable
import hep.dataforge.storage.api.TableLoader
import hep.dataforge.storage.commons.StorageConnection
import hep.dataforge.values.Values
@ -14,7 +15,7 @@ class StorageHelper(private val device: AbstractDevice, private val loaderFactor
private val loaderMap = HashMap<StorageConnection, TableLoader>()
fun push(point: Values) {
if (!device.hasState("storing") || device.getState("storing").booleanValue()) {
if (device.optBooleanState("storing").nullable == true) {
device.forEachConnection("storage", StorageConnection::class.java) { connection ->
try {
val pl = loaderMap.computeIfAbsent(connection, loaderFactory)

View File

@ -6,10 +6,7 @@
package inr.numass.control.readvac
import hep.dataforge.context.Context
import hep.dataforge.control.devices.Device
import hep.dataforge.control.devices.PortSensor
import hep.dataforge.control.measurements.Measurement
import hep.dataforge.control.measurements.SimpleMeasurement
import hep.dataforge.control.ports.ComPort
import hep.dataforge.control.ports.GenericPortController
import hep.dataforge.control.ports.Port
@ -31,51 +28,36 @@ class CM32Device(context: Context, meta: Meta) : PortSensor<Double>(context, met
} else {
PortFactory.build(meta)
}
return GenericPortController(context, port){it.endsWith("T--\r")}
return GenericPortController(context, port) { it.endsWith("T--\r") }
}
override fun startMeasurement(oldMeta: Meta, newMeta: Meta) {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
override fun setMeasurement(oldMeta: Meta?, newMeta: Meta) {
startMeasurement {
doMeasure()
}
}
override fun createMeasurement(): Measurement<Double> = CMVacMeasurement()
private fun doMeasure(): Meta{
val answer = sendAndWait("MES R PM 1\r\n")
return if (answer.isEmpty()) {
updateLogicalState(PortSensor.CONNECTED_STATE, false)
produceError("No signal")
} else if (!answer.contains("PM1:mbar")) {
updateLogicalState(PortSensor.CONNECTED_STATE, false)
produceError("Wrong answer: $answer")
} else if (answer.substring(14, 17) == "OFF") {
updateLogicalState(PortSensor.CONNECTED_STATE, true)
produceError("Off")
} else {
updateLogicalState(PortSensor.CONNECTED_STATE, true)
produceResult(answer.substring(14, 17) + answer.substring(19, 23))
}
}
override fun getType(): String {
return getMeta().getString("type", "Leibold CM32")
}
private inner class CMVacMeasurement : SimpleMeasurement<Double>() {
@Synchronized
@Throws(Exception::class)
override fun doMeasure(): Double? {
val answer = sendAndWait("MES R PM 1\r\n")
if (answer.isEmpty()) {
this.updateMessage("No signal")
updateLogicalState(PortSensor.CONNECTED_STATE, false)
return null
} else if (!answer.contains("PM1:mbar")) {
this.updateMessage("Wrong answer: " + answer)
updateLogicalState(PortSensor.CONNECTED_STATE, false)
return null
} else if (answer.substring(14, 17) == "OFF") {
this.updateMessage("Off")
updateLogicalState(PortSensor.CONNECTED_STATE, true)
return null
} else {
this.updateMessage("OK")
updateLogicalState(PortSensor.CONNECTED_STATE, true)
return java.lang.Double.parseDouble(answer.substring(14, 17) + answer.substring(19, 23))
}
}
override fun getDevice(): Device = this@CM32Device
return meta.getString("type", "numass.vac.cm32")
}
}

View File

@ -6,14 +6,15 @@
package inr.numass.control.readvac
import hep.dataforge.context.Context
import hep.dataforge.control.devices.Device
import hep.dataforge.control.devices.PortSensor
import hep.dataforge.control.measurements.Measurement
import hep.dataforge.control.measurements.SimpleMeasurement
import hep.dataforge.control.devices.intState
import hep.dataforge.control.ports.GenericPortController
import hep.dataforge.control.ports.Port
import hep.dataforge.control.ports.PortFactory
import hep.dataforge.description.ValueDef
import hep.dataforge.exceptions.ControlException
import hep.dataforge.meta.Meta
import hep.dataforge.states.StateDef
import hep.dataforge.values.ValueType
import inr.numass.control.DeviceView
/**
@ -21,52 +22,41 @@ import inr.numass.control.DeviceView
*/
@ValueDef(name = "channel")
@DeviceView(VacDisplay::class)
@StateDef(value = ValueDef(name = "channel", type = [ValueType.NUMBER], def = "2"), writable = true)
class MKSBaratronDevice(context: Context, meta: Meta) : PortSensor<Double>(context, meta) {
private val channel: Int = getMeta().getInt("channel", 2)
override fun createMeasurement(): Measurement<Double> = BaratronMeasurement()
var channel by intState("channel")
override fun getType(): String {
return getMeta().getString("type", "MKS baratron")
return meta.getString("type", "numass.vac.baratron")
}
@Throws(ControlException::class)
override fun buildPort(portName: String): Port {
val handler = super.buildPort(portName)
handler.setDelimiter("\r")
return handler
override fun connect(meta: Meta): GenericPortController {
val port: Port = PortFactory.build(meta)
logger.info("Connecting to port {}", port.name)
return GenericPortController(context, port) { it.endsWith("\r") }
}
private inner class BaratronMeasurement : SimpleMeasurement<Double>() {
override fun getDevice(): Device {
return this@MKSBaratronDevice
override fun setMeasurement(oldMeta: Meta?, newMeta: Meta) {
startMeasurement(newMeta) {
doMeasure()
}
}
@Synchronized
@Throws(Exception::class)
override fun doMeasure(): Double? {
val answer = sendAndWait("AV" + channel + "\r")
if (answer == null || answer.isEmpty()) {
// invalidateState("connection");
updateLogicalState(PortSensor.CONNECTED_STATE, false)
this.updateMessage("No connection")
return null
} else {
updateLogicalState(PortSensor.CONNECTED_STATE, true)
}
val res = java.lang.Double.parseDouble(answer)
if (res <= 0) {
this.updateMessage("Non positive")
// invalidateState("power");
return null
} else {
this.updateMessage("OK")
return res
}
private fun doMeasure(): Meta {
val answer = sendAndWait("AV$channel\r")
if (answer.isEmpty()) {
// invalidateState("connection");
updateLogicalState(PortSensor.CONNECTED_STATE, false)
return produceError("No connection")
} else {
updateLogicalState(PortSensor.CONNECTED_STATE, true)
}
val res = java.lang.Double.parseDouble(answer)
return if (res <= 0) {
produceError("Non positive")
} else {
produceResult(res)
}
}
}

View File

@ -6,11 +6,11 @@
package inr.numass.control.readvac
import hep.dataforge.context.Context
import hep.dataforge.control.devices.Device
import hep.dataforge.control.devices.PortSensor
import hep.dataforge.control.measurements.Measurement
import hep.dataforge.control.measurements.SimpleMeasurement
import hep.dataforge.control.devices.booleanState
import hep.dataforge.control.ports.GenericPortController
import hep.dataforge.control.ports.Port
import hep.dataforge.control.ports.PortFactory
import hep.dataforge.description.ValueDef
import hep.dataforge.description.ValueDefs
import hep.dataforge.exceptions.ControlException
@ -40,13 +40,7 @@ class MKSVacDevice(context: Context, meta: Meta) : PortSensor<Double>(context, m
private val deviceAddress: String = meta.getString("address", "253")
// val isPowerOnProperty = SimpleBooleanProperty()
// var isPowerOn by isPowerOnProperty
// val channelProperty = SimpleIntegerProperty(meta.getInt("channel", 5))
// var channel by channelProperty
var power: Boolean by booleanState("power")
@Throws(ControlException::class)
@ -61,15 +55,12 @@ class MKSVacDevice(context: Context, meta: Meta) : PortSensor<Double>(context, m
}
}
@Throws(ControlException::class)
override fun buildPort(portName: String): Port {
val handler = super.buildPort(portName)
handler.setDelimiter(";FF")
return handler
override fun connect(meta: Meta): GenericPortController {
val port: Port = PortFactory.build(meta)
logger.info("Connecting to port {}", port.name)
return GenericPortController(context, port) { it.endsWith(";FF") }
}
override fun createMeasurement(): Measurement<Double> = MKSVacMeasurement()
@Throws(ControlException::class)
override fun computeState(stateName: String): Any = when (stateName) {
"power" -> talk("FP?") == "ON"
@ -79,7 +70,7 @@ class MKSVacDevice(context: Context, meta: Meta) : PortSensor<Double>(context, m
@Throws(ControlException::class)
override fun requestStateChange(stateName: String, value: Value) {
when (stateName) {
"power" -> setPower(value.booleanValue())
"power" -> setPowerOn(value.booleanValue())
else -> super.requestStateChange(stateName, value)
}
@ -93,18 +84,8 @@ class MKSVacDevice(context: Context, meta: Meta) : PortSensor<Double>(context, m
super.shutdown()
}
// fun powerOnProperty(): BooleanProperty {
// try {
// return JavaBeanBooleanPropertyBuilder().bean(this)
// .name("powerOn").getter("isPowerOn").setter("setPower").build()
// } catch (ex: NoSuchMethodException) {
// throw Error(ex)
// }
//
// }
private fun setPower(powerOn: Boolean) {
if (powerOn != getLogicalState("power").booleanValue()) {
private fun setPowerOn(powerOn: Boolean) {
if (powerOn != power) {
if (powerOn) {
// String ans = talkMKS(p1Port, "@253ENC!OFF;FF");
// if (!ans.equals("OFF")) {
@ -112,47 +93,44 @@ class MKSVacDevice(context: Context, meta: Meta) : PortSensor<Double>(context, m
// }
val ans = talk("FP!ON")
if (ans == "ON") {
setLogicalState("power", true)
updateLogicalState("power", true)
} else {
this.notifyError("Failed to set power state", null)
this.notifyError("Failed to set power state")
}
} else {
val ans = talk("FP!OFF")
if (ans == "OFF") {
setLogicalState("power", false)
updateLogicalState("power", false)
} else {
this.notifyError("Failed to set power state", null)
this.notifyError("Failed to set power state")
}
}
}
}
override fun getType(): String = meta.getString("type", "MKS vacuumeter")
override fun getType(): String = meta.getString("type", "numass.vac.mks")
private inner class MKSVacMeasurement : SimpleMeasurement<Double>() {
@Synchronized
@Throws(Exception::class)
override fun doMeasure(): Double? {
// if (getState("power").booleanValue()) {
val channel = meta.getInt("channel", 5)
val answer = talk("PR$channel?")
if (answer == null || answer.isEmpty()) {
updateLogicalState(PortSensor.CONNECTED_STATE, false)
this.updateMessage("No connection")
return null
}
val res = parseDouble(answer)
return if (res <= 0) {
this.updateMessage("No power")
updateLogicalState("power", false)
null
} else {
this.updateMessage("OK")
res
}
override fun setMeasurement(oldMeta: Meta?, newMeta: Meta) {
startMeasurement(newMeta) {
doMeasure()
}
}
override fun getDevice(): Device = this@MKSVacDevice
private fun doMeasure(): Meta {
// if (getState("power").booleanValue()) {
val channel = meta.getInt("channel", 5)
val answer = talk("PR$channel?")
if (answer == null || answer.isEmpty()) {
updateLogicalState(PortSensor.CONNECTED_STATE, false)
return produceError("No connection")
}
val res = parseDouble(answer)
return if (res <= 0) {
updateLogicalState("power", false)
produceError("No power")
} else {
this.updateMessage("OK")
produceResult(res)
}
}
}

View File

@ -6,14 +6,14 @@
package inr.numass.control.readvac
import hep.dataforge.context.Context
import hep.dataforge.control.devices.Device
import hep.dataforge.control.devices.PortSensor
import hep.dataforge.control.measurements.Measurement
import hep.dataforge.control.measurements.SimpleMeasurement
import hep.dataforge.control.devices.intState
import hep.dataforge.control.ports.GenericPortController
import hep.dataforge.control.ports.Port
import hep.dataforge.control.ports.PortFactory
import hep.dataforge.description.ValueDef
import hep.dataforge.exceptions.ControlException
import hep.dataforge.meta.Meta
import hep.dataforge.states.StateDef
import hep.dataforge.values.ValueType.NUMBER
import java.math.BigDecimal
import java.math.BigInteger
@ -23,73 +23,63 @@ import java.util.regex.Pattern
/**
* @author Alexander Nozik
*/
@ValueDef(name = "address", type = arrayOf(NUMBER), def = "1", info = "A modbus address")
@StateDef(value = ValueDef(name = "address", type = [NUMBER], def = "1", info = "A modbus address"), writable = true)
class MeradatVacDevice(context: Context, meta: Meta) : PortSensor<Double>(context, meta) {
@Throws(ControlException::class)
override fun buildPort(portName: String): Port {
val newHandler = super.buildPort(portName)
newHandler.setDelimiter("\r\n")
return newHandler
}
var address by intState("address")
override fun createMeasurement(): Measurement<Double> = MeradatMeasurement()
override fun connect(meta: Meta): GenericPortController {
val port: Port = PortFactory.build(meta)
logger.info("Connecting to port {}", port.name)
return GenericPortController(context, port) { it.endsWith("\r\n") }
}
override fun getType(): String {
return getMeta().getString("type", "Vit vacuumeter")
return meta.getString("type", "numass.vac.vit")
}
override fun setMeasurement(oldMeta: Meta?, newMeta: Meta) {
startMeasurement(newMeta) {
doMeasure()
}
}
private inner class MeradatMeasurement : SimpleMeasurement<Double>() {
private fun doMeasure(): Meta {
val requestBase: String = String.format(":%02d", address)
val dataStr = requestBase.substring(1) + REQUEST
val query = requestBase + REQUEST + calculateLRC(dataStr) + "\r\n" // ":010300000002FA\r\n";
val response: Pattern = Pattern.compile(requestBase + "0304(\\w{4})(\\w{4})..\r\n")
private val query: String // ":010300000002FA\r\n";
private val response: Pattern
private val base: String
val answer = sendAndWait(query) { phrase -> phrase.startsWith(requestBase) }
init {
base = String.format(":%02d", getMeta().getInt("address", 1))
val dataStr = base.substring(1) + REQUEST
query = base + REQUEST + calculateLRC(dataStr) + "\r\n"
response = Pattern.compile(base + "0304(\\w{4})(\\w{4})..\r\n")
}
if (answer.isEmpty()) {
updateLogicalState(PortSensor.CONNECTED_STATE, false)
return produceError("No signal")
} else {
val match = response.matcher(answer)
@Synchronized
@Throws(Exception::class)
override fun doMeasure(): Double? {
val answer = sendAndWait(query) { phrase -> phrase.startsWith(base) }
if (answer.isEmpty()) {
this.updateMessage("No signal")
updateLogicalState(PortSensor.CONNECTED_STATE, false)
return null
} 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)
this.updateMessage("OK")
updateLogicalState(PortSensor.CONNECTED_STATE, true)
return res.toDouble()
} else {
this.updateMessage("Wrong answer: " + answer)
updateLogicalState(PortSensor.CONNECTED_STATE, false)
return null
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)
updateLogicalState(PortSensor.CONNECTED_STATE, true)
produceResult(res)
} else {
updateLogicalState(PortSensor.CONNECTED_STATE, false)
produceError("Wrong answer: $answer")
}
}
override fun getDevice(): Device = this@MeradatVacDevice
}
companion object {
private val REQUEST = "0300000002"
private const val REQUEST = "0300000002"
fun calculateLRC(inputString: String): String {
/*
@ -100,7 +90,7 @@ class MeradatVacDevice(context: Context, meta: Meta) : PortSensor<Double>(contex
var value = Integer.toHexString(-checksum)
value = value.substring(value.length - 2).toUpperCase()
if (value.length < 2) {
value = "0" + value
value = "0$value"
}
return value

View File

@ -12,9 +12,9 @@ import hep.dataforge.control.collectors.RegularPointCollector
import hep.dataforge.control.connections.Roles
import hep.dataforge.control.devices.Device
import hep.dataforge.control.devices.DeviceHub
import hep.dataforge.control.devices.DeviceListener
import hep.dataforge.control.devices.PortSensor.Companion.CONNECTED_STATE
import hep.dataforge.control.devices.Sensor
import hep.dataforge.control.measurements.AbstractMeasurement
import hep.dataforge.control.measurements.Measurement
import hep.dataforge.description.ValueDef
import hep.dataforge.exceptions.ControlException
import hep.dataforge.meta.Meta
@ -31,13 +31,10 @@ import hep.dataforge.values.ValueType
import hep.dataforge.values.Values
import inr.numass.control.DeviceView
import inr.numass.control.StorageHelper
import kotlinx.coroutines.experimental.launch
import kotlinx.coroutines.experimental.time.delay
import java.time.Duration
import java.time.Instant
import java.util.*
import java.util.concurrent.Executors
import java.util.concurrent.ScheduledExecutorService
import java.util.concurrent.ScheduledFuture
import java.util.concurrent.TimeUnit
import java.util.stream.Stream
/**
@ -50,8 +47,22 @@ class VacCollectorDevice(context: Context, meta: Meta, val sensors: Collection<S
private val helper = StorageHelper(this, this::buildLoader)
private val averagingDuration: Duration
get() = Duration.parse(getMeta().getString("averagingDuration", "PT30S"))
private val collector = object : DeviceListener {
val averagingDuration: Duration = Duration.parse(meta.getString("averagingDuration", "PT30S"))
private val collector = RegularPointCollector(averagingDuration) {
notifyResult(it)
}
override fun notifyDeviceStateChanged(device: Device, name: String, state: Value) {
}
override fun notifyDeviceStateChanged(device: Device, name: String, state: Meta) {
if (name == MEASUREMENT_RESULT_STATE) {
collector.put(device.name, state.getValue("value"))
}
}
}
override fun optDevice(name: Name): Optional<Device> =
@ -66,8 +77,6 @@ class VacCollectorDevice(context: Context, meta: Meta, val sensors: Collection<S
s.init()
}
}
//TODO use meta
override fun createMeasurement(): Measurement<Values> = VacuumMeasurement()
override fun getType(): String = "numass.vac.collector"
@ -87,7 +96,7 @@ class VacCollectorDevice(context: Context, meta: Meta, val sensors: Collection<S
val suffix = DateTimeUtils.fileSuffix()
return LoaderFactory.buildPointLoader(connection.storage, "vactms_" + suffix, "", "timestamp", format.build())
return LoaderFactory.buildPointLoader(connection.storage, "vactms_$suffix", "", "timestamp", format.build())
}
override fun connectAll(connection: Connection, vararg roles: String) {
@ -100,61 +109,46 @@ class VacCollectorDevice(context: Context, meta: Meta, val sensors: Collection<S
this.sensors.forEach { it.connectionHelper.connect(context, meta) }
}
private inner class VacuumMeasurement : AbstractMeasurement<Values>() {
private val collector = RegularPointCollector(averagingDuration) { this.result(it) }
private var executor: ScheduledExecutorService? = null
private var currentTask: ScheduledFuture<*>? = null
private fun notifyResult(values: Values) {
notifyResult(produceResult(values.toMeta()))
helper.push(values)
}
override fun getDevice(): Device {
return this@VacCollectorDevice
}
override fun start() {
executor = Executors.newSingleThreadScheduledExecutor { r: Runnable -> Thread(r, "VacuumMeasurement thread") }
val delay = getMeta().getInt("delay", 5)!! * 1000
currentTask = executor!!.scheduleWithFixedDelay({
sensors.forEach { sensor ->
try {
val value: Any?
value = if (sensor.optBooleanState(CONNECTED_STATE).orElse(false)) {
sensor.read()
} else {
null
}
collector.put(sensor.name, value)
} catch (ex: Exception) {
collector.put(sensor.name, Value.NULL)
}
}
}, 0, delay.toLong(), TimeUnit.MILLISECONDS)
}
@Synchronized override fun result(result: Values, time: Instant) {
super.result(result, time)
helper.push(result)
}
private fun terminator(): Values {
val p = ValueMap.Builder()
p.putValue("timestamp", DateTimeUtils.now())
getDeviceNames().forEach { n -> p.putValue(n.toUnescaped(), null) }
return p.build()
}
override fun stop(force: Boolean): Boolean {
val isRunning = currentTask != null
if (isRunning) {
logger.debug("Stopping vacuum collector measurement. Writing terminator point")
result(terminator())
currentTask!!.cancel(force)
executor!!.shutdown()
currentTask = null
afterStop()
override fun onStateChange(stateName: String, oldState: Value?, newState: Value) {
if (stateName == MEASURING_STATE) {
if (!newState.booleanValue()) {
notifyResult(terminator())
}
return isRunning
}
}
override fun setMeasurement(oldMeta: Meta?, newMeta: Meta) {
oldMeta?.let {
stopMeasurement()
}
val interval = Duration.ofSeconds(meta.getInt("delay", 5).toLong())
job = launch {
while (true) {
notifyMeasurementState(MeasurementState.IN_PROGRESS)
sensors.forEach { sensor ->
if (sensor.optBooleanState(CONNECTED_STATE).orElse(false)) {
sensor.measure()
}
}
notifyMeasurementState(MeasurementState.WAITING)
delay(interval)
}
}
}
private fun terminator(): Values {
val p = ValueMap.Builder()
deviceNames.forEach { n -> p.putValue(n.toUnescaped(), null) }
return p.build()
}
}