[WIP] Refactor constructor
This commit is contained in:
parent
a9592d0372
commit
5921978122
10
README.md
10
README.md
@ -104,6 +104,11 @@ Automatically checks consistency.
|
|||||||
>
|
>
|
||||||
> **Maturity**: EXPERIMENTAL
|
> **Maturity**: EXPERIMENTAL
|
||||||
|
|
||||||
|
### [controls-plc4x](controls-plc4x)
|
||||||
|
> A plugin for Controls-kt device server on top of plc4x library
|
||||||
|
>
|
||||||
|
> **Maturity**: EXPERIMENTAL
|
||||||
|
|
||||||
### [controls-ports-ktor](controls-ports-ktor)
|
### [controls-ports-ktor](controls-ports-ktor)
|
||||||
> Implementation of byte ports on top os ktor-io asynchronous API
|
> Implementation of byte ports on top os ktor-io asynchronous API
|
||||||
>
|
>
|
||||||
@ -209,6 +214,11 @@ Automatically checks consistency.
|
|||||||
>
|
>
|
||||||
> **Maturity**: PROTOTYPE
|
> **Maturity**: PROTOTYPE
|
||||||
|
|
||||||
|
### [magix/magix-utils](magix/magix-utils)
|
||||||
|
> Common utilities and services for Magix endpoints.
|
||||||
|
>
|
||||||
|
> **Maturity**: EXPERIMENTAL
|
||||||
|
|
||||||
### [magix/magix-zmq](magix/magix-zmq)
|
### [magix/magix-zmq](magix/magix-zmq)
|
||||||
> ZMQ client endpoint for Magix
|
> ZMQ client endpoint for Magix
|
||||||
>
|
>
|
||||||
|
@ -6,7 +6,7 @@ A low-code constructor for composite devices simulation
|
|||||||
|
|
||||||
## Artifact:
|
## Artifact:
|
||||||
|
|
||||||
The Maven coordinates of this project are `space.kscience:controls-constructor:0.3.0`.
|
The Maven coordinates of this project are `space.kscience:controls-constructor:0.4.0-dev-1`.
|
||||||
|
|
||||||
**Gradle Kotlin DSL:**
|
**Gradle Kotlin DSL:**
|
||||||
```kotlin
|
```kotlin
|
||||||
@ -16,6 +16,6 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("space.kscience:controls-constructor:0.3.0")
|
implementation("space.kscience:controls-constructor:0.4.0-dev-1")
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -2,7 +2,10 @@ package space.kscience.controls.constructor
|
|||||||
|
|
||||||
import space.kscience.controls.api.Device
|
import space.kscience.controls.api.Device
|
||||||
|
|
||||||
public sealed interface ConstructorBinding
|
/**
|
||||||
|
* A binding that is used to describe device functionality
|
||||||
|
*/
|
||||||
|
public sealed interface Binding
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A binding that exposes device property as read-only state
|
* A binding that exposes device property as read-only state
|
||||||
@ -11,16 +14,22 @@ public class PropertyBinding<T>(
|
|||||||
public val device: Device,
|
public val device: Device,
|
||||||
public val propertyName: String,
|
public val propertyName: String,
|
||||||
public val state: DeviceState<T>,
|
public val state: DeviceState<T>,
|
||||||
) : ConstructorBinding
|
) : Binding
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A binding for independent state like a timer
|
* A binding for independent state like a timer
|
||||||
*/
|
*/
|
||||||
public class StateBinding<T>(
|
public class StateBinding<T>(
|
||||||
public val state: DeviceState<T>
|
public val state: DeviceState<T>
|
||||||
) : ConstructorBinding
|
) : Binding
|
||||||
|
|
||||||
public class ActionBinding(
|
public class ActionBinding(
|
||||||
public val reads: Collection<DeviceState<*>>,
|
public val reads: Collection<DeviceState<*>>,
|
||||||
public val writes: Collection<DeviceState<*>>
|
public val writes: Collection<DeviceState<*>>
|
||||||
): ConstructorBinding
|
): Binding
|
||||||
|
|
||||||
|
|
||||||
|
public interface BindingsContainer{
|
||||||
|
public val bindings: List<Binding>
|
||||||
|
public fun registerBinding(binding: Binding)
|
||||||
|
}
|
@ -26,11 +26,11 @@ import kotlin.time.Duration
|
|||||||
public abstract class DeviceConstructor(
|
public abstract class DeviceConstructor(
|
||||||
context: Context,
|
context: Context,
|
||||||
meta: Meta = Meta.EMPTY,
|
meta: Meta = Meta.EMPTY,
|
||||||
) : DeviceGroup(context, meta) {
|
) : DeviceGroup(context, meta), BindingsContainer {
|
||||||
private val _bindings: MutableList<ConstructorBinding> = mutableListOf()
|
private val _bindings: MutableList<Binding> = mutableListOf()
|
||||||
public val bindings: List<ConstructorBinding> get() = _bindings
|
override val bindings: List<Binding> get() = _bindings
|
||||||
|
|
||||||
public fun registerBinding(binding: ConstructorBinding) {
|
override fun registerBinding(binding: Binding) {
|
||||||
_bindings.add(binding)
|
_bindings.add(binding)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,7 +46,7 @@ public abstract class DeviceConstructor(
|
|||||||
.also { registerBinding(StateBinding(it)) }
|
.also { registerBinding(StateBinding(it)) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Launch action that is performed on each [DeviceState] value change.
|
* Bind an action to a [DeviceState]. [onChange] block is performed on each state change
|
||||||
*
|
*
|
||||||
* Optionally provide [writes] - a set of states that this change affects.
|
* Optionally provide [writes] - a set of states that this change affects.
|
||||||
*/
|
*/
|
||||||
|
@ -0,0 +1,12 @@
|
|||||||
|
package space.kscience.controls.constructor
|
||||||
|
|
||||||
|
public abstract class DeviceModel : BindingsContainer {
|
||||||
|
|
||||||
|
private val _bindings: MutableList<Binding> = mutableListOf()
|
||||||
|
|
||||||
|
override val bindings: List<Binding> get() = _bindings
|
||||||
|
|
||||||
|
override fun registerBinding(binding: Binding) {
|
||||||
|
_bindings.add(binding)
|
||||||
|
}
|
||||||
|
}
|
@ -63,25 +63,25 @@ public interface DeviceStateWithDependencies<T> : DeviceState<T> {
|
|||||||
/**
|
/**
|
||||||
* Create a new read-only [DeviceState] that mirrors receiver state by mapping the value with [mapper].
|
* Create a new read-only [DeviceState] that mirrors receiver state by mapping the value with [mapper].
|
||||||
*/
|
*/
|
||||||
public fun <T, R> DeviceState<T>.map(
|
public fun <T, R> DeviceState.Companion.map(
|
||||||
|
state: DeviceState<T>,
|
||||||
converter: MetaConverter<R>, mapper: (T) -> R,
|
converter: MetaConverter<R>, mapper: (T) -> R,
|
||||||
): DeviceStateWithDependencies<R> = object : DeviceStateWithDependencies<R> {
|
): DeviceStateWithDependencies<R> = object : DeviceStateWithDependencies<R> {
|
||||||
override val dependencies = listOf(this)
|
override val dependencies = listOf(state)
|
||||||
|
|
||||||
override val converter: MetaConverter<R> = converter
|
override val converter: MetaConverter<R> = converter
|
||||||
|
|
||||||
override val value: R
|
override val value: R get() = mapper(state.value)
|
||||||
get() = mapper(this@map.value)
|
|
||||||
|
|
||||||
override val valueFlow: Flow<R> = this@map.valueFlow.map(mapper)
|
override val valueFlow: Flow<R> = state.valueFlow.map(mapper)
|
||||||
|
|
||||||
override fun toString(): String = "DeviceState.map(arg=${this@map}, converter=$converter)"
|
override fun toString(): String = "DeviceState.map(arg=${state}, converter=$converter)"
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Combine two device states into one read-only [DeviceState]. Only the latest value of each state is used.
|
* Combine two device states into one read-only [DeviceState]. Only the latest value of each state is used.
|
||||||
*/
|
*/
|
||||||
public fun <T1, T2, R> combine(
|
public fun <T1, T2, R> DeviceState.Companion.combine(
|
||||||
state1: DeviceState<T1>,
|
state1: DeviceState<T1>,
|
||||||
state2: DeviceState<T2>,
|
state2: DeviceState<T2>,
|
||||||
converter: MetaConverter<R>,
|
converter: MetaConverter<R>,
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package space.kscience.controls.constructor
|
package space.kscience.controls.constructor
|
||||||
|
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.isActive
|
import kotlinx.coroutines.isActive
|
||||||
@ -26,9 +27,9 @@ public class TimerState(
|
|||||||
|
|
||||||
private val clock = MutableStateFlow(clockManager.clock.now())
|
private val clock = MutableStateFlow(clockManager.clock.now())
|
||||||
|
|
||||||
private val updateJob = clockManager.context.launch {
|
private val updateJob = clockManager.context.launch(clockManager.asDispatcher()) {
|
||||||
while (isActive) {
|
while (isActive) {
|
||||||
clockManager.delay(tick)
|
delay(tick)
|
||||||
clock.value = clockManager.clock.now()
|
clock.value = clockManager.clock.now()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ import space.kscience.dataforge.meta.MetaConverter
|
|||||||
/**
|
/**
|
||||||
* A state describing a [Double] value in the [range]
|
* A state describing a [Double] value in the [range]
|
||||||
*/
|
*/
|
||||||
public class DoubleRangeState(
|
public class DoubleInRangeState(
|
||||||
initialValue: Double,
|
initialValue: Double,
|
||||||
public val range: ClosedFloatingPointRange<Double>,
|
public val range: ClosedFloatingPointRange<Double>,
|
||||||
) : MutableDeviceState<Double> {
|
) : MutableDeviceState<Double> {
|
||||||
@ -32,20 +32,28 @@ public class DoubleRangeState(
|
|||||||
/**
|
/**
|
||||||
* A state showing that the range is on its lower boundary
|
* A state showing that the range is on its lower boundary
|
||||||
*/
|
*/
|
||||||
public val atStartState: DeviceState<Boolean> = map(MetaConverter.boolean) { it <= range.start }
|
public val atStart: DeviceState<Boolean> = DeviceState.map(this, MetaConverter.boolean) {
|
||||||
|
it <= range.start
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A state showing that the range is on its higher boundary
|
* A state showing that the range is on its higher boundary
|
||||||
*/
|
*/
|
||||||
public val atEndState: DeviceState<Boolean> = map(MetaConverter.boolean) { it >= range.endInclusive }
|
public val atEnd: DeviceState<Boolean> = DeviceState.map(this, MetaConverter.boolean) {
|
||||||
|
it >= range.endInclusive
|
||||||
|
}
|
||||||
|
|
||||||
override fun toString(): String = "DoubleRangeState(range=$range, converter=$converter)"
|
override fun toString(): String = "DoubleRangeState(range=$range, converter=$converter)"
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("UnusedReceiverParameter")
|
/**
|
||||||
public fun DeviceGroup.rangeState(
|
* Create and register a [DoubleInRangeState]
|
||||||
|
*/
|
||||||
|
public fun BindingsContainer.doubleInRangeState(
|
||||||
initialValue: Double,
|
initialValue: Double,
|
||||||
range: ClosedFloatingPointRange<Double>,
|
range: ClosedFloatingPointRange<Double>,
|
||||||
): DoubleRangeState = DoubleRangeState(initialValue, range)
|
): DoubleInRangeState = DoubleInRangeState(initialValue, range).also {
|
||||||
|
registerBinding(StateBinding(it))
|
||||||
|
}
|
@ -25,8 +25,6 @@ private class VirtualDeviceState<T>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun toString(): String = "VirtualDeviceState(converter=$converter)"
|
override fun toString(): String = "VirtualDeviceState(converter=$converter)"
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ Core interfaces for building a device server
|
|||||||
|
|
||||||
## Artifact:
|
## Artifact:
|
||||||
|
|
||||||
The Maven coordinates of this project are `space.kscience:controls-core:0.3.0`.
|
The Maven coordinates of this project are `space.kscience:controls-core:0.4.0-dev-1`.
|
||||||
|
|
||||||
**Gradle Kotlin DSL:**
|
**Gradle Kotlin DSL:**
|
||||||
```kotlin
|
```kotlin
|
||||||
@ -26,6 +26,6 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("space.kscience:controls-core:0.3.0")
|
implementation("space.kscience:controls-core:0.4.0-dev-1")
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -1,24 +1,80 @@
|
|||||||
package space.kscience.controls.manager
|
package space.kscience.controls.manager
|
||||||
|
|
||||||
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.datetime.Clock
|
import kotlinx.datetime.Clock
|
||||||
import space.kscience.dataforge.context.AbstractPlugin
|
import kotlinx.datetime.Instant
|
||||||
import space.kscience.dataforge.context.Context
|
import space.kscience.controls.api.Device
|
||||||
import space.kscience.dataforge.context.PluginFactory
|
import space.kscience.dataforge.context.*
|
||||||
import space.kscience.dataforge.context.PluginTag
|
|
||||||
import space.kscience.dataforge.meta.Meta
|
import space.kscience.dataforge.meta.Meta
|
||||||
import kotlin.time.Duration
|
import space.kscience.dataforge.meta.double
|
||||||
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
import kotlin.math.roundToLong
|
||||||
|
|
||||||
|
@OptIn(InternalCoroutinesApi::class)
|
||||||
|
private class CompressedTimeDispatcher(
|
||||||
|
val dispatcher: CoroutineDispatcher,
|
||||||
|
val compression: Double,
|
||||||
|
) : CoroutineDispatcher(), Delay {
|
||||||
|
|
||||||
|
@InternalCoroutinesApi
|
||||||
|
override fun dispatchYield(context: CoroutineContext, block: Runnable) {
|
||||||
|
dispatcher.dispatchYield(context, block)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isDispatchNeeded(context: CoroutineContext): Boolean = dispatcher.isDispatchNeeded(context)
|
||||||
|
|
||||||
|
@ExperimentalCoroutinesApi
|
||||||
|
override fun limitedParallelism(parallelism: Int): CoroutineDispatcher = dispatcher.limitedParallelism(parallelism)
|
||||||
|
|
||||||
|
override fun dispatch(context: CoroutineContext, block: Runnable) {
|
||||||
|
dispatcher.dispatch(context, block)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val delay = ((dispatcher as? Delay) ?: (Dispatchers.Default as Delay))
|
||||||
|
|
||||||
|
override fun scheduleResumeAfterDelay(timeMillis: Long, continuation: CancellableContinuation<Unit>) {
|
||||||
|
delay.scheduleResumeAfterDelay((timeMillis / compression).roundToLong(), continuation)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun invokeOnTimeout(timeMillis: Long, block: Runnable, context: CoroutineContext): DisposableHandle {
|
||||||
|
return delay.invokeOnTimeout((timeMillis / compression).roundToLong(), block, context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class CompressedClock(
|
||||||
|
val start: Instant,
|
||||||
|
val compression: Double,
|
||||||
|
val baseClock: Clock = Clock.System,
|
||||||
|
) : Clock {
|
||||||
|
override fun now(): Instant {
|
||||||
|
val elapsed = (baseClock.now() - start)
|
||||||
|
return start + elapsed / compression
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public class ClockManager : AbstractPlugin() {
|
public class ClockManager : AbstractPlugin() {
|
||||||
override val tag: PluginTag get() = Companion.tag
|
override val tag: PluginTag get() = Companion.tag
|
||||||
|
|
||||||
|
public val timeCompression: Double by meta.double(1.0)
|
||||||
|
|
||||||
public val clock: Clock by lazy {
|
public val clock: Clock by lazy {
|
||||||
//TODO add clock customization
|
if (timeCompression == 1.0) {
|
||||||
Clock.System
|
Clock.System
|
||||||
|
} else {
|
||||||
|
CompressedClock(Clock.System.now(), timeCompression)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public suspend fun delay(duration: Duration) {
|
/**
|
||||||
//TODO add time compression
|
* Provide a [CoroutineDispatcher] with compressed time based on given [dispatcher]
|
||||||
kotlinx.coroutines.delay(duration)
|
*/
|
||||||
|
public fun asDispatcher(
|
||||||
|
dispatcher: CoroutineDispatcher = Dispatchers.Default,
|
||||||
|
): CoroutineDispatcher = if (timeCompression == 1.0) {
|
||||||
|
dispatcher
|
||||||
|
} else {
|
||||||
|
CompressedTimeDispatcher(dispatcher, timeCompression)
|
||||||
}
|
}
|
||||||
|
|
||||||
public companion object : PluginFactory<ClockManager> {
|
public companion object : PluginFactory<ClockManager> {
|
||||||
@ -29,3 +85,15 @@ public class ClockManager : AbstractPlugin() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public val Context.clock: Clock get() = plugins[ClockManager]?.clock ?: Clock.System
|
public val Context.clock: Clock get() = plugins[ClockManager]?.clock ?: Clock.System
|
||||||
|
|
||||||
|
public val Device.clock: Clock get() = context.clock
|
||||||
|
|
||||||
|
public fun Device.getCoroutineDispatcher(dispatcher: CoroutineDispatcher = Dispatchers.Default): CoroutineDispatcher =
|
||||||
|
context.plugins[ClockManager]?.asDispatcher(dispatcher) ?: dispatcher
|
||||||
|
|
||||||
|
public fun ContextBuilder.withTimeCompression(compression: Double) {
|
||||||
|
require(compression > 0.0) { "Time compression must be greater than zero." }
|
||||||
|
plugin(ClockManager) {
|
||||||
|
"timeCompression" put compression
|
||||||
|
}
|
||||||
|
}
|
@ -4,6 +4,7 @@ import kotlinx.coroutines.*
|
|||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.flow
|
import kotlinx.coroutines.flow.flow
|
||||||
import space.kscience.controls.api.Device
|
import space.kscience.controls.api.Device
|
||||||
|
import space.kscience.controls.manager.getCoroutineDispatcher
|
||||||
import kotlin.time.Duration
|
import kotlin.time.Duration
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -15,11 +16,12 @@ public fun <D : Device> D.doRecurring(
|
|||||||
task: suspend D.() -> Unit,
|
task: suspend D.() -> Unit,
|
||||||
): Job {
|
): Job {
|
||||||
val taskName = debugTaskName ?: "task[${task.hashCode().toString(16)}]"
|
val taskName = debugTaskName ?: "task[${task.hashCode().toString(16)}]"
|
||||||
return launch(CoroutineName(taskName)) {
|
val dispatcher = getCoroutineDispatcher()
|
||||||
|
return launch(CoroutineName(taskName) + dispatcher) {
|
||||||
while (isActive) {
|
while (isActive) {
|
||||||
delay(interval)
|
delay(interval)
|
||||||
//launch in parent scope to properly evaluate exceptions
|
//launch in parent scope to properly evaluate exceptions
|
||||||
this@doRecurring.launch {
|
this@doRecurring.launch(CoroutineName("$taskName-recurring") + dispatcher) {
|
||||||
task()
|
task()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
## Artifact:
|
## Artifact:
|
||||||
|
|
||||||
The Maven coordinates of this project are `space.kscience:controls-jupyter:0.3.0`.
|
The Maven coordinates of this project are `space.kscience:controls-jupyter:0.4.0-dev-1`.
|
||||||
|
|
||||||
**Gradle Kotlin DSL:**
|
**Gradle Kotlin DSL:**
|
||||||
```kotlin
|
```kotlin
|
||||||
@ -16,6 +16,6 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("space.kscience:controls-jupyter:0.3.0")
|
implementation("space.kscience:controls-jupyter:0.4.0-dev-1")
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -12,7 +12,7 @@ Magix service for binding controls devices (both as RPC client and server)
|
|||||||
|
|
||||||
## Artifact:
|
## Artifact:
|
||||||
|
|
||||||
The Maven coordinates of this project are `space.kscience:controls-magix:0.3.0`.
|
The Maven coordinates of this project are `space.kscience:controls-magix:0.4.0-dev-1`.
|
||||||
|
|
||||||
**Gradle Kotlin DSL:**
|
**Gradle Kotlin DSL:**
|
||||||
```kotlin
|
```kotlin
|
||||||
@ -22,6 +22,6 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("space.kscience:controls-magix:0.3.0")
|
implementation("space.kscience:controls-magix:0.4.0-dev-1")
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -12,7 +12,8 @@ description = """
|
|||||||
kscience {
|
kscience {
|
||||||
jvm()
|
jvm()
|
||||||
js()
|
js()
|
||||||
useCoroutines("1.8.0")
|
native()
|
||||||
|
useCoroutines()
|
||||||
useSerialization {
|
useSerialization {
|
||||||
json()
|
json()
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ Automatically checks consistency.
|
|||||||
|
|
||||||
## Artifact:
|
## Artifact:
|
||||||
|
|
||||||
The Maven coordinates of this project are `space.kscience:controls-modbus:0.3.0`.
|
The Maven coordinates of this project are `space.kscience:controls-modbus:0.4.0-dev-1`.
|
||||||
|
|
||||||
**Gradle Kotlin DSL:**
|
**Gradle Kotlin DSL:**
|
||||||
```kotlin
|
```kotlin
|
||||||
@ -24,6 +24,6 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("space.kscience:controls-modbus:0.3.0")
|
implementation("space.kscience:controls-modbus:0.4.0-dev-1")
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -12,7 +12,7 @@ A client and server connectors for OPC-UA via Eclipse Milo
|
|||||||
|
|
||||||
## Artifact:
|
## Artifact:
|
||||||
|
|
||||||
The Maven coordinates of this project are `space.kscience:controls-opcua:0.3.0`.
|
The Maven coordinates of this project are `space.kscience:controls-opcua:0.4.0-dev-1`.
|
||||||
|
|
||||||
**Gradle Kotlin DSL:**
|
**Gradle Kotlin DSL:**
|
||||||
```kotlin
|
```kotlin
|
||||||
@ -22,6 +22,6 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("space.kscience:controls-opcua:0.3.0")
|
implementation("space.kscience:controls-opcua:0.4.0-dev-1")
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -6,7 +6,7 @@ Utils to work with controls-kt on Raspberry pi
|
|||||||
|
|
||||||
## Artifact:
|
## Artifact:
|
||||||
|
|
||||||
The Maven coordinates of this project are `space.kscience:controls-pi:0.3.0`.
|
The Maven coordinates of this project are `space.kscience:controls-pi:0.4.0-dev-1`.
|
||||||
|
|
||||||
**Gradle Kotlin DSL:**
|
**Gradle Kotlin DSL:**
|
||||||
```kotlin
|
```kotlin
|
||||||
@ -16,6 +16,6 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("space.kscience:controls-pi:0.3.0")
|
implementation("space.kscience:controls-pi:0.4.0-dev-1")
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -6,7 +6,7 @@ Implementation of byte ports on top os ktor-io asynchronous API
|
|||||||
|
|
||||||
## Artifact:
|
## Artifact:
|
||||||
|
|
||||||
The Maven coordinates of this project are `space.kscience:controls-ports-ktor:0.3.0`.
|
The Maven coordinates of this project are `space.kscience:controls-ports-ktor:0.4.0-dev-1`.
|
||||||
|
|
||||||
**Gradle Kotlin DSL:**
|
**Gradle Kotlin DSL:**
|
||||||
```kotlin
|
```kotlin
|
||||||
@ -16,6 +16,6 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("space.kscience:controls-ports-ktor:0.3.0")
|
implementation("space.kscience:controls-ports-ktor:0.4.0-dev-1")
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -6,7 +6,7 @@ Implementation of direct serial port communication with JSerialComm
|
|||||||
|
|
||||||
## Artifact:
|
## Artifact:
|
||||||
|
|
||||||
The Maven coordinates of this project are `space.kscience:controls-serial:0.3.0`.
|
The Maven coordinates of this project are `space.kscience:controls-serial:0.4.0-dev-1`.
|
||||||
|
|
||||||
**Gradle Kotlin DSL:**
|
**Gradle Kotlin DSL:**
|
||||||
```kotlin
|
```kotlin
|
||||||
@ -16,6 +16,6 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("space.kscience:controls-serial:0.3.0")
|
implementation("space.kscience:controls-serial:0.4.0-dev-1")
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -6,7 +6,7 @@ A combined Magix event loop server with web server for visualization.
|
|||||||
|
|
||||||
## Artifact:
|
## Artifact:
|
||||||
|
|
||||||
The Maven coordinates of this project are `space.kscience:controls-server:0.3.0`.
|
The Maven coordinates of this project are `space.kscience:controls-server:0.4.0-dev-1`.
|
||||||
|
|
||||||
**Gradle Kotlin DSL:**
|
**Gradle Kotlin DSL:**
|
||||||
```kotlin
|
```kotlin
|
||||||
@ -16,6 +16,6 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("space.kscience:controls-server:0.3.0")
|
implementation("space.kscience:controls-server:0.4.0-dev-1")
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -6,7 +6,7 @@ An API for stand-alone Controls-kt device or a hub.
|
|||||||
|
|
||||||
## Artifact:
|
## Artifact:
|
||||||
|
|
||||||
The Maven coordinates of this project are `space.kscience:controls-storage:0.3.0`.
|
The Maven coordinates of this project are `space.kscience:controls-storage:0.4.0-dev-1`.
|
||||||
|
|
||||||
**Gradle Kotlin DSL:**
|
**Gradle Kotlin DSL:**
|
||||||
```kotlin
|
```kotlin
|
||||||
@ -16,6 +16,6 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("space.kscience:controls-storage:0.3.0")
|
implementation("space.kscience:controls-storage:0.4.0-dev-1")
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -6,7 +6,7 @@ An implementation of controls-storage on top of JetBrains Xodus.
|
|||||||
|
|
||||||
## Artifact:
|
## Artifact:
|
||||||
|
|
||||||
The Maven coordinates of this project are `space.kscience:controls-xodus:0.3.0`.
|
The Maven coordinates of this project are `space.kscience:controls-xodus:0.4.0-dev-1`.
|
||||||
|
|
||||||
**Gradle Kotlin DSL:**
|
**Gradle Kotlin DSL:**
|
||||||
```kotlin
|
```kotlin
|
||||||
@ -16,6 +16,6 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("space.kscience:controls-xodus:0.3.0")
|
implementation("space.kscience:controls-xodus:0.4.0-dev-1")
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -2,11 +2,13 @@
|
|||||||
|
|
||||||
Dashboard and visualization extensions for devices
|
Dashboard and visualization extensions for devices
|
||||||
|
|
||||||
|
Hello world!
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
## Artifact:
|
## Artifact:
|
||||||
|
|
||||||
The Maven coordinates of this project are `space.kscience:controls-vision:0.3.0`.
|
The Maven coordinates of this project are `space.kscience:controls-vision:0.4.0-dev-1`.
|
||||||
|
|
||||||
**Gradle Kotlin DSL:**
|
**Gradle Kotlin DSL:**
|
||||||
```kotlin
|
```kotlin
|
||||||
@ -16,6 +18,6 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("space.kscience:controls-vision:0.3.0")
|
implementation("space.kscience:controls-vision:0.4.0-dev-1")
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -10,6 +10,7 @@ description = """
|
|||||||
kscience {
|
kscience {
|
||||||
fullStack("js/controls-vision.js")
|
fullStack("js/controls-vision.js")
|
||||||
useKtor()
|
useKtor()
|
||||||
|
useSerialization()
|
||||||
useContextReceivers()
|
useContextReceivers()
|
||||||
dependencies {
|
dependencies {
|
||||||
api(projects.controlsCore)
|
api(projects.controlsCore)
|
||||||
|
15
controls-vision/docs/README-TEMPLATE.md
Normal file
15
controls-vision/docs/README-TEMPLATE.md
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# Module ${name}
|
||||||
|
|
||||||
|
${description}
|
||||||
|
|
||||||
|
<#if features?has_content>
|
||||||
|
## Features
|
||||||
|
|
||||||
|
${features}
|
||||||
|
|
||||||
|
</#if>
|
||||||
|
<#if published>
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
${artifact}
|
||||||
|
</#if>
|
@ -0,0 +1,24 @@
|
|||||||
|
package space.kscience.controls.vision
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import space.kscience.dataforge.meta.boolean
|
||||||
|
import space.kscience.visionforge.AbstractVision
|
||||||
|
import space.kscience.visionforge.Vision
|
||||||
|
import space.kscience.visionforge.html.VisionOfHtml
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A [Vision] that shows an indicator
|
||||||
|
*/
|
||||||
|
@Serializable
|
||||||
|
@SerialName("controls.indicator")
|
||||||
|
public class BooleanIndicatorVision : AbstractVision(), VisionOfHtml {
|
||||||
|
public val isOn: Boolean by properties.boolean(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
///**
|
||||||
|
// * A [Vision] that allows both showing the value and changing it
|
||||||
|
// */
|
||||||
|
//public interface RegulatorVision: IndicatorVision{
|
||||||
|
//
|
||||||
|
//}
|
@ -6,7 +6,6 @@ import kotlinx.serialization.modules.subclass
|
|||||||
import space.kscience.dataforge.context.PluginFactory
|
import space.kscience.dataforge.context.PluginFactory
|
||||||
import space.kscience.visionforge.Vision
|
import space.kscience.visionforge.Vision
|
||||||
import space.kscience.visionforge.VisionPlugin
|
import space.kscience.visionforge.VisionPlugin
|
||||||
import space.kscience.visionforge.plotly.VisionOfPlotly
|
|
||||||
|
|
||||||
public expect class ControlVisionPlugin: VisionPlugin{
|
public expect class ControlVisionPlugin: VisionPlugin{
|
||||||
public companion object: PluginFactory<ControlVisionPlugin>
|
public companion object: PluginFactory<ControlVisionPlugin>
|
||||||
@ -14,6 +13,6 @@ public expect class ControlVisionPlugin: VisionPlugin{
|
|||||||
|
|
||||||
internal val controlsVisionSerializersModule = SerializersModule {
|
internal val controlsVisionSerializersModule = SerializersModule {
|
||||||
polymorphic(Vision::class) {
|
polymorphic(Vision::class) {
|
||||||
subclass(VisionOfPlotly.serializer())
|
subclass(BooleanIndicatorVision.serializer())
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,20 +0,0 @@
|
|||||||
package space.kscience.controls.vision
|
|
||||||
|
|
||||||
import space.kscience.dataforge.meta.Meta
|
|
||||||
import space.kscience.dataforge.meta.node
|
|
||||||
import space.kscience.visionforge.AbstractVision
|
|
||||||
import space.kscience.visionforge.Vision
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A [Vision] that shows an indicator
|
|
||||||
*/
|
|
||||||
public class IndicatorVision: AbstractVision() {
|
|
||||||
public val value: Meta? by properties.node()
|
|
||||||
}
|
|
||||||
|
|
||||||
///**
|
|
||||||
// * A [Vision] that allows both showing the value and changing it
|
|
||||||
// */
|
|
||||||
//public interface RegulatorVision: IndicatorVision{
|
|
||||||
//
|
|
||||||
//}
|
|
@ -1,4 +1,4 @@
|
|||||||
@file:OptIn(FlowPreview::class)
|
@file:OptIn(FlowPreview::class, FlowPreview::class)
|
||||||
|
|
||||||
package space.kscience.controls.vision
|
package space.kscience.controls.vision
|
||||||
|
|
||||||
|
@ -5,13 +5,29 @@ import space.kscience.dataforge.context.Context
|
|||||||
import space.kscience.dataforge.context.PluginFactory
|
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.asName
|
||||||
import space.kscience.visionforge.VisionPlugin
|
import space.kscience.visionforge.VisionPlugin
|
||||||
|
import space.kscience.visionforge.html.ElementVisionRenderer
|
||||||
|
|
||||||
|
private val indicatorRenderer = ElementVisionRenderer<BooleanIndicatorVision> { name, vision: BooleanIndicatorVision, meta ->
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public actual class ControlVisionPlugin : VisionPlugin() {
|
public actual class ControlVisionPlugin : VisionPlugin() {
|
||||||
override val tag: PluginTag get() = Companion.tag
|
override val tag: PluginTag get() = Companion.tag
|
||||||
|
|
||||||
override val visionSerializersModule: SerializersModule get() = controlsVisionSerializersModule
|
override val visionSerializersModule: SerializersModule get() = controlsVisionSerializersModule
|
||||||
|
|
||||||
|
override fun content(target: String): Map<Name, Any> = when (target) {
|
||||||
|
ElementVisionRenderer.TYPE -> mapOf(
|
||||||
|
"indicator".asName() to indicatorRenderer
|
||||||
|
)
|
||||||
|
|
||||||
|
else -> super.content(target)
|
||||||
|
}
|
||||||
|
|
||||||
public actual companion object : PluginFactory<ControlVisionPlugin> {
|
public actual companion object : PluginFactory<ControlVisionPlugin> {
|
||||||
override val tag: PluginTag = PluginTag("controls.vision")
|
override val tag: PluginTag = PluginTag("controls.vision")
|
||||||
|
|
||||||
|
@ -13,6 +13,8 @@ import space.kscience.plotly.PlotlyConfig
|
|||||||
import space.kscience.visionforge.html.HtmlVisionFragment
|
import space.kscience.visionforge.html.HtmlVisionFragment
|
||||||
import space.kscience.visionforge.html.VisionPage
|
import space.kscience.visionforge.html.VisionPage
|
||||||
import space.kscience.visionforge.html.VisionTagConsumer
|
import space.kscience.visionforge.html.VisionTagConsumer
|
||||||
|
import space.kscience.visionforge.markup.MarkupPlugin
|
||||||
|
import space.kscience.visionforge.plotly.PlotlyPlugin
|
||||||
import space.kscience.visionforge.plotly.plotly
|
import space.kscience.visionforge.plotly.plotly
|
||||||
import space.kscience.visionforge.server.VisionRoute
|
import space.kscience.visionforge.server.VisionRoute
|
||||||
import space.kscience.visionforge.server.close
|
import space.kscience.visionforge.server.close
|
||||||
@ -25,19 +27,27 @@ public fun Context.showDashboard(
|
|||||||
routes: Routing.() -> Unit = {},
|
routes: Routing.() -> Unit = {},
|
||||||
configurationBuilder: VisionRoute.() -> Unit = {},
|
configurationBuilder: VisionRoute.() -> Unit = {},
|
||||||
visionFragment: HtmlVisionFragment,
|
visionFragment: HtmlVisionFragment,
|
||||||
): ApplicationEngine = embeddedServer(CIO, port = port) {
|
): ApplicationEngine {
|
||||||
|
//create a sub-context for visualization
|
||||||
|
val visualisationContext = buildContext {
|
||||||
|
plugin(PlotlyPlugin)
|
||||||
|
plugin(ControlVisionPlugin)
|
||||||
|
plugin(MarkupPlugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
return visualisationContext.embeddedServer(CIO, port = port) {
|
||||||
routing {
|
routing {
|
||||||
staticResources("", null, null)
|
staticResources("", null, null)
|
||||||
routes()
|
routes()
|
||||||
}
|
}
|
||||||
|
|
||||||
visionPage(
|
visionPage(
|
||||||
visionManager,
|
visualisationContext.visionManager,
|
||||||
VisionPage.scriptHeader("js/controls-vision.js"),
|
VisionPage.scriptHeader("js/controls-vision.js"),
|
||||||
configurationBuilder = configurationBuilder,
|
configurationBuilder = configurationBuilder,
|
||||||
visionFragment = visionFragment
|
visionFragment = visionFragment
|
||||||
)
|
)
|
||||||
}.also {
|
}.also {
|
||||||
it.start(false)
|
it.start(false)
|
||||||
it.openInBrowser()
|
it.openInBrowser()
|
||||||
|
|
||||||
@ -48,6 +58,7 @@ public fun Context.showDashboard(
|
|||||||
}
|
}
|
||||||
|
|
||||||
it.close()
|
it.close()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
context(VisionTagConsumer<*>)
|
context(VisionTagConsumer<*>)
|
||||||
|
@ -14,8 +14,10 @@ import androidx.compose.ui.Modifier
|
|||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.window.Window
|
import androidx.compose.ui.window.Window
|
||||||
import androidx.compose.ui.window.application
|
import androidx.compose.ui.window.application
|
||||||
import kotlinx.coroutines.launch
|
import space.kscience.controls.constructor.DeviceConstructor
|
||||||
import space.kscience.controls.constructor.*
|
import space.kscience.controls.constructor.DoubleInRangeState
|
||||||
|
import space.kscience.controls.constructor.device
|
||||||
|
import space.kscience.controls.constructor.deviceProperty
|
||||||
import space.kscience.controls.constructor.library.*
|
import space.kscience.controls.constructor.library.*
|
||||||
import space.kscience.controls.manager.ClockManager
|
import space.kscience.controls.manager.ClockManager
|
||||||
import space.kscience.controls.manager.DeviceManager
|
import space.kscience.controls.manager.DeviceManager
|
||||||
@ -40,77 +42,41 @@ import kotlin.time.DurationUnit
|
|||||||
|
|
||||||
|
|
||||||
class LinearDrive(
|
class LinearDrive(
|
||||||
|
drive: Drive,
|
||||||
|
start: LimitSwitch,
|
||||||
|
end: LimitSwitch,
|
||||||
|
pidParameters: PidParameters,
|
||||||
|
meta: Meta = Meta.EMPTY,
|
||||||
|
) : DeviceConstructor(drive.context, meta) {
|
||||||
|
|
||||||
|
val drive: Drive by device(drive)
|
||||||
|
val pid by device(PidRegulator(drive, pidParameters))
|
||||||
|
|
||||||
|
val start by device(start)
|
||||||
|
val end by device(end)
|
||||||
|
|
||||||
|
val position by deviceProperty(drive, Drive.position, Double.NaN)
|
||||||
|
|
||||||
|
val target by deviceProperty(pid, Regulator.target, 0.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A shortcut to create a virtual [LimitSwitch] from [DoubleInRangeState]
|
||||||
|
*/
|
||||||
|
fun LinearDrive(
|
||||||
context: Context,
|
context: Context,
|
||||||
state: DoubleRangeState,
|
positionState: DoubleInRangeState,
|
||||||
mass: Double,
|
mass: Double,
|
||||||
pidParameters: PidParameters,
|
pidParameters: PidParameters,
|
||||||
meta: Meta = Meta.EMPTY,
|
meta: Meta = Meta.EMPTY,
|
||||||
) : DeviceConstructor(context, meta) {
|
): LinearDrive = LinearDrive(
|
||||||
|
drive = VirtualDrive(context, mass, positionState),
|
||||||
|
start = VirtualLimitSwitch(context, positionState.atStart),
|
||||||
|
end = VirtualLimitSwitch(context, positionState.atEnd),
|
||||||
|
pidParameters = pidParameters,
|
||||||
|
meta = meta
|
||||||
|
)
|
||||||
|
|
||||||
val drive by device(VirtualDrive.factory(mass, state))
|
|
||||||
val pid by device(PidRegulator(drive, pidParameters))
|
|
||||||
|
|
||||||
val start by device(LimitSwitch(state.atStartState))
|
|
||||||
val end by device(LimitSwitch(state.atEndState))
|
|
||||||
|
|
||||||
|
|
||||||
val positionState: DoubleRangeState by property(state)
|
|
||||||
|
|
||||||
private val targetState: MutableDeviceState<Double> by deviceProperty(pid, Regulator.target, 0.0)
|
|
||||||
var target: Double by targetState
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private fun Context.launchPidDevice(
|
|
||||||
state: DoubleRangeState,
|
|
||||||
pidParameters: PidParameters,
|
|
||||||
mass: Double,
|
|
||||||
) = launch {
|
|
||||||
val device = install(
|
|
||||||
"device",
|
|
||||||
LinearDrive(this@launchPidDevice, state, mass, pidParameters)
|
|
||||||
).apply {
|
|
||||||
val clock = context.clock
|
|
||||||
val clockStart = clock.now()
|
|
||||||
doRecurring(10.milliseconds) {
|
|
||||||
val timeFromStart = clock.now() - clockStart
|
|
||||||
val t = timeFromStart.toDouble(DurationUnit.SECONDS)
|
|
||||||
val freq = 0.1
|
|
||||||
target = 5 * sin(2.0 * PI * freq * t) +
|
|
||||||
sin(2 * PI * 21 * freq * t + 0.02 * (timeFromStart / pidParameters.timeStep))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
val maxAge = 10.seconds
|
|
||||||
|
|
||||||
showDashboard {
|
|
||||||
plot {
|
|
||||||
plotNumberState(context, state, maxAge = maxAge, sampling = 50.milliseconds) {
|
|
||||||
name = "real position"
|
|
||||||
}
|
|
||||||
plotDeviceProperty(device.pid, Regulator.position.name, maxAge = maxAge, sampling = 50.milliseconds) {
|
|
||||||
name = "read position"
|
|
||||||
}
|
|
||||||
|
|
||||||
plotDeviceProperty(device.pid, Regulator.target.name, maxAge = maxAge, sampling = 50.milliseconds) {
|
|
||||||
name = "target"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
plot {
|
|
||||||
plotDeviceProperty(device.start, LimitSwitch.locked.name, maxAge = maxAge, sampling = 50.milliseconds) {
|
|
||||||
name = "start measured"
|
|
||||||
mode = ScatterMode.markers
|
|
||||||
}
|
|
||||||
plotDeviceProperty(device.end, LimitSwitch.locked.name, maxAge = maxAge, sampling = 50.milliseconds) {
|
|
||||||
name = "end measured"
|
|
||||||
mode = ScatterMode.markers
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun main() = application {
|
fun main() = application {
|
||||||
val context = Context {
|
val context = Context {
|
||||||
@ -140,12 +106,57 @@ fun main() = application {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
context.launchPidDevice(
|
val state = DoubleInRangeState(0.0, -6.0..6.0)
|
||||||
DoubleRangeState(0.0, -6.0..6.0),
|
|
||||||
pidParameters,
|
val linearDrive = context.install(
|
||||||
mass = 0.05
|
"linearDrive",
|
||||||
|
LinearDrive(context, state, 0.05, pidParameters)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val clockStart = context.clock.now()
|
||||||
|
linearDrive.doRecurring(10.milliseconds) {
|
||||||
|
val timeFromStart = clock.now() - clockStart
|
||||||
|
val t = timeFromStart.toDouble(DurationUnit.SECONDS)
|
||||||
|
val freq = 0.1
|
||||||
|
target.value = 5 * sin(2.0 * PI * freq * t) +
|
||||||
|
sin(2 * PI * 21 * freq * t + 0.02 * (timeFromStart / pidParameters.timeStep))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
val maxAge = 10.seconds
|
||||||
|
|
||||||
|
context.showDashboard {
|
||||||
|
plot {
|
||||||
|
plotNumberState(context, state, maxAge = maxAge, sampling = 50.milliseconds) {
|
||||||
|
name = "real position"
|
||||||
|
}
|
||||||
|
plotDeviceProperty(linearDrive.pid, Regulator.position.name, maxAge = maxAge, sampling = 50.milliseconds) {
|
||||||
|
name = "read position"
|
||||||
|
}
|
||||||
|
|
||||||
|
plotDeviceProperty(linearDrive.pid, Regulator.target.name, maxAge = maxAge, sampling = 50.milliseconds) {
|
||||||
|
name = "target"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
plot {
|
||||||
|
plotDeviceProperty(
|
||||||
|
linearDrive.start,
|
||||||
|
LimitSwitch.locked.name,
|
||||||
|
maxAge = maxAge,
|
||||||
|
sampling = 50.milliseconds
|
||||||
|
) {
|
||||||
|
name = "start measured"
|
||||||
|
mode = ScatterMode.markers
|
||||||
|
}
|
||||||
|
plotDeviceProperty(linearDrive.end, LimitSwitch.locked.name, maxAge = maxAge, sampling = 50.milliseconds) {
|
||||||
|
name = "end measured"
|
||||||
|
mode = ScatterMode.markers
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
Window(title = "Pid regulator simulator", onCloseRequest = ::exitApplication) {
|
Window(title = "Pid regulator simulator", onCloseRequest = ::exitApplication) {
|
||||||
MaterialTheme {
|
MaterialTheme {
|
||||||
Column {
|
Column {
|
@ -97,7 +97,7 @@ fun AxisPane(axes: Map<String, PiMotionMasterDevice.Axis>) {
|
|||||||
@Composable
|
@Composable
|
||||||
fun PiMotionMasterApp(device: PiMotionMasterDevice) {
|
fun PiMotionMasterApp(device: PiMotionMasterDevice) {
|
||||||
|
|
||||||
val scope = rememberCoroutineScope()
|
// val scope = rememberCoroutineScope()
|
||||||
val connected by device.composeState(PiMotionMasterDevice.connected, false)
|
val connected by device.composeState(PiMotionMasterDevice.connected, false)
|
||||||
var debugServerJob by remember { mutableStateOf<Job?>(null) }
|
var debugServerJob by remember { mutableStateOf<Job?>(null) }
|
||||||
var axes by remember { mutableStateOf<Map<String, PiMotionMasterDevice.Axis>?>(null) }
|
var axes by remember { mutableStateOf<Map<String, PiMotionMasterDevice.Axis>?>(null) }
|
||||||
|
30
docs/templates/ARTIFACT-TEMPLATE.md
vendored
30
docs/templates/ARTIFACT-TEMPLATE.md
vendored
@ -1,30 +0,0 @@
|
|||||||
## Artifact:
|
|
||||||
|
|
||||||
The Maven coordinates of this project are `${group}:${name}:${version}`.
|
|
||||||
|
|
||||||
**Gradle:**
|
|
||||||
```groovy
|
|
||||||
repositories {
|
|
||||||
maven { url 'https://repo.kotlin.link' }
|
|
||||||
mavenCentral()
|
|
||||||
// development and snapshot versions
|
|
||||||
maven { url 'https://maven.pkg.jetbrains.space/spc/p/sci/dev' }
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
implementation '${group}:${name}:${version}'
|
|
||||||
}
|
|
||||||
```
|
|
||||||
**Gradle Kotlin DSL:**
|
|
||||||
```kotlin
|
|
||||||
repositories {
|
|
||||||
maven("https://repo.kotlin.link")
|
|
||||||
mavenCentral()
|
|
||||||
// development and snapshot versions
|
|
||||||
maven("https://maven.pkg.jetbrains.space/spc/p/sci/dev")
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
implementation("${group}:${name}:${version}")
|
|
||||||
}
|
|
||||||
```
|
|
@ -6,7 +6,7 @@ A kotlin API for magix standard and some zero-dependency magix services
|
|||||||
|
|
||||||
## Artifact:
|
## Artifact:
|
||||||
|
|
||||||
The Maven coordinates of this project are `space.kscience:magix-api:0.3.0`.
|
The Maven coordinates of this project are `space.kscience:magix-api:0.4.0-dev-1`.
|
||||||
|
|
||||||
**Gradle Kotlin DSL:**
|
**Gradle Kotlin DSL:**
|
||||||
```kotlin
|
```kotlin
|
||||||
@ -16,6 +16,6 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("space.kscience:magix-api:0.3.0")
|
implementation("space.kscience:magix-api:0.4.0-dev-1")
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -6,7 +6,7 @@ Java API to work with magix endpoints without Kotlin
|
|||||||
|
|
||||||
## Artifact:
|
## Artifact:
|
||||||
|
|
||||||
The Maven coordinates of this project are `space.kscience:magix-java-endpoint:0.3.0`.
|
The Maven coordinates of this project are `space.kscience:magix-java-endpoint:0.4.0-dev-1`.
|
||||||
|
|
||||||
**Gradle Kotlin DSL:**
|
**Gradle Kotlin DSL:**
|
||||||
```kotlin
|
```kotlin
|
||||||
@ -16,6 +16,6 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("space.kscience:magix-java-endpoint:0.3.0")
|
implementation("space.kscience:magix-java-endpoint:0.4.0-dev-1")
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -6,7 +6,7 @@ MQTT client magix endpoint
|
|||||||
|
|
||||||
## Artifact:
|
## Artifact:
|
||||||
|
|
||||||
The Maven coordinates of this project are `space.kscience:magix-mqtt:0.3.0`.
|
The Maven coordinates of this project are `space.kscience:magix-mqtt:0.4.0-dev-1`.
|
||||||
|
|
||||||
**Gradle Kotlin DSL:**
|
**Gradle Kotlin DSL:**
|
||||||
```kotlin
|
```kotlin
|
||||||
@ -16,6 +16,6 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("space.kscience:magix-mqtt:0.3.0")
|
implementation("space.kscience:magix-mqtt:0.4.0-dev-1")
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -6,7 +6,7 @@ RabbitMQ client magix endpoint
|
|||||||
|
|
||||||
## Artifact:
|
## Artifact:
|
||||||
|
|
||||||
The Maven coordinates of this project are `space.kscience:magix-rabbit:0.3.0`.
|
The Maven coordinates of this project are `space.kscience:magix-rabbit:0.4.0-dev-1`.
|
||||||
|
|
||||||
**Gradle Kotlin DSL:**
|
**Gradle Kotlin DSL:**
|
||||||
```kotlin
|
```kotlin
|
||||||
@ -16,6 +16,6 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("space.kscience:magix-rabbit:0.3.0")
|
implementation("space.kscience:magix-rabbit:0.4.0-dev-1")
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -6,7 +6,7 @@ Magix endpoint (client) based on RSocket
|
|||||||
|
|
||||||
## Artifact:
|
## Artifact:
|
||||||
|
|
||||||
The Maven coordinates of this project are `space.kscience:magix-rsocket:0.3.0`.
|
The Maven coordinates of this project are `space.kscience:magix-rsocket:0.4.0-dev-1`.
|
||||||
|
|
||||||
**Gradle Kotlin DSL:**
|
**Gradle Kotlin DSL:**
|
||||||
```kotlin
|
```kotlin
|
||||||
@ -16,6 +16,6 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("space.kscience:magix-rsocket:0.3.0")
|
implementation("space.kscience:magix-rsocket:0.4.0-dev-1")
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -6,7 +6,7 @@ A magix event loop implementation in Kotlin. Includes HTTP/SSE and RSocket route
|
|||||||
|
|
||||||
## Artifact:
|
## Artifact:
|
||||||
|
|
||||||
The Maven coordinates of this project are `space.kscience:magix-server:0.3.0`.
|
The Maven coordinates of this project are `space.kscience:magix-server:0.4.0-dev-1`.
|
||||||
|
|
||||||
**Gradle Kotlin DSL:**
|
**Gradle Kotlin DSL:**
|
||||||
```kotlin
|
```kotlin
|
||||||
@ -16,6 +16,6 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("space.kscience:magix-server:0.3.0")
|
implementation("space.kscience:magix-server:0.4.0-dev-1")
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -6,7 +6,7 @@ Magix history database API
|
|||||||
|
|
||||||
## Artifact:
|
## Artifact:
|
||||||
|
|
||||||
The Maven coordinates of this project are `space.kscience:magix-storage:0.3.0`.
|
The Maven coordinates of this project are `space.kscience:magix-storage:0.4.0-dev-1`.
|
||||||
|
|
||||||
**Gradle Kotlin DSL:**
|
**Gradle Kotlin DSL:**
|
||||||
```kotlin
|
```kotlin
|
||||||
@ -16,6 +16,6 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("space.kscience:magix-storage:0.3.0")
|
implementation("space.kscience:magix-storage:0.4.0-dev-1")
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
## Artifact:
|
## Artifact:
|
||||||
|
|
||||||
The Maven coordinates of this project are `space.kscience:magix-storage-xodus:0.3.0`.
|
The Maven coordinates of this project are `space.kscience:magix-storage-xodus:0.4.0-dev-1`.
|
||||||
|
|
||||||
**Gradle Kotlin DSL:**
|
**Gradle Kotlin DSL:**
|
||||||
```kotlin
|
```kotlin
|
||||||
@ -16,6 +16,6 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("space.kscience:magix-storage-xodus:0.3.0")
|
implementation("space.kscience:magix-storage-xodus:0.4.0-dev-1")
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -6,7 +6,7 @@ ZMQ client endpoint for Magix
|
|||||||
|
|
||||||
## Artifact:
|
## Artifact:
|
||||||
|
|
||||||
The Maven coordinates of this project are `space.kscience:magix-zmq:0.3.0`.
|
The Maven coordinates of this project are `space.kscience:magix-zmq:0.4.0-dev-1`.
|
||||||
|
|
||||||
**Gradle Kotlin DSL:**
|
**Gradle Kotlin DSL:**
|
||||||
```kotlin
|
```kotlin
|
||||||
@ -16,6 +16,6 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("space.kscience:magix-zmq:0.3.0")
|
implementation("space.kscience:magix-zmq:0.4.0-dev-1")
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
Loading…
Reference in New Issue
Block a user