Yet another devices revision
This commit is contained in:
parent
885b87f87f
commit
b9a822ed14
@ -26,6 +26,7 @@ import hep.dataforge.control.devices.Sensor
|
|||||||
import hep.dataforge.control.devices.StateDef
|
import hep.dataforge.control.devices.StateDef
|
||||||
import hep.dataforge.control.measurements.AbstractMeasurement
|
import hep.dataforge.control.measurements.AbstractMeasurement
|
||||||
import hep.dataforge.control.measurements.Measurement
|
import hep.dataforge.control.measurements.Measurement
|
||||||
|
import hep.dataforge.control.ports.GenericPortController
|
||||||
import hep.dataforge.control.ports.Port
|
import hep.dataforge.control.ports.Port
|
||||||
import hep.dataforge.description.ValueDef
|
import hep.dataforge.description.ValueDef
|
||||||
import hep.dataforge.exceptions.ControlException
|
import hep.dataforge.exceptions.ControlException
|
||||||
@ -43,6 +44,7 @@ import inr.numass.control.DeviceView
|
|||||||
import inr.numass.control.StorageHelper
|
import inr.numass.control.StorageHelper
|
||||||
import java.time.Duration
|
import java.time.Duration
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import java.util.function.BiConsumer
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -62,7 +64,6 @@ class PKT8Device(context: Context, meta: Meta) : PortSensor<PKT8Result>(context,
|
|||||||
* The key is the letter (a,b,c,d...) as in measurements
|
* The key is the letter (a,b,c,d...) as in measurements
|
||||||
*/
|
*/
|
||||||
val channels = LinkedHashMap<String, PKT8Channel>()
|
val channels = LinkedHashMap<String, PKT8Channel>()
|
||||||
private var collector: RegularPointCollector? = null
|
|
||||||
private var storageHelper: StorageHelper? = null
|
private var storageHelper: StorageHelper? = null
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -71,8 +72,8 @@ class PKT8Device(context: Context, meta: Meta) : PortSensor<PKT8Result>(context,
|
|||||||
//private var format: TableFormat? = null
|
//private var format: TableFormat? = null
|
||||||
|
|
||||||
|
|
||||||
private// Building data format
|
// Building data format
|
||||||
val tableFormat: TableFormat by lazy {
|
private val tableFormat: TableFormat by lazy {
|
||||||
val tableFormatBuilder = TableFormatBuilder()
|
val tableFormatBuilder = TableFormatBuilder()
|
||||||
.addTime("timestamp")
|
.addTime("timestamp")
|
||||||
|
|
||||||
@ -91,13 +92,14 @@ class PKT8Device(context: Context, meta: Meta) : PortSensor<PKT8Result>(context,
|
|||||||
val abuf: String
|
val abuf: String
|
||||||
get() = getState(ABUF).stringValue()
|
get() = getState(ABUF).stringValue()
|
||||||
|
|
||||||
|
private val duration = Duration.parse(meta().getString("averagingDuration", "PT30S"))
|
||||||
|
|
||||||
private fun buildLoader(connection: StorageConnection): TableLoader {
|
private fun buildLoader(connection: StorageConnection): TableLoader {
|
||||||
val storage = connection.storage
|
val storage = connection.storage
|
||||||
val suffix = DateTimeUtils.fileSuffix()
|
val suffix = DateTimeUtils.fileSuffix()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return LoaderFactory.buildPointLoder(storage,
|
return LoaderFactory.buildPointLoder(storage, "cryotemp_" + suffix, "", "timestamp", tableFormat)
|
||||||
"cryotemp_" + suffix, "", "timestamp", tableFormat)
|
|
||||||
} catch (e: StorageException) {
|
} catch (e: StorageException) {
|
||||||
throw RuntimeException("Failed to builder loader from storage", e)
|
throw RuntimeException("Failed to builder loader from storage", e)
|
||||||
}
|
}
|
||||||
@ -124,44 +126,39 @@ class PKT8Device(context: Context, meta: Meta) : PortSensor<PKT8Result>(context,
|
|||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
//update parameters from meta
|
//update parameters from meta
|
||||||
if (meta().hasValue("pga")) {
|
meta.optValue("pga").ifPresent {
|
||||||
logger.info("Setting dynamic range to " + meta().getInt("pga")!!)
|
logger.info("Setting dynamic range to " + it.intValue())
|
||||||
val response = sendAndWait("g" + meta().getInt("pga")!!, TIMEOUT).trim { it <= ' ' }
|
val response = sendAndWait("g" + it.intValue()).trim { it <= ' ' }
|
||||||
if (response.contains("=")) {
|
if (response.contains("=")) {
|
||||||
updateState(PGA, Integer.parseInt(response.substring(4)))
|
updateState(PGA, Integer.parseInt(response.substring(4)))
|
||||||
} else {
|
} else {
|
||||||
logger.error("Setting pga failsed with message: " + response)
|
logger.error("Setting pga failed with message: " + response)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setSPS(meta().getInt("sps", 0)!!)
|
|
||||||
setBUF(meta().getInt("abuf", 100)!!)
|
setSPS(meta().getInt("sps", 0))
|
||||||
|
setBUF(meta().getInt("abuf", 100))
|
||||||
|
|
||||||
// setting up the collector
|
// setting up the collector
|
||||||
storageHelper = StorageHelper(this) { connection: StorageConnection -> this.buildLoader(connection) }
|
storageHelper = StorageHelper(this) { connection: StorageConnection -> this.buildLoader(connection) }
|
||||||
val duration = Duration.parse(meta().getString("averagingDuration", "PT30S"))
|
|
||||||
collector = RegularPointCollector(duration, this.channels.values.map { it.name }) { dp: Values ->
|
|
||||||
logger.debug("Point measurement complete. Pushing...")
|
|
||||||
storageHelper?.push(dp)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(ControlException::class)
|
@Throws(ControlException::class)
|
||||||
override fun shutdown() {
|
override fun shutdown() {
|
||||||
|
measurement?.stop(true)
|
||||||
storageHelper?.close()
|
storageHelper?.close()
|
||||||
collector?.stop()
|
|
||||||
collector = null
|
|
||||||
super.shutdown()
|
super.shutdown()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(ControlException::class)
|
@Throws(ControlException::class)
|
||||||
override fun buildHandler(portName: String): Port {
|
override fun buildPort(portName: String): Port {
|
||||||
//setup connection
|
//setup connection
|
||||||
val handler: Port = if ("virtual" == portName) {
|
val handler: Port = if ("virtual" == portName) {
|
||||||
logger.info("Starting {} using virtual debug port", name)
|
logger.info("Starting {} using virtual debug port", name)
|
||||||
PKT8VirtualPort("PKT8", meta().getMetaOrEmpty("debug"))
|
PKT8VirtualPort("PKT8", meta().getMetaOrEmpty("debug"))
|
||||||
} else {
|
} else {
|
||||||
super.buildHandler(portName)
|
super.buildPort(portName)
|
||||||
}
|
}
|
||||||
handler.setDelimiter("\n")
|
handler.setDelimiter("\n")
|
||||||
|
|
||||||
@ -172,7 +169,7 @@ class PKT8Device(context: Context, meta: Meta) : PortSensor<PKT8Result>(context,
|
|||||||
logger.info("Setting avaraging buffer size to " + buf)
|
logger.info("Setting avaraging buffer size to " + buf)
|
||||||
var response: String
|
var response: String
|
||||||
try {
|
try {
|
||||||
response = sendAndWait("b" + buf, Duration.ofMillis(400)).trim { it <= ' ' }
|
response = sendAndWait("b" + buf).trim { it <= ' ' }
|
||||||
} catch (ex: Exception) {
|
} catch (ex: Exception) {
|
||||||
response = ex.message ?: ""
|
response = ex.message ?: ""
|
||||||
}
|
}
|
||||||
@ -239,7 +236,7 @@ class PKT8Device(context: Context, meta: Meta) : PortSensor<PKT8Result>(context,
|
|||||||
private fun setSPS(sps: Int) {
|
private fun setSPS(sps: Int) {
|
||||||
logger.info("Setting sampling rate to " + spsToStr(sps))
|
logger.info("Setting sampling rate to " + spsToStr(sps))
|
||||||
val response: String = try {
|
val response: String = try {
|
||||||
sendAndWait("v" + sps, TIMEOUT).trim { it <= ' ' }
|
sendAndWait("v" + sps).trim { it <= ' ' }
|
||||||
} catch (ex: Exception) {
|
} catch (ex: Exception) {
|
||||||
ex.message ?: ""
|
ex.message ?: ""
|
||||||
}
|
}
|
||||||
@ -257,11 +254,7 @@ class PKT8Device(context: Context, meta: Meta) : PortSensor<PKT8Result>(context,
|
|||||||
this.measurement
|
this.measurement
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
if (port.isLocked) {
|
PKT8Measurement(connection)
|
||||||
logger.error("Breaking hold on handler because it is locked")
|
|
||||||
port.breakHold()
|
|
||||||
}
|
|
||||||
PKT8Measurement(port)
|
|
||||||
} catch (e: ControlException) {
|
} catch (e: ControlException) {
|
||||||
throw MeasurementException(e)
|
throw MeasurementException(e)
|
||||||
}
|
}
|
||||||
@ -274,7 +267,7 @@ class PKT8Device(context: Context, meta: Meta) : PortSensor<PKT8Result>(context,
|
|||||||
//clearing PKT queue
|
//clearing PKT queue
|
||||||
try {
|
try {
|
||||||
send("p")
|
send("p")
|
||||||
sendAndWait("p", TIMEOUT)
|
sendAndWait("p")
|
||||||
} catch (e: ControlException) {
|
} catch (e: ControlException) {
|
||||||
logger.error("Failed to clear PKT8 port")
|
logger.error("Failed to clear PKT8 port")
|
||||||
// throw new MeasurementException(e);
|
// throw new MeasurementException(e);
|
||||||
@ -284,10 +277,19 @@ class PKT8Device(context: Context, meta: Meta) : PortSensor<PKT8Result>(context,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inner class PKT8Measurement(private val handler: Port) : AbstractMeasurement<PKT8Result>(), Port.PortController {
|
inner class PKT8Measurement(private val controller: GenericPortController) : AbstractMeasurement<PKT8Result>() {
|
||||||
|
|
||||||
override fun getDevice(): Device = this@PKT8Device
|
override fun getDevice(): Device = this@PKT8Device
|
||||||
|
|
||||||
|
private var collector: RegularPointCollector = RegularPointCollector(duration, channels.values.map { it.name }) { dp: Values ->
|
||||||
|
logger.debug("Point measurement complete. Pushing...")
|
||||||
|
storageHelper?.push(dp)
|
||||||
|
}
|
||||||
|
|
||||||
|
var errorListener: BiConsumer<String, Throwable>? = null
|
||||||
|
var stopListener: GenericPortController.PhraseListener? = null;
|
||||||
|
var valueListener: GenericPortController.PhraseListener? = null;
|
||||||
|
|
||||||
override fun start() {
|
override fun start() {
|
||||||
if (isStarted) {
|
if (isStarted) {
|
||||||
logger.warn("Trying to start measurement which is already started")
|
logger.warn("Trying to start measurement which is already started")
|
||||||
@ -295,11 +297,37 @@ class PKT8Device(context: Context, meta: Meta) : PortSensor<PKT8Result>(context,
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
logger.info("Starting measurement")
|
logger.info("Starting measurement")
|
||||||
handler.holdBy(this)
|
//add weak error listener
|
||||||
handler.send(this, "s")
|
errorListener = controller.onError(this::onError)
|
||||||
|
|
||||||
|
//add weak stop listener
|
||||||
|
stopListener = controller.onPhrase("[Ss]topped\\s*") {
|
||||||
|
afterPause()
|
||||||
|
updateState(Sensor.MEASURING_STATE, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
//add weak measurement listener
|
||||||
|
valueListener = controller.onPhrase("[a-f].*") {
|
||||||
|
val trimmed = it.trim()
|
||||||
|
val designation = trimmed.substring(0, 1)
|
||||||
|
val rawValue = java.lang.Double.parseDouble(trimmed.substring(1)) / 100
|
||||||
|
|
||||||
|
val channel = this@PKT8Device.channels[designation]
|
||||||
|
|
||||||
|
if (channel != null) {
|
||||||
|
result(channel.evaluate(rawValue))
|
||||||
|
collector.put(channel.name, channel.getTemperature(rawValue))
|
||||||
|
} else {
|
||||||
|
result(PKT8Result(designation, rawValue, -1.0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//send start signal
|
||||||
|
controller.send("s")
|
||||||
|
|
||||||
afterStart()
|
afterStart()
|
||||||
} catch (ex: ControlException) {
|
} catch (ex: ControlException) {
|
||||||
portError("Failed to start measurement", ex)
|
onError("Failed to start measurement", ex)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -308,56 +336,31 @@ class PKT8Device(context: Context, meta: Meta) : PortSensor<PKT8Result>(context,
|
|||||||
override fun stop(force: Boolean): Boolean {
|
override fun stop(force: Boolean): Boolean {
|
||||||
if (isFinished) {
|
if (isFinished) {
|
||||||
logger.warn("Trying to stop measurement which is already stopped")
|
logger.warn("Trying to stop measurement which is already stopped")
|
||||||
}
|
return true
|
||||||
|
} else {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
logger.info("Stopping measurement")
|
logger.info("Stopping measurement")
|
||||||
val response = sendAndWait("p", TIMEOUT).trim { it <= ' ' }
|
val response = sendAndWait("p").trim()
|
||||||
// Должно быть именно с большой буквы!!!
|
// Должно быть именно с большой буквы!!!
|
||||||
return "Stopped" == response || "stopped" == response
|
return "Stopped" == response || "stopped" == response
|
||||||
} catch (ex: Exception) {
|
} catch (ex: Exception) {
|
||||||
error(ex)
|
onError("Failed to stop measurement", ex)
|
||||||
return false
|
return false
|
||||||
} finally {
|
} finally {
|
||||||
collector?.clear()
|
afterStop()
|
||||||
logger.debug("Removing port lock")
|
errorListener?.let { controller.removeErrorListener(it) }
|
||||||
handler.releaseBy(this)
|
stopListener?.let { controller.removePhraseListener(it) }
|
||||||
}
|
valueListener?.let { controller.removePhraseListener(it) }
|
||||||
}
|
collector.stop()
|
||||||
|
logger.debug("Collector stopped")
|
||||||
|
|
||||||
override fun acceptPhrase(message: String) {
|
|
||||||
val trimmed = message.trim { it <= ' ' }
|
|
||||||
|
|
||||||
if (isStarted) {
|
|
||||||
if (trimmed == "Stopped" || trimmed == "stopped") {
|
|
||||||
afterPause()
|
|
||||||
updateState(Sensor.MEASURING_STATE, false)
|
|
||||||
// getLogger().info("Measurement stopped");
|
|
||||||
} else {
|
|
||||||
val designation = trimmed.substring(0, 1)
|
|
||||||
val rawValue = java.lang.Double.parseDouble(trimmed.substring(1)) / 100
|
|
||||||
|
|
||||||
val channel = this@PKT8Device.channels[designation]
|
|
||||||
|
|
||||||
if (channel != null) {
|
|
||||||
result(channel.evaluate(rawValue))
|
|
||||||
collector?.put(channel.name, channel.getTemperature(rawValue))
|
|
||||||
} else {
|
|
||||||
result(PKT8Result(designation, rawValue, -1.0))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun portError(errorMessage: String, error: Throwable) {
|
|
||||||
super.error(error)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val PKT8_DEVICE_TYPE = "numass.pkt8"
|
val PKT8_DEVICE_TYPE = "numass.pkt8"
|
||||||
private val TIMEOUT = Duration.ofMillis(400)
|
|
||||||
|
|
||||||
val PGA = "pga"
|
val PGA = "pga"
|
||||||
val SPS = "sps"
|
val SPS = "sps"
|
||||||
|
@ -18,12 +18,12 @@ import java.util.function.Supplier
|
|||||||
/**
|
/**
|
||||||
* @author Alexander Nozik
|
* @author Alexander Nozik
|
||||||
*/
|
*/
|
||||||
class PKT8VirtualPort(portName: String, meta: Meta) : VirtualPort(), Metoid {
|
class PKT8VirtualPort(portName: String, meta: Meta) : VirtualPort(meta), Metoid {
|
||||||
|
|
||||||
private val generator = Random()
|
private val generator = Random()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
super.configure(meta).configureValue("id", portName)
|
super.configureValue("id", portName)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized override fun evaluateRequest(request: String) {
|
@Synchronized override fun evaluateRequest(request: String) {
|
||||||
|
@ -51,7 +51,7 @@ public class VirtualLambdaPort extends VirtualPort {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getPortId() {
|
public String toString() {
|
||||||
return virtualPortName;
|
return virtualPortName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,13 +21,13 @@ import hep.dataforge.control.RoleDef
|
|||||||
import hep.dataforge.control.RoleDefs
|
import hep.dataforge.control.RoleDefs
|
||||||
import hep.dataforge.control.collectors.RegularPointCollector
|
import hep.dataforge.control.collectors.RegularPointCollector
|
||||||
import hep.dataforge.control.connections.Roles
|
import hep.dataforge.control.connections.Roles
|
||||||
import hep.dataforge.control.devices.*
|
import hep.dataforge.control.devices.Device
|
||||||
|
import hep.dataforge.control.devices.PortSensor
|
||||||
|
import hep.dataforge.control.devices.StateDef
|
||||||
|
import hep.dataforge.control.devices.StateDefs
|
||||||
import hep.dataforge.control.measurements.AbstractMeasurement
|
import hep.dataforge.control.measurements.AbstractMeasurement
|
||||||
import hep.dataforge.control.ports.GenericPortController
|
|
||||||
import hep.dataforge.control.ports.Port
|
import hep.dataforge.control.ports.Port
|
||||||
import hep.dataforge.control.ports.TcpPort
|
|
||||||
import hep.dataforge.description.ValueDef
|
import hep.dataforge.description.ValueDef
|
||||||
import hep.dataforge.events.EventBuilder
|
|
||||||
import hep.dataforge.exceptions.ControlException
|
import hep.dataforge.exceptions.ControlException
|
||||||
import hep.dataforge.exceptions.MeasurementException
|
import hep.dataforge.exceptions.MeasurementException
|
||||||
import hep.dataforge.exceptions.PortException
|
import hep.dataforge.exceptions.PortException
|
||||||
@ -61,15 +61,10 @@ import java.util.function.Consumer
|
|||||||
StateDef(ValueDef(name = "filamentStatus", info = "Filament status"))
|
StateDef(ValueDef(name = "filamentStatus", info = "Filament status"))
|
||||||
)
|
)
|
||||||
@DeviceView(MspDisplay::class)
|
@DeviceView(MspDisplay::class)
|
||||||
class MspDevice(context: Context, meta: Meta) : Sensor<Values>(context, meta), Port.PortController {
|
class MspDevice(context: Context, meta: Meta) : PortSensor<Values>(context, meta) {
|
||||||
|
|
||||||
private var handler: TcpPort? = null
|
|
||||||
private val controller = GenericPortController(this)
|
|
||||||
private var measurementDelegate: Consumer<MspResponse>? = null
|
private var measurementDelegate: Consumer<MspResponse>? = null
|
||||||
|
|
||||||
val isConnected: Boolean
|
|
||||||
get() = getState(PortSensor.CONNECTED_STATE).booleanValue()
|
|
||||||
|
|
||||||
val isSelected: Boolean
|
val isSelected: Boolean
|
||||||
get() = getState("selected").booleanValue()
|
get() = getState("selected").booleanValue()
|
||||||
|
|
||||||
@ -79,22 +74,60 @@ class MspDevice(context: Context, meta: Meta) : Sensor<Values>(context, meta), P
|
|||||||
val isFilamentOn: Boolean
|
val isFilamentOn: Boolean
|
||||||
get() = getState("filamentOn").booleanValue()
|
get() = getState("filamentOn").booleanValue()
|
||||||
|
|
||||||
private val averagingDuration: Duration
|
private val averagingDuration: Duration = Duration.parse(meta().getString("averagingDuration", "PT30S"))
|
||||||
get() = Duration.parse(meta().getString("averagingDuration", "PT30S"))
|
|
||||||
|
|
||||||
// public MspDevice(String name, Context context, Meta config) {
|
|
||||||
// super(name, context, config);
|
|
||||||
// }
|
|
||||||
@Throws(ControlException::class)
|
@Throws(ControlException::class)
|
||||||
override fun init() {
|
override fun init() {
|
||||||
super.init()
|
super.init()
|
||||||
val ip = meta().getString("connection.ip", "127.0.0.1")
|
connection.weakOnError(this::notifyError)
|
||||||
val port = meta().getInt("connection.port", 10014)!!
|
onResponse("FilamentStatus"){
|
||||||
logger.info("Connection to MKS mass-spectrometer on {}:{}...", ip, port)
|
val status = it[0, 2]
|
||||||
handler = TcpPort(ip, port)
|
updateState("filamentOn", status == "ON")
|
||||||
handler!!.setDelimiter("\r\r")
|
updateState("filamentStatus", status)
|
||||||
|
}
|
||||||
|
logger.info("Connected to MKS mass-spectrometer on {}", connection.port);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add reaction on specific response
|
||||||
|
*/
|
||||||
|
private fun onResponse(command: String, action: (MspResponse) -> Unit) {
|
||||||
|
connection.weakOnPhrase({it.startsWith(command)}){
|
||||||
|
action(MspResponse(it))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
override fun acceptPhrase(message: String) {
|
||||||
|
dispatchEvent(
|
||||||
|
EventBuilder
|
||||||
|
.make("msp")
|
||||||
|
.setMetaValue("response", message.trim { it <= ' ' }).build()
|
||||||
|
)
|
||||||
|
val response = MspResponse(message)
|
||||||
|
|
||||||
|
when (response.commandName) {
|
||||||
|
// all possible async messages
|
||||||
|
"FilamentStatus" -> {
|
||||||
|
val status = response[0, 2]
|
||||||
|
updateState("filamentOn", status == "ON")
|
||||||
|
updateState("filamentStatus", status)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (measurementDelegate != null) {
|
||||||
|
measurementDelegate!!.accept(response)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun portError(errorMessage: String?, error: Throwable?) {
|
||||||
|
notifyError(errorMessage, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
override fun buildPort(portName: String?): Port = super.buildPort(portName).apply { setDelimiter("\r\r") }
|
||||||
|
|
||||||
@Throws(ControlException::class)
|
@Throws(ControlException::class)
|
||||||
override fun shutdown() {
|
override fun shutdown() {
|
||||||
super.stopMeasurement(true)
|
super.stopMeasurement(true)
|
||||||
@ -102,15 +135,9 @@ class MspDevice(context: Context, meta: Meta) : Sensor<Values>(context, meta), P
|
|||||||
setFilamentOn(false)
|
setFilamentOn(false)
|
||||||
setConnected(false)
|
setConnected(false)
|
||||||
}
|
}
|
||||||
getHandler().close()
|
|
||||||
super.shutdown()
|
super.shutdown()
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Override
|
|
||||||
// protected Meta getMeasurementMeta() {
|
|
||||||
// return meta().getMeta("peakJump");
|
|
||||||
// }
|
|
||||||
|
|
||||||
@Throws(MeasurementException::class)
|
@Throws(MeasurementException::class)
|
||||||
override fun createMeasurement(): PeakJumpMeasurement {
|
override fun createMeasurement(): PeakJumpMeasurement {
|
||||||
val measurementMeta = meta().getMeta("peakJump")
|
val measurementMeta = meta().getMeta("peakJump")
|
||||||
@ -125,20 +152,16 @@ class MspDevice(context: Context, meta: Meta) : Sensor<Values>(context, meta), P
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Throws(ControlException::class)
|
@Throws(ControlException::class)
|
||||||
override fun computeState(stateName: String): Any {
|
override fun computeState(stateName: String): Any = when (stateName) {
|
||||||
when (stateName) {
|
"connected" -> false
|
||||||
"connected" -> return false
|
"filament" -> 1
|
||||||
"filament" -> return 1
|
"filamentOn" -> false//Always return false on first request
|
||||||
"filamentOn" -> return false//Always return false on first request
|
"filamentStatus" -> "UNKNOWN"
|
||||||
"filamentStatus" -> return "UNKNOWN"
|
"storing" -> false
|
||||||
"storing" -> return false
|
else -> super.computeState(stateName)
|
||||||
else -> return super.computeState(stateName)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getType(): String {
|
override fun getType(): String = MSP_DEVICE_TYPE
|
||||||
return "MKS E-Vision"
|
|
||||||
}
|
|
||||||
|
|
||||||
@Throws(ControlException::class)
|
@Throws(ControlException::class)
|
||||||
override fun requestStateChange(stateName: String, value: Value) {
|
override fun requestStateChange(stateName: String, value: Value) {
|
||||||
@ -162,40 +185,40 @@ class MspDevice(context: Context, meta: Meta) : Sensor<Values>(context, meta), P
|
|||||||
val sensorName: String
|
val sensorName: String
|
||||||
if (isConnected != connected) {
|
if (isConnected != connected) {
|
||||||
if (connected) {
|
if (connected) {
|
||||||
getHandler().holdBy(controller)
|
connection.open()
|
||||||
var response = sendAndWait("Sensors")
|
var response = commandAndWait("Sensors")
|
||||||
if (response.isOK) {
|
if (response.isOK) {
|
||||||
sensorName = response[2, 1]
|
sensorName = response[2, 1]
|
||||||
} else {
|
} else {
|
||||||
portError(response.errorDescription(), null)
|
notifyError(response.errorDescription(), null)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
//PENDING определеить в конфиге номер прибора
|
//PENDING определеить в конфиге номер прибора
|
||||||
|
|
||||||
response = sendAndWait("Select", sensorName)
|
response = commandAndWait("Select", sensorName)
|
||||||
if (response.isOK) {
|
if (response.isOK) {
|
||||||
updateState("selected", true)
|
updateState("selected", true)
|
||||||
// selected = true;
|
// selected = true;
|
||||||
} else {
|
} else {
|
||||||
portError(response.errorDescription(), null)
|
notifyError(response.errorDescription(), null)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
response = sendAndWait("Control", "inr.numass.msp", "1.0")
|
response = commandAndWait("Control", "inr.numass.msp", "1.0")
|
||||||
if (response.isOK) {
|
if (response.isOK) {
|
||||||
// controlled = true;
|
// controlled = true;
|
||||||
// invalidateState("controlled");
|
// invalidateState("controlled");
|
||||||
updateState("controlled", true)
|
updateState("controlled", true)
|
||||||
} else {
|
} else {
|
||||||
portError(response.errorDescription(), null)
|
notifyError(response.errorDescription(), null)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
// connected = true;
|
// connected = true;
|
||||||
updateState(PortSensor.CONNECTED_STATE, true)
|
updateState(PortSensor.CONNECTED_STATE, true)
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
getHandler().releaseBy(controller)
|
connection.close()
|
||||||
return !sendAndWait("Release").isOK
|
return !commandAndWait("Release").isOK
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@ -211,15 +234,8 @@ class MspDevice(context: Context, meta: Meta) : Sensor<Values>(context, meta), P
|
|||||||
* @throws PortException
|
* @throws PortException
|
||||||
*/
|
*/
|
||||||
@Throws(PortException::class)
|
@Throws(PortException::class)
|
||||||
private fun send(command: String, vararg parameters: Any) {
|
private fun command(command: String, vararg parameters: Any) {
|
||||||
val request = buildCommand(command, *parameters)
|
send(buildCommand(command, *parameters))
|
||||||
dispatchEvent(
|
|
||||||
EventBuilder
|
|
||||||
.make("msp")
|
|
||||||
.setMetaValue("request", request)
|
|
||||||
.build()
|
|
||||||
)
|
|
||||||
getHandler().send(request)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -248,25 +264,15 @@ class MspDevice(context: Context, meta: Meta) : Sensor<Values>(context, meta), P
|
|||||||
* @throws PortException
|
* @throws PortException
|
||||||
*/
|
*/
|
||||||
@Throws(PortException::class)
|
@Throws(PortException::class)
|
||||||
private fun sendAndWait(commandName: String, vararg parameters: Any): MspResponse {
|
private fun commandAndWait(commandName: String, vararg parameters: Any): MspResponse {
|
||||||
|
send(buildCommand(commandName, *parameters))
|
||||||
val request = buildCommand(commandName, *parameters)
|
val response = connection.waitFor(timeout) { str: String -> str.trim { it <= ' ' }.startsWith(commandName) }
|
||||||
dispatchEvent(
|
|
||||||
EventBuilder
|
|
||||||
.make("msp")
|
|
||||||
.setMetaValue("request", request)
|
|
||||||
.build()
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
getHandler().send(controller, request)
|
|
||||||
val response = controller.waitFor(TIMEOUT) { str: String -> str.trim { it <= ' ' }.startsWith(commandName) }
|
|
||||||
return MspResponse(response)
|
return MspResponse(response)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(PortException::class)
|
@Throws(PortException::class)
|
||||||
fun selectFilament(filament: Int) {
|
private fun selectFilament(filament: Int) {
|
||||||
val response = sendAndWait("FilamentSelect", filament)
|
val response = commandAndWait("FilamentSelect", filament)
|
||||||
if (response.isOK) {
|
if (response.isOK) {
|
||||||
updateState("filament", response[1, 1])
|
updateState("filament", response[1, 1])
|
||||||
} else {
|
} else {
|
||||||
@ -282,51 +288,22 @@ class MspDevice(context: Context, meta: Meta) : Sensor<Values>(context, meta), P
|
|||||||
* @throws hep.dataforge.exceptions.PortException
|
* @throws hep.dataforge.exceptions.PortException
|
||||||
*/
|
*/
|
||||||
@Throws(PortException::class)
|
@Throws(PortException::class)
|
||||||
fun setFilamentOn(filamentOn: Boolean): Boolean {
|
private fun setFilamentOn(filamentOn: Boolean): Boolean {
|
||||||
return if (filamentOn) {
|
return if (filamentOn) {
|
||||||
sendAndWait("FilamentControl", "On").isOK
|
commandAndWait("FilamentControl", "On").isOK
|
||||||
} else {
|
} else {
|
||||||
sendAndWait("FilamentControl", "Off").isOK
|
commandAndWait("FilamentControl", "Off").isOK
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//
|
||||||
/**
|
// /**
|
||||||
* Evaluate general async messages
|
// * Evaluate general async messages
|
||||||
*
|
// *
|
||||||
* @param response
|
// * @param response
|
||||||
*/
|
// */
|
||||||
private fun evaluateResponse(response: MspResponse) {
|
// private fun evaluateResponse(response: MspResponse) {
|
||||||
|
//
|
||||||
}
|
// }
|
||||||
|
|
||||||
override fun acceptPhrase(message: String) {
|
|
||||||
dispatchEvent(
|
|
||||||
EventBuilder
|
|
||||||
.make("msp")
|
|
||||||
.setMetaValue("response", message.trim { it <= ' ' }).build()
|
|
||||||
)
|
|
||||||
val response = MspResponse(message)
|
|
||||||
|
|
||||||
when (response.commandName) {
|
|
||||||
// all possible async messages
|
|
||||||
"FilamentStatus" -> {
|
|
||||||
val status = response[0, 2]
|
|
||||||
updateState("filamentOn", status == "ON")
|
|
||||||
updateState("filamentStatus", status)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (measurementDelegate != null) {
|
|
||||||
measurementDelegate!!.accept(response)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun portError(errorMessage: String?, error: Throwable?) {
|
|
||||||
notifyError(errorMessage, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getHandler(): TcpPort {
|
|
||||||
return handler ?: throw RuntimeException("Device not initialized")
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The MKS response as two-dimensional array of strings
|
* The MKS response as two-dimensional array of strings
|
||||||
@ -372,9 +349,7 @@ class MspDevice(context: Context, meta: Meta) : Sensor<Values>(context, meta), P
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun get(lineNo: Int, columnNo: Int): String {
|
operator fun get(lineNo: Int, columnNo: Int): String = data[lineNo][columnNo]
|
||||||
return data[lineNo][columnNo]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inner class PeakJumpMeasurement(private val meta: Meta) : AbstractMeasurement<Values>(), Consumer<MspResponse> {
|
inner class PeakJumpMeasurement(private val meta: Meta) : AbstractMeasurement<Values>(), Consumer<MspResponse> {
|
||||||
@ -398,9 +373,7 @@ class MspDevice(context: Context, meta: Meta) : Sensor<Values>(context, meta), P
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getDevice(): Device {
|
override fun getDevice(): Device = this@MspDevice
|
||||||
return this@MspDevice
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun start() {
|
override fun start() {
|
||||||
try {
|
try {
|
||||||
@ -409,11 +382,11 @@ class MspDevice(context: Context, meta: Meta) : Sensor<Values>(context, meta), P
|
|||||||
val accuracy = meta.getInt("accuracy", 5)!!
|
val accuracy = meta.getInt("accuracy", 5)!!
|
||||||
//PENDING вставить остальные параметры?
|
//PENDING вставить остальные параметры?
|
||||||
sendAndWait("MeasurementRemoveAll")
|
sendAndWait("MeasurementRemoveAll")
|
||||||
if (sendAndWait("AddPeakJump", measurementName, filterMode, accuracy, 0, 0, 0).isOK) {
|
if (commandAndWait("AddPeakJump", measurementName, filterMode, accuracy, 0, 0, 0).isOK) {
|
||||||
peakMap.clear()
|
peakMap.clear()
|
||||||
for (peak in meta.getMetaList("peak")) {
|
for (peak in meta.getMetaList("peak")) {
|
||||||
peakMap.put(peak.getInt("mass"), peak.getString("name", peak.getString("mass")))
|
peakMap.put(peak.getInt("mass"), peak.getString("name", peak.getString("mass")))
|
||||||
if (!sendAndWait("MeasurementAddMass", peak.getString("mass")).isOK) {
|
if (!commandAndWait("MeasurementAddMass", peak.getString("mass")).isOK) {
|
||||||
throw ControlException("Can't add mass to measurement measurement for msp")
|
throw ControlException("Can't add mass to measurement measurement for msp")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -424,11 +397,11 @@ class MspDevice(context: Context, meta: Meta) : Sensor<Values>(context, meta), P
|
|||||||
if (!isFilamentOn) {
|
if (!isFilamentOn) {
|
||||||
this.error("Can't start measurement. Filament is not turned on.", null)
|
this.error("Can't start measurement. Filament is not turned on.", null)
|
||||||
}
|
}
|
||||||
if (!sendAndWait("ScanAdd", measurementName).isOK) {
|
if (!commandAndWait("ScanAdd", measurementName).isOK) {
|
||||||
this.error("Failed to add scan", null)
|
this.error("Failed to add scan", null)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sendAndWait("ScanStart", 2).isOK) {
|
if (!commandAndWait("ScanStart", 2).isOK) {
|
||||||
this.error("Failed to start scan", null)
|
this.error("Failed to start scan", null)
|
||||||
}
|
}
|
||||||
} catch (ex: ControlException) {
|
} catch (ex: ControlException) {
|
||||||
@ -442,7 +415,7 @@ class MspDevice(context: Context, meta: Meta) : Sensor<Values>(context, meta), P
|
|||||||
override fun stop(force: Boolean): Boolean {
|
override fun stop(force: Boolean): Boolean {
|
||||||
try {
|
try {
|
||||||
collector.stop()
|
collector.stop()
|
||||||
val stop = sendAndWait("ScanStop").isOK
|
val stop = commandAndWait("ScanStop").isOK
|
||||||
afterStop()
|
afterStop()
|
||||||
helper.close()
|
helper.close()
|
||||||
return stop
|
return stop
|
||||||
@ -466,9 +439,6 @@ class MspDevice(context: Context, meta: Meta) : Sensor<Values>(context, meta), P
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun accept(response: MspResponse) {
|
override fun accept(response: MspResponse) {
|
||||||
|
|
||||||
//Evaluating device state change
|
|
||||||
evaluateResponse(response)
|
|
||||||
//Evaluating measurement information
|
//Evaluating measurement information
|
||||||
when (response.commandName) {
|
when (response.commandName) {
|
||||||
"MassReading" -> {
|
"MassReading" -> {
|
||||||
@ -484,7 +454,7 @@ class MspDevice(context: Context, meta: Meta) : Sensor<Values>(context, meta), P
|
|||||||
|
|
||||||
if (numScans == 0) {
|
if (numScans == 0) {
|
||||||
try {
|
try {
|
||||||
send("ScanResume", 10)
|
command("ScanResume", 10)
|
||||||
//FIXME обработать ошибку связи
|
//FIXME обработать ошибку связи
|
||||||
} catch (ex: PortException) {
|
} catch (ex: PortException) {
|
||||||
error(null, ex)
|
error(null, ex)
|
||||||
|
@ -111,12 +111,12 @@ abstract class DeviceDisplay<D : Device> : Component(), Connection, DeviceListen
|
|||||||
* @param property
|
* @param property
|
||||||
*/
|
*/
|
||||||
protected fun bindBooleanToState(state: String, property: BooleanProperty) {
|
protected fun bindBooleanToState(state: String, property: BooleanProperty) {
|
||||||
getStateBinding(state).addListener { observable, oldValue, newValue ->
|
getStateBinding(state).addListener { _, oldValue, newValue ->
|
||||||
if (isOpen && oldValue !== newValue) {
|
if (isOpen && oldValue !== newValue) {
|
||||||
property.value = newValue.booleanValue()
|
property.value = newValue.booleanValue()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
property.addListener { observable, oldValue, newValue ->
|
property.addListener { _, oldValue, newValue ->
|
||||||
if (isOpen && oldValue != newValue) {
|
if (isOpen && oldValue != newValue) {
|
||||||
runAsync {
|
runAsync {
|
||||||
if(!device.isInitialized){
|
if(!device.isInitialized){
|
||||||
|
@ -117,7 +117,7 @@ fun Node.deviceStateToggle(connection: DeviceDisplay<*>, state: String, title: S
|
|||||||
if (connection.device.hasState(state)) {
|
if (connection.device.hasState(state)) {
|
||||||
togglebutton(title) {
|
togglebutton(title) {
|
||||||
isSelected = false
|
isSelected = false
|
||||||
selectedProperty().addListener { observable, oldValue, newValue ->
|
selectedProperty().addListener { _, oldValue, newValue ->
|
||||||
if (oldValue != newValue) {
|
if (oldValue != newValue) {
|
||||||
connection.device.setState(state, newValue).thenAccept {
|
connection.device.setState(state, newValue).thenAccept {
|
||||||
isSelected = it.booleanValue()
|
isSelected = it.booleanValue()
|
||||||
|
@ -108,7 +108,7 @@ fun findDeviceMeta(config: Meta, criterion: Predicate<Meta>): Optional<Meta> {
|
|||||||
|
|
||||||
fun setupContext(meta: Meta): Context {
|
fun setupContext(meta: Meta): Context {
|
||||||
val ctx = Global.getContext("NUMASS-CONTROL")
|
val ctx = Global.getContext("NUMASS-CONTROL")
|
||||||
ctx.getPluginManager().getOrLoad(StorageManager::class.java)
|
ctx.pluginManager.getOrLoad(StorageManager::class.java)
|
||||||
return ctx
|
return ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ import inr.numass.control.DeviceView
|
|||||||
class CM32Device(context: Context, meta: Meta) : PortSensor<Double>(context, meta) {
|
class CM32Device(context: Context, meta: Meta) : PortSensor<Double>(context, meta) {
|
||||||
|
|
||||||
@Throws(ControlException::class)
|
@Throws(ControlException::class)
|
||||||
override fun buildHandler(portName: String): Port {
|
override fun buildPort(portName: String): Port {
|
||||||
logger.info("Connecting to port {}", portName)
|
logger.info("Connecting to port {}", portName)
|
||||||
val new: Port
|
val new: Port
|
||||||
if (portName.startsWith("com")) {
|
if (portName.startsWith("com")) {
|
||||||
@ -50,7 +50,7 @@ class CM32Device(context: Context, meta: Meta) : PortSensor<Double>(context, met
|
|||||||
@Throws(Exception::class)
|
@Throws(Exception::class)
|
||||||
override fun doMeasure(): Double? {
|
override fun doMeasure(): Double? {
|
||||||
|
|
||||||
val answer = sendAndWait("MES R PM 1\r\n", timeout())
|
val answer = sendAndWait("MES R PM 1\r\n")
|
||||||
|
|
||||||
if (answer.isEmpty()) {
|
if (answer.isEmpty()) {
|
||||||
this.updateMessage("No signal")
|
this.updateMessage("No signal")
|
||||||
|
@ -35,8 +35,8 @@ class MKSBaratronDevice(context: Context, meta: Meta) : PortSensor<Double>(conte
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Throws(ControlException::class)
|
@Throws(ControlException::class)
|
||||||
override fun buildHandler(portName: String): Port {
|
override fun buildPort(portName: String): Port {
|
||||||
val handler = super.buildHandler(portName)
|
val handler = super.buildPort(portName)
|
||||||
handler.setDelimiter("\r")
|
handler.setDelimiter("\r")
|
||||||
return handler
|
return handler
|
||||||
}
|
}
|
||||||
@ -50,7 +50,7 @@ class MKSBaratronDevice(context: Context, meta: Meta) : PortSensor<Double>(conte
|
|||||||
@Synchronized
|
@Synchronized
|
||||||
@Throws(Exception::class)
|
@Throws(Exception::class)
|
||||||
override fun doMeasure(): Double? {
|
override fun doMeasure(): Double? {
|
||||||
val answer = sendAndWait("AV" + channel + "\r", timeout())
|
val answer = sendAndWait("AV" + channel + "\r")
|
||||||
if (answer == null || answer.isEmpty()) {
|
if (answer == null || answer.isEmpty()) {
|
||||||
// invalidateState("connection");
|
// invalidateState("connection");
|
||||||
updateState(PortSensor.CONNECTED_STATE, false)
|
updateState(PortSensor.CONNECTED_STATE, false)
|
||||||
|
@ -66,7 +66,7 @@ class MKSVacDevice(context: Context, meta: Meta) : PortSensor<Double>(context, m
|
|||||||
|
|
||||||
@Throws(ControlException::class)
|
@Throws(ControlException::class)
|
||||||
private fun talk(requestContent: String): String? {
|
private fun talk(requestContent: String): String? {
|
||||||
val answer = sendAndWait(String.format("@%s%s;FF", deviceAddress, requestContent), timeout())
|
val answer = sendAndWait(String.format("@%s%s;FF", deviceAddress, requestContent))
|
||||||
|
|
||||||
val match = Pattern.compile("@" + deviceAddress + "ACK(.*);FF").matcher(answer)
|
val match = Pattern.compile("@" + deviceAddress + "ACK(.*);FF").matcher(answer)
|
||||||
return if (match.matches()) {
|
return if (match.matches()) {
|
||||||
@ -77,8 +77,8 @@ class MKSVacDevice(context: Context, meta: Meta) : PortSensor<Double>(context, m
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Throws(ControlException::class)
|
@Throws(ControlException::class)
|
||||||
override fun buildHandler(portName: String): Port {
|
override fun buildPort(portName: String): Port {
|
||||||
val handler = super.buildHandler(portName)
|
val handler = super.buildPort(portName)
|
||||||
handler.setDelimiter(";FF")
|
handler.setDelimiter(";FF")
|
||||||
return handler
|
return handler
|
||||||
}
|
}
|
||||||
|
@ -27,8 +27,8 @@ import java.util.regex.Pattern
|
|||||||
class MeradatVacDevice(context: Context, meta: Meta) : PortSensor<Double>(context, meta) {
|
class MeradatVacDevice(context: Context, meta: Meta) : PortSensor<Double>(context, meta) {
|
||||||
|
|
||||||
@Throws(ControlException::class)
|
@Throws(ControlException::class)
|
||||||
override fun buildHandler(portName: String): Port {
|
override fun buildPort(portName: String): Port {
|
||||||
val newHandler = super.buildHandler(portName)
|
val newHandler = super.buildPort(portName)
|
||||||
newHandler.setDelimiter("\r\n")
|
newHandler.setDelimiter("\r\n")
|
||||||
return newHandler
|
return newHandler
|
||||||
}
|
}
|
||||||
@ -59,7 +59,7 @@ class MeradatVacDevice(context: Context, meta: Meta) : PortSensor<Double>(contex
|
|||||||
@Throws(Exception::class)
|
@Throws(Exception::class)
|
||||||
override fun doMeasure(): Double? {
|
override fun doMeasure(): Double? {
|
||||||
|
|
||||||
val answer = sendAndWait(query, timeout()) { phrase -> phrase.startsWith(base) }
|
val answer = sendAndWait(query) { phrase -> phrase.startsWith(base) }
|
||||||
|
|
||||||
if (answer.isEmpty()) {
|
if (answer.isEmpty()) {
|
||||||
this.updateMessage("No signal")
|
this.updateMessage("No signal")
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
// alert('sending request to ${dataSource}')
|
// alert('sending request to ${dataSource}')
|
||||||
var query = new google.visualization.Query("${dataSource}", opts);
|
var query = new google.visualization.Query("${dataSource}", opts);
|
||||||
query.setRefreshInterval(${updateInterval});
|
query.setRefreshInterval(${updateInterval});
|
||||||
query.send(handleQueryResponse);
|
query.command(handleQueryResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleQueryResponse(response) {
|
function handleQueryResponse(response) {
|
||||||
|
Loading…
Reference in New Issue
Block a user