Migrate to DataForge 0.8.0

This commit is contained in:
Alexander Nozik 2024-03-04 15:24:27 +03:00
parent dbacdbc7cf
commit 2a700a5a2a
36 changed files with 103 additions and 134 deletions

View File

@ -5,8 +5,8 @@ plugins {
id("space.kscience.gradle.project") id("space.kscience.gradle.project")
} }
val dataforgeVersion: String by extra("0.7.1") val dataforgeVersion: String by extra("0.8.0")
val visionforgeVersion by extra("0.3.1") val visionforgeVersion by extra("0.4.0")
val ktorVersion: String by extra(space.kscience.gradle.KScienceVersions.ktorVersion) val ktorVersion: String by extra(space.kscience.gradle.KScienceVersions.ktorVersion)
val rsocketVersion by extra("0.15.4") val rsocketVersion by extra("0.15.4")
val xodusVersion by extra("2.0.1") val xodusVersion by extra("2.0.1")

View File

@ -5,7 +5,7 @@ import space.kscience.controls.api.PropertyDescriptor
import space.kscience.dataforge.context.Context import space.kscience.dataforge.context.Context
import space.kscience.dataforge.context.Factory import space.kscience.dataforge.context.Factory
import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.transformations.MetaConverter import space.kscience.dataforge.meta.MetaConverter
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.asName import space.kscience.dataforge.names.asName
import kotlin.properties.PropertyDelegateProvider import kotlin.properties.PropertyDelegateProvider

View File

@ -12,11 +12,7 @@ import space.kscience.controls.manager.install
import space.kscience.dataforge.context.Context import space.kscience.dataforge.context.Context
import space.kscience.dataforge.context.Factory import space.kscience.dataforge.context.Factory
import space.kscience.dataforge.context.request import space.kscience.dataforge.context.request
import space.kscience.dataforge.meta.Laminate import space.kscience.dataforge.meta.*
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.MutableMeta
import space.kscience.dataforge.meta.get
import space.kscience.dataforge.meta.transformations.MetaConverter
import space.kscience.dataforge.misc.DFExperimental import space.kscience.dataforge.misc.DFExperimental
import space.kscience.dataforge.names.* import space.kscience.dataforge.names.*
import kotlin.collections.set import kotlin.collections.set

View File

@ -10,7 +10,7 @@ import space.kscience.controls.spec.DevicePropertySpec
import space.kscience.controls.spec.MutableDevicePropertySpec import space.kscience.controls.spec.MutableDevicePropertySpec
import space.kscience.controls.spec.name import space.kscience.controls.spec.name
import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.transformations.MetaConverter import space.kscience.dataforge.meta.MetaConverter
import kotlin.time.Duration import kotlin.time.Duration
/** /**
@ -25,9 +25,9 @@ public interface DeviceState<T> {
public companion object public companion object
} }
public val <T> DeviceState<T>.metaFlow: Flow<Meta> get() = valueFlow.map(converter::objectToMeta) public val <T> DeviceState<T>.metaFlow: Flow<Meta> get() = valueFlow.map(converter::convert)
public val <T> DeviceState<T>.valueAsMeta: Meta get() = converter.objectToMeta(value) public val <T> DeviceState<T>.valueAsMeta: Meta get() = converter.convert(value)
/** /**
@ -38,9 +38,9 @@ public interface MutableDeviceState<T> : DeviceState<T> {
} }
public var <T : Any> MutableDeviceState<T>.valueAsMeta: Meta public var <T : Any> MutableDeviceState<T>.valueAsMeta: Meta
get() = converter.objectToMeta(value) get() = converter.convert(value)
set(arg) { set(arg) {
value = converter.metaToObject(arg) value = converter.read(arg)
} }
/** /**
@ -98,7 +98,7 @@ private open class BoundDeviceState<T>(
override val valueFlow: StateFlow<T> = device.messageFlow.filterIsInstance<PropertyChangedMessage>().filter { override val valueFlow: StateFlow<T> = device.messageFlow.filterIsInstance<PropertyChangedMessage>().filter {
it.property == propertyName it.property == propertyName
}.mapNotNull { }.mapNotNull {
converter.metaToObject(it.value) converter.read(it.value)
}.stateIn(device.context, SharingStarted.Eagerly, initialValue) }.stateIn(device.context, SharingStarted.Eagerly, initialValue)
override val value: T get() = valueFlow.value override val value: T get() = valueFlow.value
@ -111,7 +111,7 @@ public suspend fun <T> Device.propertyAsState(
propertyName: String, propertyName: String,
metaConverter: MetaConverter<T>, metaConverter: MetaConverter<T>,
): DeviceState<T> { ): DeviceState<T> {
val initialValue = metaConverter.metaToObject(readProperty(propertyName)) ?: error("Conversion of property failed") val initialValue = metaConverter.readOrNull(readProperty(propertyName)) ?: error("Conversion of property failed")
return BoundDeviceState(metaConverter, this, propertyName, initialValue) return BoundDeviceState(metaConverter, this, propertyName, initialValue)
} }
@ -140,7 +140,7 @@ private class MutableBoundDeviceState<T>(
get() = valueFlow.value get() = valueFlow.value
set(newValue) { set(newValue) {
device.launch { device.launch {
device.writeProperty(propertyName, converter.objectToMeta(newValue)) device.writeProperty(propertyName, converter.convert(newValue))
} }
} }
} }
@ -155,7 +155,7 @@ public suspend fun <T> Device.mutablePropertyAsState(
propertyName: String, propertyName: String,
metaConverter: MetaConverter<T>, metaConverter: MetaConverter<T>,
): MutableDeviceState<T> { ): MutableDeviceState<T> {
val initialValue = metaConverter.metaToObject(readProperty(propertyName)) ?: error("Conversion of property failed") val initialValue = metaConverter.readOrNull(readProperty(propertyName)) ?: error("Conversion of property failed")
return mutablePropertyAsState(propertyName, metaConverter, initialValue) return mutablePropertyAsState(propertyName, metaConverter, initialValue)
} }

View File

@ -9,9 +9,9 @@ import space.kscience.controls.manager.clock
import space.kscience.controls.spec.* import space.kscience.controls.spec.*
import space.kscience.dataforge.context.Context import space.kscience.dataforge.context.Context
import space.kscience.dataforge.context.Factory import space.kscience.dataforge.context.Factory
import space.kscience.dataforge.meta.MetaConverter
import space.kscience.dataforge.meta.double import space.kscience.dataforge.meta.double
import space.kscience.dataforge.meta.get import space.kscience.dataforge.meta.get
import space.kscience.dataforge.meta.transformations.MetaConverter
import kotlin.math.pow import kotlin.math.pow
import kotlin.time.Duration.Companion.milliseconds import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.DurationUnit import kotlin.time.DurationUnit

View File

@ -2,7 +2,7 @@ package space.kscience.controls.constructor
import space.kscience.controls.api.Device import space.kscience.controls.api.Device
import space.kscience.controls.spec.* import space.kscience.controls.spec.*
import space.kscience.dataforge.meta.transformations.MetaConverter import space.kscience.dataforge.meta.MetaConverter
/** /**

View File

@ -2,7 +2,7 @@ package space.kscience.controls.constructor
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import space.kscience.dataforge.meta.transformations.MetaConverter import space.kscience.dataforge.meta.MetaConverter
/** /**

View File

@ -139,7 +139,7 @@ public interface CachingDevice : Device {
/** /**
* Get the logical state of property or suspend to read the physical value. * Get the logical state of property or suspend to read the physical value.
*/ */
public suspend fun Device.requestProperty(propertyName: String): Meta = if (this is CachingDevice) { public suspend fun Device.getOrReadProperty(propertyName: String): Meta = if (this is CachingDevice) {
getProperty(propertyName) ?: readProperty(propertyName) getProperty(propertyName) ?: readProperty(propertyName)
} else { } else {
readProperty(propertyName) readProperty(propertyName)

View File

@ -16,7 +16,7 @@ public suspend fun Device.respondMessage(deviceTarget: Name, request: DeviceMess
is PropertyGetMessage -> { is PropertyGetMessage -> {
PropertyChangedMessage( PropertyChangedMessage(
property = request.property, property = request.property,
value = requestProperty(request.property), value = getOrReadProperty(request.property),
sourceDevice = deviceTarget, sourceDevice = deviceTarget,
targetDevice = request.sourceDevice targetDevice = request.sourceDevice
) )
@ -26,7 +26,7 @@ public suspend fun Device.respondMessage(deviceTarget: Name, request: DeviceMess
writeProperty(request.property, request.value) writeProperty(request.property, request.value)
PropertyChangedMessage( PropertyChangedMessage(
property = request.property, property = request.property,
value = requestProperty(request.property), value = getOrReadProperty(request.property),
sourceDevice = deviceTarget, sourceDevice = deviceTarget,
targetDevice = request.sourceDevice targetDevice = request.sourceDevice
) )

View File

@ -9,7 +9,7 @@ import space.kscience.controls.api.DeviceMessage
import space.kscience.controls.api.PropertyChangedMessage import space.kscience.controls.api.PropertyChangedMessage
import space.kscience.controls.spec.DevicePropertySpec import space.kscience.controls.spec.DevicePropertySpec
import space.kscience.controls.spec.name import space.kscience.controls.spec.name
import space.kscience.dataforge.meta.transformations.MetaConverter import space.kscience.dataforge.meta.MetaConverter
/** /**
* An interface for device property history. * An interface for device property history.
@ -42,7 +42,7 @@ public class CollectedPropertyHistory<T>(
private val store: SharedFlow<ValueWithTime<T>> = eventFlow private val store: SharedFlow<ValueWithTime<T>> = eventFlow
.filterIsInstance<PropertyChangedMessage>() .filterIsInstance<PropertyChangedMessage>()
.filter { it.property == propertyName } .filter { it.property == propertyName }
.map { ValueWithTime(converter.metaToObject(it.value), it.time) } .map { ValueWithTime(converter.read(it.value), it.time) }
.shareIn(scope, started = SharingStarted.Eagerly, replay = maxSize) .shareIn(scope, started = SharingStarted.Eagerly, replay = maxSize)
override fun flowHistory(from: Instant, until: Instant): Flow<ValueWithTime<T>> = override fun flowHistory(from: Instant, until: Instant): Flow<ValueWithTime<T>> =

View File

@ -5,10 +5,8 @@ import kotlinx.io.Sink
import kotlinx.io.Source import kotlinx.io.Source
import space.kscience.dataforge.io.IOFormat import space.kscience.dataforge.io.IOFormat
import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.MetaConverter
import space.kscience.dataforge.meta.get import space.kscience.dataforge.meta.get
import space.kscience.dataforge.meta.transformations.MetaConverter
import kotlin.reflect.KType
import kotlin.reflect.typeOf
/** /**
* A value coupled to a time it was obtained at * A value coupled to a time it was obtained at
@ -36,8 +34,6 @@ public data class ValueWithTime<T>(val value: T, val time: Instant) {
} }
private class ValueWithTimeIOFormat<T>(val valueFormat: IOFormat<T>) : IOFormat<ValueWithTime<T>> { private class ValueWithTimeIOFormat<T>(val valueFormat: IOFormat<T>) : IOFormat<ValueWithTime<T>> {
override val type: KType get() = typeOf<ValueWithTime<T>>()
override fun readFrom(source: Source): ValueWithTime<T> { override fun readFrom(source: Source): ValueWithTime<T> {
val timestamp = InstantIOFormat.readFrom(source) val timestamp = InstantIOFormat.readFrom(source)
@ -56,18 +52,18 @@ private class ValueWithTimeMetaConverter<T>(
val valueConverter: MetaConverter<T>, val valueConverter: MetaConverter<T>,
) : MetaConverter<ValueWithTime<T>> { ) : MetaConverter<ValueWithTime<T>> {
override val type: KType = typeOf<ValueWithTime<T>>()
override fun metaToObjectOrNull( override fun readOrNull(
meta: Meta, source: Meta,
): ValueWithTime<T>? = valueConverter.metaToObject(meta[ValueWithTime.META_VALUE_KEY] ?: Meta.EMPTY)?.let { ): ValueWithTime<T>? = valueConverter.read(source[ValueWithTime.META_VALUE_KEY] ?: Meta.EMPTY)?.let {
ValueWithTime(it, meta[ValueWithTime.META_TIME_KEY]?.instant ?: Instant.DISTANT_PAST) ValueWithTime(it, source[ValueWithTime.META_TIME_KEY]?.instant ?: Instant.DISTANT_PAST)
} }
override fun objectToMeta(obj: ValueWithTime<T>): Meta = Meta { override fun convert(obj: ValueWithTime<T>): Meta = Meta {
ValueWithTime.META_TIME_KEY put obj.time.toMeta() ValueWithTime.META_TIME_KEY put obj.time.toMeta()
ValueWithTime.META_VALUE_KEY put valueConverter.objectToMeta(obj.value) ValueWithTime.META_VALUE_KEY put valueConverter.convert(obj.value)
} }
} }
public fun <T : Any> MetaConverter<T>.withTime(): MetaConverter<ValueWithTime<T>> = ValueWithTimeMetaConverter(this) public fun <T : Any> MetaConverter<T>.withTime(): MetaConverter<ValueWithTime<T>> = ValueWithTimeMetaConverter(this)

View File

@ -21,7 +21,7 @@ import kotlin.coroutines.CoroutineContext
*/ */
@OptIn(InternalDeviceAPI::class) @OptIn(InternalDeviceAPI::class)
private suspend fun <D : Device, T> MutableDevicePropertySpec<D, T>.writeMeta(device: D, item: Meta) { private suspend fun <D : Device, T> MutableDevicePropertySpec<D, T>.writeMeta(device: D, item: Meta) {
write(device, converter.metaToObject(item) ?: error("Meta $item could not be read with $converter")) write(device, converter.readOrNull(item) ?: error("Meta $item could not be read with $converter"))
} }
/** /**
@ -29,16 +29,16 @@ private suspend fun <D : Device, T> MutableDevicePropertySpec<D, T>.writeMeta(de
*/ */
@OptIn(InternalDeviceAPI::class) @OptIn(InternalDeviceAPI::class)
private suspend fun <D : Device, T> DevicePropertySpec<D, T>.readMeta(device: D): Meta? = private suspend fun <D : Device, T> DevicePropertySpec<D, T>.readMeta(device: D): Meta? =
read(device)?.let(converter::objectToMeta) read(device)?.let(converter::convert)
private suspend fun <D : Device, I, O> DeviceActionSpec<D, I, O>.executeWithMeta( private suspend fun <D : Device, I, O> DeviceActionSpec<D, I, O>.executeWithMeta(
device: D, device: D,
item: Meta, item: Meta,
): Meta? { ): Meta? {
val arg: I = inputConverter.metaToObject(item) ?: error("Failed to convert $item with $inputConverter") val arg: I = inputConverter.readOrNull(item) ?: error("Failed to convert $item with $inputConverter")
val res = execute(device, arg) val res = execute(device, arg)
return res?.let { outputConverter.objectToMeta(res) } return res?.let { outputConverter.convert(res) }
} }
@ -120,7 +120,7 @@ public abstract class DeviceBase<D : Device>(
* Notify the device that a property with [spec] value is changed * Notify the device that a property with [spec] value is changed
*/ */
protected suspend fun <T> propertyChanged(spec: DevicePropertySpec<D, T>, value: T) { protected suspend fun <T> propertyChanged(spec: DevicePropertySpec<D, T>, value: T) {
propertyChanged(spec.name, spec.converter.objectToMeta(value)) propertyChanged(spec.name, spec.converter.convert(value))
} }
/** /**

View File

@ -3,7 +3,7 @@ package space.kscience.controls.spec
import space.kscience.controls.api.Device import space.kscience.controls.api.Device
import space.kscience.controls.api.PropertyDescriptor import space.kscience.controls.api.PropertyDescriptor
import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.transformations.MetaConverter import space.kscience.dataforge.meta.MetaConverter
internal object DeviceMetaPropertySpec : DevicePropertySpec<Device, Meta> { internal object DeviceMetaPropertySpec : DevicePropertySpec<Device, Meta> {
override val descriptor: PropertyDescriptor = PropertyDescriptor("@meta") override val descriptor: PropertyDescriptor = PropertyDescriptor("@meta")

View File

@ -5,7 +5,7 @@ import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.* import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import space.kscience.controls.api.* import space.kscience.controls.api.*
import space.kscience.dataforge.meta.transformations.MetaConverter import space.kscience.dataforge.meta.MetaConverter
/** /**
@ -72,23 +72,23 @@ public interface DeviceActionSpec<in D, I, O> {
public val DeviceActionSpec<*, *, *>.name: String get() = descriptor.name public val DeviceActionSpec<*, *, *>.name: String get() = descriptor.name
public suspend fun <T, D : Device> D.read(propertySpec: DevicePropertySpec<D, T>): T = public suspend fun <T, D : Device> D.read(propertySpec: DevicePropertySpec<D, T>): T =
propertySpec.converter.metaToObject(readProperty(propertySpec.name)) ?: error("Property read result is not valid") propertySpec.converter.readOrNull(readProperty(propertySpec.name)) ?: error("Property read result is not valid")
/** /**
* Read typed value and update/push event if needed. * Read typed value and update/push event if needed.
* Return null if property read is not successful or property is undefined. * Return null if property read is not successful or property is undefined.
*/ */
public suspend fun <T, D : DeviceBase<D>> D.readOrNull(propertySpec: DevicePropertySpec<D, T>): T? = public suspend fun <T, D : DeviceBase<D>> D.readOrNull(propertySpec: DevicePropertySpec<D, T>): T? =
readPropertyOrNull(propertySpec.name)?.let(propertySpec.converter::metaToObject) readPropertyOrNull(propertySpec.name)?.let(propertySpec.converter::readOrNull)
public suspend fun <T, D : Device> D.request(propertySpec: DevicePropertySpec<D, T>): T = public suspend fun <T, D : Device> D.getOrRead(propertySpec: DevicePropertySpec<D, T>): T =
propertySpec.converter.metaToObject(requestProperty(propertySpec.name)) propertySpec.converter.read(getOrReadProperty(propertySpec.name))
/** /**
* Write typed property state and invalidate logical state * Write typed property state and invalidate logical state
*/ */
public suspend fun <T, D : Device> D.write(propertySpec: MutableDevicePropertySpec<D, T>, value: T) { public suspend fun <T, D : Device> D.write(propertySpec: MutableDevicePropertySpec<D, T>, value: T) {
writeProperty(propertySpec.name, propertySpec.converter.objectToMeta(value)) writeProperty(propertySpec.name, propertySpec.converter.convert(value))
} }
/** /**
@ -104,7 +104,7 @@ public fun <T, D : Device> D.writeAsync(propertySpec: MutableDevicePropertySpec<
public fun <D : Device, T> D.propertyFlow(spec: DevicePropertySpec<D, T>): Flow<T> = messageFlow public fun <D : Device, T> D.propertyFlow(spec: DevicePropertySpec<D, T>): Flow<T> = messageFlow
.filterIsInstance<PropertyChangedMessage>() .filterIsInstance<PropertyChangedMessage>()
.filter { it.property == spec.name } .filter { it.property == spec.name }
.mapNotNull { spec.converter.metaToObject(it.value) } .mapNotNull { spec.converter.read(it.value) }
/** /**
* A type safe property change listener. Uses the device [CoroutineScope]. * A type safe property change listener. Uses the device [CoroutineScope].
@ -117,7 +117,7 @@ public fun <D : Device, T> D.onPropertyChange(
.filterIsInstance<PropertyChangedMessage>() .filterIsInstance<PropertyChangedMessage>()
.filter { it.property == spec.name } .filter { it.property == spec.name }
.onEach { change -> .onEach { change ->
val newValue = spec.converter.metaToObject(change.value) val newValue = spec.converter.read(change.value)
if (newValue != null) { if (newValue != null) {
change.callback(newValue) change.callback(newValue)
} }
@ -136,7 +136,7 @@ public fun <D : Device, T> D.useProperty(
.filterIsInstance<PropertyChangedMessage>() .filterIsInstance<PropertyChangedMessage>()
.filter { it.property == spec.name } .filter { it.property == spec.name }
.collect { change -> .collect { change ->
val newValue = spec.converter.metaToObject(change.value) val newValue = spec.converter.readOrNull(change.value)
if (newValue != null) { if (newValue != null) {
callback(newValue) callback(newValue)
} }

View File

@ -5,20 +5,16 @@ import space.kscience.controls.api.ActionDescriptor
import space.kscience.controls.api.Device import space.kscience.controls.api.Device
import space.kscience.controls.api.PropertyDescriptor import space.kscience.controls.api.PropertyDescriptor
import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.transformations.MetaConverter import space.kscience.dataforge.meta.MetaConverter
import kotlin.properties.PropertyDelegateProvider import kotlin.properties.PropertyDelegateProvider
import kotlin.properties.ReadOnlyProperty import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty import kotlin.reflect.KProperty
import kotlin.reflect.KType
import kotlin.reflect.typeOf
public object UnitMetaConverter : MetaConverter<Unit> { public object UnitMetaConverter : MetaConverter<Unit> {
override val type: KType = typeOf<Unit>() override fun readOrNull(source: Meta): Unit = Unit
override fun metaToObjectOrNull(meta: Meta): Unit = Unit override fun convert(obj: Unit): Meta = Meta.EMPTY
override fun objectToMeta(obj: Unit): Meta = Meta.EMPTY
} }
public val MetaConverter.Companion.unit: MetaConverter<Unit> get() = UnitMetaConverter public val MetaConverter.Companion.unit: MetaConverter<Unit> get() = UnitMetaConverter

View File

@ -1,9 +1,6 @@
package space.kscience.controls.spec package space.kscience.controls.spec
import space.kscience.dataforge.meta.* import space.kscience.dataforge.meta.*
import space.kscience.dataforge.meta.transformations.MetaConverter
import kotlin.reflect.KType
import kotlin.reflect.typeOf
import kotlin.time.Duration import kotlin.time.Duration
import kotlin.time.DurationUnit import kotlin.time.DurationUnit
import kotlin.time.toDuration import kotlin.time.toDuration
@ -12,16 +9,14 @@ public fun Double.asMeta(): Meta = Meta(asValue())
//TODO to be moved to DF //TODO to be moved to DF
public object DurationConverter : MetaConverter<Duration> { public object DurationConverter : MetaConverter<Duration> {
override val type: KType = typeOf<Duration>() override fun readOrNull(source: Meta): Duration = source.value?.double?.toDuration(DurationUnit.SECONDS)
override fun metaToObjectOrNull(meta: Meta): Duration = meta.value?.double?.toDuration(DurationUnit.SECONDS)
?: run { ?: run {
val unit: DurationUnit = meta["unit"].enum<DurationUnit>() ?: DurationUnit.SECONDS val unit: DurationUnit = source["unit"].enum<DurationUnit>() ?: DurationUnit.SECONDS
val value = meta[Meta.VALUE_KEY].double ?: error("No value present for Duration") val value = source[Meta.VALUE_KEY].double ?: error("No value present for Duration")
return@run value.toDuration(unit) return@run value.toDuration(unit)
} }
override fun objectToMeta(obj: Duration): Meta = obj.toDouble(DurationUnit.SECONDS).asMeta() override fun convert(obj: Duration): Meta = obj.toDouble(DurationUnit.SECONDS).asMeta()
} }
public val MetaConverter.Companion.duration: MetaConverter<Duration> get() = DurationConverter public val MetaConverter.Companion.duration: MetaConverter<Duration> get() = DurationConverter

View File

@ -4,8 +4,8 @@ import space.kscience.controls.api.Device
import space.kscience.controls.api.PropertyDescriptor import space.kscience.controls.api.PropertyDescriptor
import space.kscience.controls.api.metaDescriptor import space.kscience.controls.api.metaDescriptor
import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.MetaConverter
import space.kscience.dataforge.meta.ValueType import space.kscience.dataforge.meta.ValueType
import space.kscience.dataforge.meta.transformations.MetaConverter
import kotlin.properties.PropertyDelegateProvider import kotlin.properties.PropertyDelegateProvider
import kotlin.properties.ReadOnlyProperty import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KMutableProperty1 import kotlin.reflect.KMutableProperty1
@ -53,8 +53,8 @@ public fun <T, D : DeviceBase<D>> DeviceSpec<D>.logicalProperty(
converter, converter,
descriptorBuilder, descriptorBuilder,
name, name,
read = { propertyName -> getProperty(propertyName)?.let(converter::metaToObject) }, read = { propertyName -> getProperty(propertyName)?.let(converter::readOrNull) },
write = { propertyName, value -> writeProperty(propertyName, converter.objectToMeta(value)) } write = { propertyName, value -> writeProperty(propertyName, converter.convert(value)) }
) )

View File

@ -1,7 +1,7 @@
import space.kscience.visionforge.html.runVisionClient
import space.kscience.visionforge.jupyter.VFNotebookClient import space.kscience.visionforge.jupyter.VFNotebookClient
import space.kscience.visionforge.markup.MarkupPlugin import space.kscience.visionforge.markup.MarkupPlugin
import space.kscience.visionforge.plotly.PlotlyPlugin import space.kscience.visionforge.plotly.PlotlyPlugin
import space.kscience.visionforge.runVisionClient
public fun main(): Unit = runVisionClient { public fun main(): Unit = runVisionClient {
// plugin(DeviceManager) // plugin(DeviceManager)

View File

@ -144,7 +144,7 @@ public fun <T> MagixEndpoint.controlsPropertyFlow(
.filter { message -> .filter { message ->
message.sourceDevice == deviceName && message.property == propertySpec.name message.sourceDevice == deviceName && message.property == propertySpec.name
}.map { }.map {
propertySpec.converter.metaToObject(it.value) propertySpec.converter.read(it.value)
} }
} }
@ -157,7 +157,7 @@ public suspend fun <T> MagixEndpoint.sendControlsPropertyChange(
) { ) {
val message = PropertySetMessage( val message = PropertySetMessage(
property = propertySpec.name, property = propertySpec.name,
value = propertySpec.converter.objectToMeta(value), value = propertySpec.converter.convert(value),
targetDevice = deviceName targetDevice = deviceName
) )
send(DeviceManager.magixFormat, message, source = sourceEndpointName, target = targetEndpointName) send(DeviceManager.magixFormat, message, source = sourceEndpointName, target = targetEndpointName)
@ -177,6 +177,6 @@ public fun <T> MagixEndpoint.controlsPropertyMessageFlow(
.filter { message -> .filter { message ->
message.sourceDevice == deviceName && message.property == propertySpec.name message.sourceDevice == deviceName && message.property == propertySpec.name
}.map { }.map {
it to propertySpec.converter.metaToObject(it.value) it to propertySpec.converter.read(it.value)
} }
} }

View File

@ -5,7 +5,7 @@ import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.* import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import space.kscience.controls.api.PropertyChangedMessage import space.kscience.controls.api.PropertyChangedMessage
import space.kscience.controls.api.requestProperty import space.kscience.controls.api.getOrReadProperty
import space.kscience.controls.spec.DeviceActionSpec import space.kscience.controls.spec.DeviceActionSpec
import space.kscience.controls.spec.DevicePropertySpec import space.kscience.controls.spec.DevicePropertySpec
import space.kscience.controls.spec.MutableDevicePropertySpec import space.kscience.controls.spec.MutableDevicePropertySpec
@ -17,14 +17,14 @@ import space.kscience.dataforge.meta.Meta
* An accessor that allows DeviceClient to connect to any property without type checks * An accessor that allows DeviceClient to connect to any property without type checks
*/ */
public suspend fun <T> DeviceClient.read(propertySpec: DevicePropertySpec<*, T>): T = public suspend fun <T> DeviceClient.read(propertySpec: DevicePropertySpec<*, T>): T =
propertySpec.converter.metaToObject(readProperty(propertySpec.name)) ?: error("Property read result is not valid") propertySpec.converter.readOrNull(readProperty(propertySpec.name)) ?: error("Property read result is not valid")
public suspend fun <T> DeviceClient.request(propertySpec: DevicePropertySpec<*, T>): T = public suspend fun <T> DeviceClient.request(propertySpec: DevicePropertySpec<*, T>): T =
propertySpec.converter.metaToObject(requestProperty(propertySpec.name)) propertySpec.converter.read(getOrReadProperty(propertySpec.name))
public suspend fun <T> DeviceClient.write(propertySpec: MutableDevicePropertySpec<*, T>, value: T) { public suspend fun <T> DeviceClient.write(propertySpec: MutableDevicePropertySpec<*, T>, value: T) {
writeProperty(propertySpec.name, propertySpec.converter.objectToMeta(value)) writeProperty(propertySpec.name, propertySpec.converter.convert(value))
} }
public fun <T> DeviceClient.writeAsync(propertySpec: MutableDevicePropertySpec<*, T>, value: T): Job = launch { public fun <T> DeviceClient.writeAsync(propertySpec: MutableDevicePropertySpec<*, T>, value: T): Job = launch {
@ -34,7 +34,7 @@ public fun <T> DeviceClient.writeAsync(propertySpec: MutableDevicePropertySpec<*
public fun <T> DeviceClient.propertyFlow(spec: DevicePropertySpec<*, T>): Flow<T> = messageFlow public fun <T> DeviceClient.propertyFlow(spec: DevicePropertySpec<*, T>): Flow<T> = messageFlow
.filterIsInstance<PropertyChangedMessage>() .filterIsInstance<PropertyChangedMessage>()
.filter { it.property == spec.name } .filter { it.property == spec.name }
.mapNotNull { spec.converter.metaToObject(it.value) } .mapNotNull { spec.converter.readOrNull(it.value) }
public fun <T> DeviceClient.onPropertyChange( public fun <T> DeviceClient.onPropertyChange(
spec: DevicePropertySpec<*, T>, spec: DevicePropertySpec<*, T>,
@ -44,7 +44,7 @@ public fun <T> DeviceClient.onPropertyChange(
.filterIsInstance<PropertyChangedMessage>() .filterIsInstance<PropertyChangedMessage>()
.filter { it.property == spec.name } .filter { it.property == spec.name }
.onEach { change -> .onEach { change ->
val newValue = spec.converter.metaToObject(change.value) val newValue = spec.converter.readOrNull(change.value)
if (newValue != null) { if (newValue != null) {
change.callback(newValue) change.callback(newValue)
} }
@ -60,7 +60,7 @@ public fun <T> DeviceClient.useProperty(
.filterIsInstance<PropertyChangedMessage>() .filterIsInstance<PropertyChangedMessage>()
.filter { it.property == spec.name } .filter { it.property == spec.name }
.collect { change -> .collect { change ->
val newValue = spec.converter.metaToObject(change.value) val newValue = spec.converter.readOrNull(change.value)
if (newValue != null) { if (newValue != null) {
callback(newValue) callback(newValue)
} }
@ -68,12 +68,12 @@ public fun <T> DeviceClient.useProperty(
} }
public suspend fun <I, O> DeviceClient.execute(actionSpec: DeviceActionSpec<*, I, O>, input: I): O { public suspend fun <I, O> DeviceClient.execute(actionSpec: DeviceActionSpec<*, I, O>, input: I): O {
val inputMeta = actionSpec.inputConverter.objectToMeta(input) val inputMeta = actionSpec.inputConverter.convert(input)
val res = execute(actionSpec.name, inputMeta) val res = execute(actionSpec.name, inputMeta)
return actionSpec.outputConverter.metaToObject(res ?: Meta.EMPTY) return actionSpec.outputConverter.read(res ?: Meta.EMPTY)
} }
public suspend fun <O> DeviceClient.execute(actionSpec: DeviceActionSpec<*, Unit, O>): O { public suspend fun <O> DeviceClient.execute(actionSpec: DeviceActionSpec<*, Unit, O>): O {
val res = execute(actionSpec.name, Meta.EMPTY) val res = execute(actionSpec.name, Meta.EMPTY)
return actionSpec.outputConverter.metaToObject(res ?: Meta.EMPTY) return actionSpec.outputConverter.read(res ?: Meta.EMPTY)
} }

View File

@ -6,7 +6,7 @@ import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import space.kscience.controls.api.get import space.kscience.controls.api.get
import space.kscience.controls.api.requestProperty import space.kscience.controls.api.getOrReadProperty
import space.kscience.controls.manager.DeviceManager import space.kscience.controls.manager.DeviceManager
import space.kscience.dataforge.context.error import space.kscience.dataforge.context.error
import space.kscience.dataforge.context.logger import space.kscience.dataforge.context.logger
@ -91,7 +91,7 @@ public fun DeviceManager.launchTangoMagix(
val device = get(payload.device) val device = get(payload.device)
when (payload.action) { when (payload.action) {
TangoAction.read -> { TangoAction.read -> {
val value = device.requestProperty(payload.name) val value = device.getOrReadProperty(payload.name)
respond(request, payload) { requestPayload -> respond(request, payload) { requestPayload ->
requestPayload.copy( requestPayload.copy(
value = value, value = value,
@ -104,7 +104,7 @@ public fun DeviceManager.launchTangoMagix(
device.writeProperty(payload.name, value) device.writeProperty(payload.name, value)
} }
//wait for value to be written and return final state //wait for value to be written and return final state
val value = device.requestProperty(payload.name) val value = device.getOrReadProperty(payload.name)
respond(request, payload) { requestPayload -> respond(request, payload) { requestPayload ->
requestPayload.copy( requestPayload.copy(
value = value, value = value,

View File

@ -9,8 +9,8 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.*
import org.eclipse.milo.opcua.stack.core.types.enumerated.TimestampsToReturn import org.eclipse.milo.opcua.stack.core.types.enumerated.TimestampsToReturn
import space.kscience.controls.api.Device import space.kscience.controls.api.Device
import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.MetaConverter
import space.kscience.dataforge.meta.MetaSerializer import space.kscience.dataforge.meta.MetaSerializer
import space.kscience.dataforge.meta.transformations.MetaConverter
import kotlin.properties.ReadWriteProperty import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty import kotlin.reflect.KProperty
@ -43,7 +43,7 @@ public suspend inline fun <reified T: Any> OpcUaDevice.readOpcWithTime(
else -> error("Incompatible OPC property value $content") else -> error("Incompatible OPC property value $content")
} }
val res: T = converter.metaToObject(meta) val res: T = converter.read(meta)
return res to time return res to time
} }
@ -69,7 +69,7 @@ public suspend inline fun <reified T> OpcUaDevice.readOpc(
else -> error("Incompatible OPC property value $content") else -> error("Incompatible OPC property value $content")
} }
return converter.metaToObject(meta) ?: error("Meta $meta could not be converted to ${T::class}") return converter.readOrNull(meta) ?: error("Meta $meta could not be converted to ${T::class}")
} }
public suspend inline fun <reified T> OpcUaDevice.writeOpc( public suspend inline fun <reified T> OpcUaDevice.writeOpc(
@ -77,7 +77,7 @@ public suspend inline fun <reified T> OpcUaDevice.writeOpc(
converter: MetaConverter<T>, converter: MetaConverter<T>,
value: T value: T
): StatusCode { ): StatusCode {
val meta = converter.objectToMeta(value) val meta = converter.convert(value)
return client.writeValue(nodeId, DataValue(Variant(meta))).await() return client.writeValue(nodeId, DataValue(Variant(meta))).await()
} }

View File

@ -31,7 +31,7 @@ public class MiloConfiguration : Scheme() {
public var endpointUrl: String by string { error("Endpoint url is not defined") } public var endpointUrl: String by string { error("Endpoint url is not defined") }
public var username: MiloUsername? by specOrNull(MiloUsername) public var username: MiloUsername? by schemeOrNull(MiloUsername)
public var securityPolicy: SecurityPolicy by enum(SecurityPolicy.None) public var securityPolicy: SecurityPolicy by enum(SecurityPolicy.None)

View File

@ -7,7 +7,7 @@ import org.junit.jupiter.api.Test
import space.kscience.controls.spec.DeviceSpec import space.kscience.controls.spec.DeviceSpec
import space.kscience.controls.spec.doubleProperty import space.kscience.controls.spec.doubleProperty
import space.kscience.controls.spec.read import space.kscience.controls.spec.read
import space.kscience.dataforge.meta.transformations.MetaConverter import space.kscience.dataforge.meta.MetaConverter
import kotlin.test.Ignore import kotlin.test.Ignore
class OpcUaClientTest { class OpcUaClientTest {

View File

@ -6,8 +6,6 @@ import jetbrains.exodus.entitystore.PersistentEntityStores
import jetbrains.exodus.entitystore.StoreTransaction import jetbrains.exodus.entitystore.StoreTransaction
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.asFlow import kotlinx.coroutines.flow.asFlow
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.map
import kotlinx.datetime.Instant import kotlinx.datetime.Instant
import kotlinx.serialization.encodeToString import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
@ -72,13 +70,13 @@ public class XodusDeviceMessageStorage(
DEVICE_MESSAGE_ENTITY_TYPE, DEVICE_MESSAGE_ENTITY_TYPE,
DeviceMessage::time.name, DeviceMessage::time.name,
true true
).asFlow().map { ).map {
Json.decodeFromString( Json.decodeFromString(
DeviceMessage.serializer(), DeviceMessage.serializer(),
it.getBlobString("json") ?: error("No json content found") it.getBlobString("json") ?: error("No json content found")
) )
} }
} }.asFlow()
override fun read( override fun read(
eventType: String, eventType: String,
@ -90,7 +88,7 @@ public class XodusDeviceMessageStorage(
DEVICE_MESSAGE_ENTITY_TYPE, DEVICE_MESSAGE_ENTITY_TYPE,
"type", "type",
eventType eventType
).asFlow().filter { ).filter {
it.timeInRange(range) && it.timeInRange(range) &&
it.propertyMatchesName(DeviceMessage::sourceDevice.name, sourceDevice) && it.propertyMatchesName(DeviceMessage::sourceDevice.name, sourceDevice) &&
it.propertyMatchesName(DeviceMessage::targetDevice.name, targetDevice) it.propertyMatchesName(DeviceMessage::targetDevice.name, targetDevice)
@ -100,7 +98,7 @@ public class XodusDeviceMessageStorage(
it.getBlobString("json") ?: error("No json content found") it.getBlobString("json") ?: error("No json content found")
) )
} }
} }.asFlow()
override fun close() { override fun close() {
entityStore.close() entityStore.close()

View File

@ -1,5 +1,6 @@
import jetbrains.exodus.entitystore.PersistentEntityStores import jetbrains.exodus.entitystore.PersistentEntityStores
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import kotlinx.datetime.Instant import kotlinx.datetime.Instant
import org.junit.jupiter.api.AfterAll import org.junit.jupiter.api.AfterAll
@ -7,8 +8,8 @@ import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.BeforeAll import org.junit.jupiter.api.BeforeAll
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import space.kscience.controls.api.PropertyChangedMessage import space.kscience.controls.api.PropertyChangedMessage
import space.kscience.controls.storage.read
import space.kscience.controls.xodus.XodusDeviceMessageStorage import space.kscience.controls.xodus.XodusDeviceMessageStorage
import space.kscience.controls.xodus.query
import space.kscience.controls.xodus.writeMessage import space.kscience.controls.xodus.writeMessage
import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
@ -67,7 +68,7 @@ internal class PropertyHistoryTest {
XodusDeviceMessageStorage(entityStore).use { storage -> XodusDeviceMessageStorage(entityStore).use { storage ->
assertEquals( assertEquals(
propertyChangedMessages[0], propertyChangedMessages[0],
storage.query<PropertyChangedMessage>( storage.read<PropertyChangedMessage>(
sourceDevice = "virtual-car".asName() sourceDevice = "virtual-car".asName()
).first { it.property == "speed" } ).first { it.property == "speed" }
) )

View File

@ -7,7 +7,7 @@ import kotlinx.datetime.Instant
import space.kscience.controls.api.PropertyChangedMessage import space.kscience.controls.api.PropertyChangedMessage
import space.kscience.controls.misc.PropertyHistory import space.kscience.controls.misc.PropertyHistory
import space.kscience.controls.misc.ValueWithTime import space.kscience.controls.misc.ValueWithTime
import space.kscience.dataforge.meta.transformations.MetaConverter import space.kscience.dataforge.meta.MetaConverter
public fun <T> DeviceMessageStorage.propertyHistory( public fun <T> DeviceMessageStorage.propertyHistory(
propertyName: String, propertyName: String,
@ -16,5 +16,5 @@ public fun <T> DeviceMessageStorage.propertyHistory(
override fun flowHistory(from: Instant, until: Instant): Flow<ValueWithTime<T>> = override fun flowHistory(from: Instant, until: Instant): Flow<ValueWithTime<T>> =
read<PropertyChangedMessage>(from..until) read<PropertyChangedMessage>(from..until)
.filter { it.property == propertyName } .filter { it.property == propertyName }
.map { ValueWithTime(converter.metaToObject(it.value), it.time) } .map { ValueWithTime(converter.read(it.value), it.time) }
} }

View File

@ -149,7 +149,7 @@ private fun <T> Trace.updateFromState(
public fun <T> Plot.plotDeviceState( public fun <T> Plot.plotDeviceState(
context: Context, context: Context,
state: DeviceState<T>, state: DeviceState<T>,
extractValue: T.() -> Value = { state.converter.objectToMeta(this).value ?: Null }, extractValue: T.() -> Value = { state.converter.convert(this).value ?: Null },
maxAge: Duration = defaultMaxAge, maxAge: Duration = defaultMaxAge,
maxPoints: Int = defaultMaxPoints, maxPoints: Int = defaultMaxPoints,
minPoints: Int = defaultMinPoints, minPoints: Int = defaultMinPoints,

View File

@ -7,10 +7,9 @@ import space.kscience.dataforge.context.PluginFactory
import space.kscience.dataforge.context.PluginTag import space.kscience.dataforge.context.PluginTag
import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.visionforge.ElementVisionRenderer
import space.kscience.visionforge.Vision import space.kscience.visionforge.Vision
import space.kscience.visionforge.VisionClient
import space.kscience.visionforge.VisionPlugin import space.kscience.visionforge.VisionPlugin
import space.kscience.visionforge.html.ElementVisionRenderer
public actual class ControlVisionPlugin : VisionPlugin(), ElementVisionRenderer { public actual class ControlVisionPlugin : VisionPlugin(), ElementVisionRenderer {
override val tag: PluginTag get() = Companion.tag override val tag: PluginTag get() = Companion.tag
@ -21,7 +20,7 @@ public actual class ControlVisionPlugin : VisionPlugin(), ElementVisionRenderer
TODO("Not yet implemented") TODO("Not yet implemented")
} }
override fun render(element: Element, client: VisionClient, name: Name, vision: Vision, meta: Meta) { override fun render(element: Element, name: Name, vision: Vision, meta: Meta) {
TODO("Not yet implemented") TODO("Not yet implemented")
} }

View File

@ -1,8 +1,8 @@
package space.kscience.controls.vision package space.kscience.controls.vision
import space.kscience.visionforge.html.runVisionClient
import space.kscience.visionforge.markup.MarkupPlugin import space.kscience.visionforge.markup.MarkupPlugin
import space.kscience.visionforge.plotly.PlotlyPlugin import space.kscience.visionforge.plotly.PlotlyPlugin
import space.kscience.visionforge.runVisionClient
public fun main(): Unit = runVisionClient { public fun main(): Unit = runVisionClient {
plugin(PlotlyPlugin) plugin(PlotlyPlugin)

View File

@ -24,7 +24,7 @@ dependencies {
implementation("io.ktor:ktor-client-cio:$ktorVersion") implementation("io.ktor:ktor-client-cio:$ktorVersion")
implementation("no.tornado:tornadofx:1.7.20") implementation("no.tornado:tornadofx:1.7.20")
implementation("space.kscience:plotlykt-server:0.6.1") implementation("space.kscience:plotlykt-server:0.7.1")
// implementation("com.github.Ricky12Awesome:json-schema-serialization:0.6.6") // implementation("com.github.Ricky12Awesome:json-schema-serialization:0.6.6")
implementation(spclibs.logback.classic) implementation(spclibs.logback.classic)
} }

View File

@ -7,9 +7,9 @@ import space.kscience.controls.spec.*
import space.kscience.dataforge.context.Context import space.kscience.dataforge.context.Context
import space.kscience.dataforge.context.Factory import space.kscience.dataforge.context.Factory
import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.MetaConverter
import space.kscience.dataforge.meta.ValueType import space.kscience.dataforge.meta.ValueType
import space.kscience.dataforge.meta.descriptors.value import space.kscience.dataforge.meta.descriptors.value
import space.kscience.dataforge.meta.transformations.MetaConverter
import java.time.Instant import java.time.Instant
import kotlin.math.cos import kotlin.math.cos
import kotlin.math.sin import kotlin.math.sin

View File

@ -22,7 +22,7 @@ class MagixVirtualCar(context: Context, meta: Meta) : VirtualCar(context, meta)
(payload as? PropertyChangedMessage)?.let { message -> (payload as? PropertyChangedMessage)?.let { message ->
if (message.sourceDevice == Name.parse("virtual-car")) { if (message.sourceDevice == Name.parse("virtual-car")) {
when (message.property) { when (message.property) {
"acceleration" -> write(IVirtualCar.acceleration, Vector2D.metaToObject(message.value)) "acceleration" -> write(IVirtualCar.acceleration, Vector2D.read(message.value))
} }
} }
} }

View File

@ -11,34 +11,26 @@ import space.kscience.controls.spec.doRecurring
import space.kscience.controls.spec.read import space.kscience.controls.spec.read
import space.kscience.dataforge.context.Context import space.kscience.dataforge.context.Context
import space.kscience.dataforge.context.Factory import space.kscience.dataforge.context.Factory
import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.*
import space.kscience.dataforge.meta.MetaRepr
import space.kscience.dataforge.meta.double
import space.kscience.dataforge.meta.get
import space.kscience.dataforge.meta.transformations.MetaConverter
import kotlin.math.pow import kotlin.math.pow
import kotlin.reflect.KType
import kotlin.reflect.typeOf
import kotlin.time.Duration import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.ExperimentalTime import kotlin.time.ExperimentalTime
data class Vector2D(var x: Double = 0.0, var y: Double = 0.0) : MetaRepr { data class Vector2D(var x: Double = 0.0, var y: Double = 0.0) : MetaRepr {
override fun toMeta(): Meta = objectToMeta(this) override fun toMeta(): Meta = convert(this)
operator fun div(arg: Double): Vector2D = Vector2D(x / arg, y / arg) operator fun div(arg: Double): Vector2D = Vector2D(x / arg, y / arg)
companion object CoordinatesMetaConverter : MetaConverter<Vector2D> { companion object CoordinatesMetaConverter : MetaConverter<Vector2D> {
override val type: KType = typeOf<Vector2D>() override fun readOrNull(source: Meta): Vector2D = Vector2D(
source["x"].double ?: 0.0,
override fun metaToObjectOrNull(meta: Meta): Vector2D = Vector2D( source["y"].double ?: 0.0
meta["x"].double ?: 0.0,
meta["y"].double ?: 0.0
) )
override fun objectToMeta(obj: Vector2D): Meta = Meta { override fun convert(obj: Vector2D): Meta = Meta {
"x" put obj.x "x" put obj.x
"y" put obj.y "y" put obj.y
} }

View File

@ -10,9 +10,9 @@ import space.kscience.dataforge.context.Context
import space.kscience.dataforge.context.Factory import space.kscience.dataforge.context.Factory
import space.kscience.dataforge.context.request import space.kscience.dataforge.context.request
import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.MetaConverter
import space.kscience.dataforge.meta.get import space.kscience.dataforge.meta.get
import space.kscience.dataforge.meta.int import space.kscience.dataforge.meta.int
import space.kscience.dataforge.meta.transformations.MetaConverter
//TODO this device is not tested //TODO this device is not tested
@ -94,7 +94,7 @@ class MksPdr900Device(context: Context, meta: Meta) : DeviceBySpec<MksPdr900Devi
val channel by logicalProperty(MetaConverter.int) val channel by logicalProperty(MetaConverter.int)
val value by doubleProperty(read = { val value by doubleProperty(read = {
readChannelData(request(channel) ?: DEFAULT_CHANNEL) readChannelData(getOrRead(channel))
}) })
val error by logicalProperty(MetaConverter.string) val error by logicalProperty(MetaConverter.string)

View File

@ -16,11 +16,7 @@ import space.kscience.controls.api.PropertyDescriptor
import space.kscience.controls.ports.* import space.kscience.controls.ports.*
import space.kscience.controls.spec.* import space.kscience.controls.spec.*
import space.kscience.dataforge.context.* import space.kscience.dataforge.context.*
import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.*
import space.kscience.dataforge.meta.asValue
import space.kscience.dataforge.meta.double
import space.kscience.dataforge.meta.get
import space.kscience.dataforge.meta.transformations.MetaConverter
import space.kscience.dataforge.names.NameToken import space.kscience.dataforge.names.NameToken
import kotlin.collections.component1 import kotlin.collections.component1
import kotlin.collections.component2 import kotlin.collections.component2