Refactoring properties getters
This commit is contained in:
parent
fe3958fd08
commit
596e3a0cfc
@ -29,21 +29,25 @@ public interface Device : Closeable, ContextAware, CoroutineScope {
|
|||||||
public val actionDescriptors: Collection<ActionDescriptor>
|
public val actionDescriptors: Collection<ActionDescriptor>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of the property or throw error if property in not defined.
|
* Read physical state of property and update/push notifications if needed.
|
||||||
* Suspend if property value is not available
|
|
||||||
*/
|
*/
|
||||||
public suspend fun getProperty(propertyName: String): MetaItem
|
public suspend fun readItem(propertyName: String): MetaItem
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invalidate property and force recalculate
|
* Get the logical state of property or return null if it is invalid
|
||||||
*/
|
*/
|
||||||
public suspend fun invalidateProperty(propertyName: String)
|
public fun getItem(propertyName: String): MetaItem?
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invalidate property (set logical state to invalid)
|
||||||
|
*/
|
||||||
|
public suspend fun invalidate(propertyName: String)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set property [value] for a property with name [propertyName].
|
* Set property [value] for a property with name [propertyName].
|
||||||
* In rare cases could suspend if the [Device] supports command queue and it is full at the moment.
|
* In rare cases could suspend if the [Device] supports command queue and it is full at the moment.
|
||||||
*/
|
*/
|
||||||
public suspend fun setProperty(propertyName: String, value: MetaItem)
|
public suspend fun writeItem(propertyName: String, value: MetaItem)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The [SharedFlow] of property changes
|
* The [SharedFlow] of property changes
|
||||||
@ -65,9 +69,19 @@ public interface Device : Closeable, ContextAware, CoroutineScope {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public suspend fun Device.getState(): Meta = Meta{
|
|
||||||
for(descriptor in propertyDescriptors) {
|
/**
|
||||||
descriptor.name put getProperty(descriptor.name)
|
* Get the logical state of property or suspend to read the physical value.
|
||||||
|
*/
|
||||||
|
public suspend fun Device.getOrReadItem(propertyName: String): MetaItem =
|
||||||
|
getItem(propertyName) ?: readItem(propertyName)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a snapshot of logical state of the device
|
||||||
|
*/
|
||||||
|
public fun Device.getProperties(): Meta = Meta {
|
||||||
|
for (descriptor in propertyDescriptors) {
|
||||||
|
descriptor.name put getItem(descriptor.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,11 +58,11 @@ public fun DeviceHub.getOrNull(nameString: String): Device? = getOrNull(nameStri
|
|||||||
public operator fun DeviceHub.get(nameString: String): Device =
|
public operator fun DeviceHub.get(nameString: String): Device =
|
||||||
getOrNull(nameString) ?: error("Device with name $nameString not found in $this")
|
getOrNull(nameString) ?: error("Device with name $nameString not found in $this")
|
||||||
|
|
||||||
public suspend fun DeviceHub.getProperty(deviceName: Name, propertyName: String): MetaItem =
|
public suspend fun DeviceHub.readItem(deviceName: Name, propertyName: String): MetaItem =
|
||||||
this[deviceName].getProperty(propertyName)
|
this[deviceName].readItem(propertyName)
|
||||||
|
|
||||||
public suspend fun DeviceHub.setProperty(deviceName: Name, propertyName: String, value: MetaItem) {
|
public suspend fun DeviceHub.writeItem(deviceName: Name, propertyName: String, value: MetaItem) {
|
||||||
this[deviceName].setProperty(propertyName, value)
|
this[deviceName].writeItem(propertyName, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
public suspend fun DeviceHub.execute(deviceName: Name, command: String, argument: MetaItem?): MetaItem? =
|
public suspend fun DeviceHub.execute(deviceName: Name, command: String, argument: MetaItem?): MetaItem? =
|
||||||
|
@ -152,14 +152,17 @@ public abstract class DeviceBase(final override val context: Context) : Device {
|
|||||||
_actions[name] = action
|
_actions[name] = action
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getProperty(propertyName: String): MetaItem =
|
override suspend fun readItem(propertyName: String): MetaItem =
|
||||||
(_properties[propertyName] ?: error("Property with name $propertyName not defined")).read()
|
(_properties[propertyName] ?: error("Property with name $propertyName not defined")).read()
|
||||||
|
|
||||||
override suspend fun invalidateProperty(propertyName: String) {
|
override fun getItem(propertyName: String): MetaItem?=
|
||||||
|
(_properties[propertyName] ?: error("Property with name $propertyName not defined")).value
|
||||||
|
|
||||||
|
override suspend fun invalidate(propertyName: String) {
|
||||||
(_properties[propertyName] ?: error("Property with name $propertyName not defined")).invalidate()
|
(_properties[propertyName] ?: error("Property with name $propertyName not defined")).invalidate()
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun setProperty(propertyName: String, value: MetaItem) {
|
override suspend fun writeItem(propertyName: String, value: MetaItem) {
|
||||||
(_properties[propertyName] as? DeviceProperty ?: error("Property with name $propertyName not defined")).write(
|
(_properties[propertyName] as? DeviceProperty ?: error("Property with name $propertyName not defined")).write(
|
||||||
value
|
value
|
||||||
)
|
)
|
||||||
|
@ -67,7 +67,7 @@ public class DeviceController(
|
|||||||
is PropertyGetMessage -> {
|
is PropertyGetMessage -> {
|
||||||
PropertyChangedMessage(
|
PropertyChangedMessage(
|
||||||
property = request.property,
|
property = request.property,
|
||||||
value = device.getProperty(request.property),
|
value = device.getOrReadItem(request.property),
|
||||||
sourceDevice = deviceTarget,
|
sourceDevice = deviceTarget,
|
||||||
targetDevice = request.sourceDevice
|
targetDevice = request.sourceDevice
|
||||||
)
|
)
|
||||||
@ -75,13 +75,13 @@ public class DeviceController(
|
|||||||
|
|
||||||
is PropertySetMessage -> {
|
is PropertySetMessage -> {
|
||||||
if (request.value == null) {
|
if (request.value == null) {
|
||||||
device.invalidateProperty(request.property)
|
device.invalidate(request.property)
|
||||||
} else {
|
} else {
|
||||||
device.setProperty(request.property, request.value)
|
device.writeItem(request.property, request.value)
|
||||||
}
|
}
|
||||||
PropertyChangedMessage(
|
PropertyChangedMessage(
|
||||||
property = request.property,
|
property = request.property,
|
||||||
value = device.getProperty(request.property),
|
value = device.getOrReadItem(request.property),
|
||||||
sourceDevice = deviceTarget,
|
sourceDevice = deviceTarget,
|
||||||
targetDevice = request.sourceDevice
|
targetDevice = request.sourceDevice
|
||||||
)
|
)
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
package ru.mipt.npm.controls.properties
|
package ru.mipt.npm.controls.properties
|
||||||
|
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.SupervisorJob
|
||||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
import kotlinx.coroutines.flow.SharedFlow
|
import kotlinx.coroutines.flow.SharedFlow
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import kotlinx.coroutines.sync.withLock
|
import kotlinx.coroutines.sync.withLock
|
||||||
import ru.mipt.npm.controls.api.ActionDescriptor
|
import ru.mipt.npm.controls.api.ActionDescriptor
|
||||||
@ -21,6 +23,7 @@ import kotlin.reflect.KProperty
|
|||||||
/**
|
/**
|
||||||
* @param D recursive self-type for properties and actions
|
* @param D recursive self-type for properties and actions
|
||||||
*/
|
*/
|
||||||
|
@OptIn(InternalDeviceAPI::class)
|
||||||
public open class DeviceBySpec<D : DeviceBySpec<D>>(
|
public open class DeviceBySpec<D : DeviceBySpec<D>>(
|
||||||
public val spec: DeviceSpec<D>,
|
public val spec: DeviceSpec<D>,
|
||||||
context: Context = Global,
|
context: Context = Global,
|
||||||
@ -55,11 +58,9 @@ public open class DeviceBySpec<D : DeviceBySpec<D>>(
|
|||||||
internal val self: D
|
internal val self: D
|
||||||
get() = this as D
|
get() = this as D
|
||||||
|
|
||||||
internal fun getLogicalState(propertyName: String): MetaItem? = logicalState[propertyName]
|
|
||||||
|
|
||||||
private val stateLock = Mutex()
|
private val stateLock = Mutex()
|
||||||
|
|
||||||
internal suspend fun updateLogical(propertyName: String, value: MetaItem?) {
|
private suspend fun updateLogical(propertyName: String, value: MetaItem?) {
|
||||||
if (value != logicalState[propertyName]) {
|
if (value != logicalState[propertyName]) {
|
||||||
stateLock.withLock {
|
stateLock.withLock {
|
||||||
logicalState[propertyName] = value
|
logicalState[propertyName] = value
|
||||||
@ -74,27 +75,26 @@ public open class DeviceBySpec<D : DeviceBySpec<D>>(
|
|||||||
* Force read physical value and push an update if it is changed. It does not matter if logical state is present.
|
* Force read physical value and push an update if it is changed. It does not matter if logical state is present.
|
||||||
* The logical state is updated after read
|
* The logical state is updated after read
|
||||||
*/
|
*/
|
||||||
public suspend fun readProperty(propertyName: String): MetaItem {
|
override suspend fun readItem(propertyName: String): MetaItem {
|
||||||
val newValue = properties[propertyName]?.readItem(self)
|
val newValue = properties[propertyName]?.readItem(self)
|
||||||
?: error("A property with name $propertyName is not registered in $this")
|
?: error("A property with name $propertyName is not registered in $this")
|
||||||
updateLogical(propertyName, newValue)
|
updateLogical(propertyName, newValue)
|
||||||
return newValue
|
return newValue
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getProperty(propertyName: String): MetaItem =
|
override fun getItem(propertyName: String): MetaItem? = logicalState[propertyName]
|
||||||
logicalState[propertyName] ?: readProperty(propertyName)
|
|
||||||
|
|
||||||
override suspend fun invalidateProperty(propertyName: String) {
|
override suspend fun invalidate(propertyName: String) {
|
||||||
stateLock.withLock {
|
stateLock.withLock {
|
||||||
logicalState.remove(propertyName)
|
logicalState.remove(propertyName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun setProperty(propertyName: String, value: MetaItem): Unit {
|
override suspend fun writeItem(propertyName: String, value: MetaItem): Unit {
|
||||||
//If there is a physical property with given name, invalidate logical property and write physical one
|
//If there is a physical property with given name, invalidate logical property and write physical one
|
||||||
(properties[propertyName] as? WritableDevicePropertySpec<D, out Any>)?.let {
|
(properties[propertyName] as? WritableDevicePropertySpec<D, out Any>)?.let {
|
||||||
it.writeItem(self, value)
|
it.writeItem(self, value)
|
||||||
invalidateProperty(propertyName)
|
invalidate(propertyName)
|
||||||
} ?: run {
|
} ?: run {
|
||||||
updateLogical(propertyName, value)
|
updateLogical(propertyName, value)
|
||||||
}
|
}
|
||||||
@ -113,36 +113,44 @@ public open class DeviceBySpec<D : DeviceBySpec<D>>(
|
|||||||
): ReadWriteProperty<D, T> = observable(initialValue) { property: KProperty<*>, oldValue: T, newValue: T ->
|
): ReadWriteProperty<D, T> = observable(initialValue) { property: KProperty<*>, oldValue: T, newValue: T ->
|
||||||
if (oldValue != newValue) {
|
if (oldValue != newValue) {
|
||||||
launch {
|
launch {
|
||||||
invalidateProperty(property.name)
|
invalidate(property.name)
|
||||||
_propertyFlow.emit(property.name to converter.objectToMetaItem(newValue))
|
_propertyFlow.emit(property.name to converter.objectToMetaItem(newValue))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public suspend fun <T : Any> DevicePropertySpec<D, T>.read(): T = read(self)
|
/**
|
||||||
|
* Read typed value and update/push event if needed
|
||||||
|
*/
|
||||||
|
public suspend fun <T : Any> DevicePropertySpec<D, T>.read(): T {
|
||||||
|
val res = read(self)
|
||||||
|
updateLogical(name, converter.objectToMetaItem(res))
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun <T : Any> DevicePropertySpec<D, T>.get(): T? = getItem(name)?.let(converter::itemToObject)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write typed property state and invalidate logical state
|
||||||
|
*/
|
||||||
|
public suspend fun <T : Any> WritableDevicePropertySpec<D, T>.write(value: T) {
|
||||||
|
write(self, value)
|
||||||
|
invalidate(name)
|
||||||
|
}
|
||||||
|
|
||||||
override fun close() {
|
override fun close() {
|
||||||
with(spec){ self.onShutdown() }
|
with(spec) { self.onShutdown() }
|
||||||
super.close()
|
super.close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public suspend fun <D : DeviceBySpec<D>, T : Any> D.getSuspend(
|
public suspend fun <D : DeviceBySpec<D>, T : Any> D.read(
|
||||||
propertySpec: DevicePropertySpec<D, T>
|
propertySpec: DevicePropertySpec<D, T>
|
||||||
): T = propertySpec.read(this@getSuspend).also {
|
): T = propertySpec.read()
|
||||||
updateLogical(propertySpec.name, propertySpec.converter.objectToMetaItem(it))
|
|
||||||
|
public fun <D : DeviceBySpec<D>, T : Any> D.write(
|
||||||
|
propertySpec: WritableDevicePropertySpec<D, T>,
|
||||||
|
value: T
|
||||||
|
): Job = launch {
|
||||||
|
propertySpec.write(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public fun <D : DeviceBySpec<D>, T : Any> D.getAsync(
|
|
||||||
propertySpec: DevicePropertySpec<D, T>
|
|
||||||
): Deferred<T> = async {
|
|
||||||
getSuspend(propertySpec)
|
|
||||||
}
|
|
||||||
|
|
||||||
public operator fun <D : DeviceBySpec<D>, T : Any> D.set(propertySpec: WritableDevicePropertySpec<D, T>, value: T) {
|
|
||||||
launch {
|
|
||||||
propertySpec.write(this@set, value)
|
|
||||||
invalidateProperty(propertySpec.name)
|
|
||||||
}
|
|
||||||
}
|
|
@ -8,6 +8,13 @@ import space.kscience.dataforge.meta.transformations.MetaConverter
|
|||||||
import space.kscience.dataforge.meta.transformations.nullableItemToObject
|
import space.kscience.dataforge.meta.transformations.nullableItemToObject
|
||||||
import space.kscience.dataforge.meta.transformations.nullableObjectToMetaItem
|
import space.kscience.dataforge.meta.transformations.nullableObjectToMetaItem
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This API is internal and should not be used in user code
|
||||||
|
*/
|
||||||
|
@RequiresOptIn
|
||||||
|
public annotation class InternalDeviceAPI
|
||||||
|
|
||||||
//TODO relax T restriction after DF 0.4.4
|
//TODO relax T restriction after DF 0.4.4
|
||||||
public interface DevicePropertySpec<in D : Device, T : Any> {
|
public interface DevicePropertySpec<in D : Device, T : Any> {
|
||||||
/**
|
/**
|
||||||
@ -28,9 +35,11 @@ public interface DevicePropertySpec<in D : Device, T : Any> {
|
|||||||
/**
|
/**
|
||||||
* Read physical value from the given [device]
|
* Read physical value from the given [device]
|
||||||
*/
|
*/
|
||||||
|
@InternalDeviceAPI
|
||||||
public suspend fun read(device: D): T
|
public suspend fun read(device: D): T
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(InternalDeviceAPI::class)
|
||||||
public suspend fun <D : Device, T : Any> DevicePropertySpec<D, T>.readItem(device: D): MetaItem =
|
public suspend fun <D : Device, T : Any> DevicePropertySpec<D, T>.readItem(device: D): MetaItem =
|
||||||
converter.objectToMetaItem(read(device))
|
converter.objectToMetaItem(read(device))
|
||||||
|
|
||||||
@ -39,9 +48,11 @@ public interface WritableDevicePropertySpec<in D : Device, T : Any> : DeviceProp
|
|||||||
/**
|
/**
|
||||||
* Write physical value to a device
|
* Write physical value to a device
|
||||||
*/
|
*/
|
||||||
|
@InternalDeviceAPI
|
||||||
public suspend fun write(device: D, value: T)
|
public suspend fun write(device: D, value: T)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(InternalDeviceAPI::class)
|
||||||
public suspend fun <D : Device, T : Any> WritableDevicePropertySpec<D, T>.writeItem(device: D, item: MetaItem) {
|
public suspend fun <D : Device, T : Any> WritableDevicePropertySpec<D, T>.writeItem(device: D, item: MetaItem) {
|
||||||
write(device, converter.itemToObject(item))
|
write(device, converter.itemToObject(item))
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ import kotlin.reflect.KMutableProperty1
|
|||||||
import kotlin.reflect.KProperty
|
import kotlin.reflect.KProperty
|
||||||
import kotlin.reflect.KProperty1
|
import kotlin.reflect.KProperty1
|
||||||
|
|
||||||
|
@OptIn(InternalDeviceAPI::class)
|
||||||
public abstract class DeviceSpec<D : DeviceBySpec<D>>(
|
public abstract class DeviceSpec<D : DeviceBySpec<D>>(
|
||||||
private val buildDevice: () -> D
|
private val buildDevice: () -> D
|
||||||
) : Factory<D> {
|
) : Factory<D> {
|
||||||
|
@ -0,0 +1,32 @@
|
|||||||
|
package ru.mipt.npm.controls.properties
|
||||||
|
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.flow
|
||||||
|
import kotlinx.coroutines.isActive
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlin.time.Duration
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform a recurring asynchronous read action and return a flow of results.
|
||||||
|
* The flow is lazy so action is not performed unless flow is consumed.
|
||||||
|
* The flow uses called context. In order to call it on device context, use `flowOn(coroutineContext)`.
|
||||||
|
*
|
||||||
|
* The flow is canceled when the device scope is canceled
|
||||||
|
*/
|
||||||
|
public fun <D : DeviceBySpec<D>, R> D.readRecurring(interval: Duration, reader: suspend D.() -> R): Flow<R> = flow {
|
||||||
|
while (isActive) {
|
||||||
|
kotlinx.coroutines.delay(interval)
|
||||||
|
emit(reader())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Do a recurring task on a device. The task could
|
||||||
|
*/
|
||||||
|
public fun <D : DeviceBySpec<D>> D.doRecurring(interval: Duration, task: suspend D.() -> Unit): Job = launch {
|
||||||
|
while (isActive) {
|
||||||
|
kotlinx.coroutines.delay(interval)
|
||||||
|
task()
|
||||||
|
}
|
||||||
|
}
|
@ -1,13 +1,10 @@
|
|||||||
package ru.mipt.npm.controls.properties
|
package ru.mipt.npm.controls.properties
|
||||||
|
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import ru.mipt.npm.controls.api.PropertyDescriptor
|
|
||||||
import space.kscience.dataforge.meta.transformations.MetaConverter
|
|
||||||
import kotlin.reflect.KFunction
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Blocking property get call
|
* Blocking property get call
|
||||||
*/
|
*/
|
||||||
public operator fun <D : DeviceBySpec<D>, T : Any> D.get(
|
public operator fun <D : DeviceBySpec<D>, T : Any> D.get(
|
||||||
propertySpec: DevicePropertySpec<D, T>
|
propertySpec: DevicePropertySpec<D, T>
|
||||||
): T = runBlocking { getAsync(propertySpec).await() }
|
): T = runBlocking { read(propertySpec) }
|
@ -6,6 +6,7 @@ import kotlinx.coroutines.flow.onEach
|
|||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import ru.mipt.npm.controls.api.get
|
import ru.mipt.npm.controls.api.get
|
||||||
|
import ru.mipt.npm.controls.api.getOrReadItem
|
||||||
import ru.mipt.npm.controls.controllers.DeviceManager
|
import ru.mipt.npm.controls.controllers.DeviceManager
|
||||||
import ru.mipt.npm.magix.api.MagixEndpoint
|
import ru.mipt.npm.magix.api.MagixEndpoint
|
||||||
import ru.mipt.npm.magix.api.MagixMessage
|
import ru.mipt.npm.magix.api.MagixMessage
|
||||||
@ -83,7 +84,7 @@ public fun DeviceManager.launchTangoMagix(
|
|||||||
val device = get(request.payload.device)
|
val device = get(request.payload.device)
|
||||||
when (request.payload.action) {
|
when (request.payload.action) {
|
||||||
TangoAction.read -> {
|
TangoAction.read -> {
|
||||||
val value = device.getProperty(request.payload.name)
|
val value = device.getOrReadItem(request.payload.name)
|
||||||
respond(request) { requestPayload ->
|
respond(request) { requestPayload ->
|
||||||
requestPayload.copy(
|
requestPayload.copy(
|
||||||
value = value,
|
value = value,
|
||||||
@ -93,10 +94,10 @@ public fun DeviceManager.launchTangoMagix(
|
|||||||
}
|
}
|
||||||
TangoAction.write -> {
|
TangoAction.write -> {
|
||||||
request.payload.value?.let { value ->
|
request.payload.value?.let { value ->
|
||||||
device.setProperty(request.payload.name, value)
|
device.writeItem(request.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.getProperty(request.payload.name)
|
val value = device.getOrReadItem(request.payload.name)
|
||||||
respond(request) { requestPayload ->
|
respond(request) { requestPayload ->
|
||||||
requestPayload.copy(
|
requestPayload.copy(
|
||||||
value = value,
|
value = value,
|
||||||
|
@ -1,17 +1,16 @@
|
|||||||
package ru.mipt.npm.controls.demo
|
package ru.mipt.npm.controls.demo
|
||||||
|
|
||||||
import kotlinx.coroutines.delay
|
|
||||||
import kotlinx.coroutines.isActive
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import ru.mipt.npm.controls.properties.*
|
import ru.mipt.npm.controls.properties.*
|
||||||
import space.kscience.dataforge.meta.Meta
|
import space.kscience.dataforge.meta.Meta
|
||||||
import space.kscience.dataforge.meta.transformations.MetaConverter
|
import space.kscience.dataforge.meta.transformations.MetaConverter
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
|
import kotlin.time.Duration
|
||||||
|
import kotlin.time.ExperimentalTime
|
||||||
|
|
||||||
|
|
||||||
class DemoDevice : DeviceBySpec<DemoDevice>(DemoDevice) {
|
class DemoDevice : DeviceBySpec<DemoDevice>(DemoDevice) {
|
||||||
var timeScale by state(5000.0)
|
var timeScale by state(5000.0)
|
||||||
var sinScale by state( 1.0)
|
var sinScale by state(1.0)
|
||||||
var cosScale by state(1.0)
|
var cosScale by state(1.0)
|
||||||
|
|
||||||
companion object : DeviceSpec<DemoDevice>(::DemoDevice) {
|
companion object : DeviceSpec<DemoDevice>(::DemoDevice) {
|
||||||
@ -34,8 +33,8 @@ class DemoDevice : DeviceBySpec<DemoDevice>(DemoDevice) {
|
|||||||
Meta {
|
Meta {
|
||||||
val time = Instant.now()
|
val time = Instant.now()
|
||||||
"time" put time.toEpochMilli()
|
"time" put time.toEpochMilli()
|
||||||
"x" put getSuspend(sin)
|
"x" put read(sin)
|
||||||
"y" put getSuspend(cos)
|
"y" put read(cos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,13 +45,11 @@ class DemoDevice : DeviceBySpec<DemoDevice>(DemoDevice) {
|
|||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalTime::class)
|
||||||
override fun DemoDevice.onStartup() {
|
override fun DemoDevice.onStartup() {
|
||||||
launch {
|
doRecurring(Duration.milliseconds(50)){
|
||||||
while(isActive){
|
sin.read()
|
||||||
delay(50)
|
cos.read()
|
||||||
sin.read()
|
|
||||||
cos.read()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user