Documentation update
This commit is contained in:
parent
e7cfb1d2ba
commit
8cd191bb0d
24
.github/workflows/build.yml
vendored
Normal file
24
.github/workflows/build.yml
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
name: Gradle build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ dev, master ]
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: windows-latest
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-java@v3.5.1
|
||||
with:
|
||||
java-version: '11'
|
||||
distribution: 'liberica'
|
||||
cache: 'gradle'
|
||||
- name: Gradle Wrapper Validation
|
||||
uses: gradle/wrapper-validation-action@v1.0.4
|
||||
- name: Gradle Build
|
||||
uses: gradle/gradle-build-action@v2.4.2
|
||||
with:
|
||||
arguments: test jvmTest
|
17
.github/workflows/gradle.yml
vendored
17
.github/workflows/gradle.yml
vendored
@ -1,17 +0,0 @@
|
||||
name: Gradle build
|
||||
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Set up JDK 11
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 11
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew build
|
31
.github/workflows/pages.yml
vendored
Normal file
31
.github/workflows/pages.yml
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
name: Dokka publication
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
release:
|
||||
types: [ created ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 40
|
||||
steps:
|
||||
- uses: actions/checkout@v3.0.0
|
||||
- uses: actions/setup-java@v3.0.0
|
||||
with:
|
||||
java-version: 11
|
||||
distribution: liberica
|
||||
- name: Cache konan
|
||||
uses: actions/cache@v3.0.1
|
||||
with:
|
||||
path: ~/.konan
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-gradle-
|
||||
- uses: gradle/gradle-build-action@v2.4.2
|
||||
with:
|
||||
arguments: dokkaHtmlMultiModule --no-parallel
|
||||
- uses: JamesIves/github-pages-deploy-action@v4.3.0
|
||||
with:
|
||||
branch: gh-pages
|
||||
folder: build/dokka/htmlMultiModule
|
50
.github/workflows/publish.yml
vendored
Normal file
50
.github/workflows/publish.yml
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
name: Gradle publish
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
release:
|
||||
types: [ created ]
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
environment:
|
||||
name: publish
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ macOS-latest, windows-latest ]
|
||||
runs-on: ${{matrix.os}}
|
||||
steps:
|
||||
- uses: actions/checkout@v3.0.0
|
||||
- uses: actions/setup-java@v3.10.0
|
||||
with:
|
||||
java-version: 11
|
||||
distribution: liberica
|
||||
- name: Cache konan
|
||||
uses: actions/cache@v3.0.1
|
||||
with:
|
||||
path: ~/.konan
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-gradle-
|
||||
- name: Publish Windows Artifacts
|
||||
if: matrix.os == 'windows-latest'
|
||||
uses: gradle/gradle-build-action@v2.4.2
|
||||
with:
|
||||
arguments: |
|
||||
publishAllPublicationsToSpaceRepository
|
||||
-Ppublishing.targets=all
|
||||
-Ppublishing.space.user=${{ secrets.SPACE_APP_ID }}
|
||||
-Ppublishing.space.token=${{ secrets.SPACE_APP_SECRET }}
|
||||
- name: Publish Mac Artifacts
|
||||
if: matrix.os == 'macOS-latest'
|
||||
uses: gradle/gradle-build-action@v2.4.2
|
||||
with:
|
||||
arguments: |
|
||||
publishMacosX64PublicationToSpaceRepository
|
||||
publishMacosArm64PublicationToSpaceRepository
|
||||
publishIosX64PublicationToSpaceRepository
|
||||
publishIosArm64PublicationToSpaceRepository
|
||||
publishIosSimulatorArm64PublicationToSpaceRepository
|
||||
-Ppublishing.targets=all
|
||||
-Ppublishing.space.user=${{ secrets.SPACE_APP_ID }}
|
||||
-Ppublishing.space.token=${{ secrets.SPACE_APP_SECRET }}
|
3
.space.kts
Normal file
3
.space.kts
Normal file
@ -0,0 +1,3 @@
|
||||
job("Build and run tests") {
|
||||
gradlew("amazoncorretto:17-alpine", "build")
|
||||
}
|
178
README.md
178
README.md
@ -3,58 +3,182 @@
|
||||
# Controls.kt
|
||||
|
||||
Controls.kt (former DataForge-control) is a data acquisition framework (work in progress). It is based on DataForge, a software framework for automated data processing.
|
||||
This repository contains a prototype of API and simple implementation
|
||||
This repository contains a prototype of API and simple implementation
|
||||
of a slow control system, including a demo.
|
||||
|
||||
Controls.kt uses some concepts and modules of DataForge,
|
||||
such as `Meta` (immutable tree-like structure) and `Meta` (which
|
||||
includes a scalar value, or a tree of values, easily convertable to/from JSON
|
||||
if needed).
|
||||
Controls.kt uses some concepts and modules of DataForge,
|
||||
such as `Meta` (tree-like value structure).
|
||||
|
||||
To learn more about DataForge, please consult the following URLs:
|
||||
* [Kotlin multiplatform implementation of DataForge](https://github.com/mipt-npm/dataforge-core)
|
||||
* [DataForge documentation](http://npm.mipt.ru/dataforge/)
|
||||
* [Original implementation of DataForge](https://bitbucket.org/Altavir/dataforge/src/default/)
|
||||
* [Kotlin multiplatform implementation of DataForge](https://github.com/mipt-npm/dataforge-core)
|
||||
* [DataForge documentation](http://npm.mipt.ru/dataforge/)
|
||||
* [Original implementation of DataForge](https://bitbucket.org/Altavir/dataforge/src/default/)
|
||||
|
||||
DataForge-control is a [Kotlin-multiplatform](https://kotlinlang.org/docs/reference/multiplatform.html)
|
||||
application. Asynchronous operations are implemented with
|
||||
application. Asynchronous operations are implemented with
|
||||
[kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) library.
|
||||
|
||||
## Materials and publications
|
||||
|
||||
* Video - [A general overview seminar](https://youtu.be/LO-qjWgXMWc)
|
||||
* Video - [A seminar about the system mechanics](https://youtu.be/wES0RV5GpoQ)
|
||||
* Article - [A Novel Solution for Controlling Hardware Components of Accelerators and Beamlines](https://www.preprints.org/manuscript/202108.0336/v1)
|
||||
* Article - [A Novel Solution for Controlling Hardware Components of Accelerators and Beamlines](https://www.preprints.org/manuscript/202108.0336/v1)
|
||||
|
||||
### Features
|
||||
Among other things, you can:
|
||||
- Describe devices and their properties.
|
||||
- Describe devices and their properties.
|
||||
- Collect data from devices and execute arbitrary actions supported by a device.
|
||||
- Property values can be cached in the system and requested from devices as needed, asynchronously.
|
||||
- Connect devices to event bus via bidirectional message flows.
|
||||
|
||||
### `dataforge-control-core` module packages
|
||||
Example view of a demo:
|
||||
|
||||
- `api` - defines API for device management. The main class here is
|
||||
[`Device`](controls-core/src/commonMain/kotlin/ru/mipt/npm/controls/api/Device.kt).
|
||||
Generally, a Device has Properties that can be read and written. Also, some Actions
|
||||
can optionally be applied on a device (may or may not affect properties).
|
||||
![](docs/pictures/demo-view.png)
|
||||
|
||||
- `base` - contains baseline `Device` implementation
|
||||
[`DeviceBase`](controls-core/src/commonMain/kotlin/ru/mipt/npm/controls/base/DeviceBase.kt)
|
||||
and property implementation, including property asynchronous flows.
|
||||
## Modules
|
||||
|
||||
|
||||
### [controls-core](controls-core)
|
||||
>
|
||||
>
|
||||
> **Maturity**: EXPERIMENTAL
|
||||
>
|
||||
> **Features:**
|
||||
> - [device](controls-core/src/commonMain/kotlin/space/kscience/controls/api/Device.kt) : Device API with subscription (asynchronous and pseudo-synchronous properties)
|
||||
> - [deviceMessage](controls-core/src/commonMain/kotlin/space/kscience/controls/api/DeviceMessage.kt) : Specification for messages used to communicate between Controls-kt devices.
|
||||
> - [deviceHub](controls-core/src/commonMain/kotlin/space/kscience/controls/api/DeviceHub.kt) : Grouping of devices into local tree-like hubs.
|
||||
|
||||
|
||||
### [controls-ktor-tcp](controls-ktor-tcp)
|
||||
>
|
||||
>
|
||||
> **Maturity**: EXPERIMENTAL
|
||||
|
||||
### [controls-magix-client](controls-magix-client)
|
||||
>
|
||||
>
|
||||
> **Maturity**: EXPERIMENTAL
|
||||
|
||||
### [controls-modbus](controls-modbus)
|
||||
>
|
||||
>
|
||||
> **Maturity**: EXPERIMENTAL
|
||||
|
||||
### [controls-opcua](controls-opcua)
|
||||
>
|
||||
>
|
||||
> **Maturity**: EXPERIMENTAL
|
||||
|
||||
### [controls-serial](controls-serial)
|
||||
>
|
||||
>
|
||||
> **Maturity**: EXPERIMENTAL
|
||||
|
||||
### [controls-server](controls-server)
|
||||
>
|
||||
>
|
||||
> **Maturity**: EXPERIMENTAL
|
||||
|
||||
### [controls-storage](controls-storage)
|
||||
>
|
||||
>
|
||||
> **Maturity**: PROTOTYPE
|
||||
|
||||
### [demo](demo)
|
||||
>
|
||||
>
|
||||
> **Maturity**: EXPERIMENTAL
|
||||
|
||||
### [magix](magix)
|
||||
>
|
||||
>
|
||||
> **Maturity**: EXPERIMENTAL
|
||||
|
||||
### [controls-storage/controls-xodus](controls-storage/controls-xodus)
|
||||
>
|
||||
>
|
||||
> **Maturity**: PROTOTYPE
|
||||
|
||||
### [demo/all-things](demo/all-things)
|
||||
>
|
||||
>
|
||||
> **Maturity**: EXPERIMENTAL
|
||||
|
||||
### [demo/car](demo/car)
|
||||
>
|
||||
>
|
||||
> **Maturity**: EXPERIMENTAL
|
||||
|
||||
### [demo/echo](demo/echo)
|
||||
>
|
||||
>
|
||||
> **Maturity**: EXPERIMENTAL
|
||||
|
||||
### [demo/magix-demo](demo/magix-demo)
|
||||
>
|
||||
>
|
||||
> **Maturity**: EXPERIMENTAL
|
||||
|
||||
### [demo/mks-pdr900](demo/mks-pdr900)
|
||||
>
|
||||
>
|
||||
> **Maturity**: EXPERIMENTAL
|
||||
|
||||
### [demo/motors](demo/motors)
|
||||
>
|
||||
>
|
||||
> **Maturity**: EXPERIMENTAL
|
||||
|
||||
### [magix/magix-api](magix/magix-api)
|
||||
>
|
||||
>
|
||||
> **Maturity**: EXPERIMENTAL
|
||||
|
||||
### [magix/magix-java-client](magix/magix-java-client)
|
||||
>
|
||||
>
|
||||
> **Maturity**: EXPERIMENTAL
|
||||
|
||||
### [magix/magix-mqtt](magix/magix-mqtt)
|
||||
>
|
||||
>
|
||||
> **Maturity**: PROTOTYPE
|
||||
|
||||
### [magix/magix-rabbit](magix/magix-rabbit)
|
||||
>
|
||||
>
|
||||
> **Maturity**: PROTOTYPE
|
||||
|
||||
### [magix/magix-rsocket](magix/magix-rsocket)
|
||||
>
|
||||
>
|
||||
> **Maturity**: EXPERIMENTAL
|
||||
|
||||
### [magix/magix-server](magix/magix-server)
|
||||
>
|
||||
>
|
||||
> **Maturity**: EXPERIMENTAL
|
||||
|
||||
### [magix/magix-storage](magix/magix-storage)
|
||||
>
|
||||
>
|
||||
> **Maturity**: EXPERIMENTAL
|
||||
|
||||
### [magix/magix-zmq](magix/magix-zmq)
|
||||
>
|
||||
>
|
||||
> **Maturity**: EXPERIMENTAL
|
||||
|
||||
### [magix/magix-storage/magix-storage-xodus](magix/magix-storage/magix-storage-xodus)
|
||||
>
|
||||
>
|
||||
> **Maturity**: PROTOTYPE
|
||||
|
||||
- `controllers` - implements Message Controller that can be attached to the event bus, Message
|
||||
and Property flows.
|
||||
|
||||
### `demo` module
|
||||
|
||||
The demo includes a simple mock device with a few properties changing as `sin` and `cos` of
|
||||
the current time. The device is configurable via a simple TornadoFX-based control panel.
|
||||
You can run a demo by executing `application/run` Gradle task.
|
||||
the current time. The device is configurable via a simple TornadoFX-based control panel.
|
||||
You can run a demo by executing `application/run` Gradle task.
|
||||
|
||||
The graphs are displayed using [plotly.kt](https://github.com/mipt-npm/plotly.kt) library.
|
||||
|
||||
Example view of a demo:
|
||||
|
||||
![](docs/pictures/demo-view.png)
|
||||
|
@ -35,6 +35,8 @@ ksciencePublish {
|
||||
space("https://maven.pkg.jetbrains.space/spc/p/controls/maven")
|
||||
}
|
||||
|
||||
readme.readmeTemplate = file("docs/templates/README-TEMPLATE.md")
|
||||
|
||||
apiValidation {
|
||||
validationDisabled = true
|
||||
}
|
@ -18,3 +18,28 @@ kscience {
|
||||
api(spclibs.kotlinx.datetime)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
readme{
|
||||
feature("device", ref = "src/commonMain/kotlin/space/kscience/controls/api/Device.kt"){
|
||||
"""
|
||||
Device API with subscription (asynchronous and pseudo-synchronous properties)
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
readme{
|
||||
feature("deviceMessage", ref = "src/commonMain/kotlin/space/kscience/controls/api/DeviceMessage.kt"){
|
||||
"""
|
||||
Specification for messages used to communicate between Controls-kt devices.
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
readme{
|
||||
feature("deviceHub", ref = "src/commonMain/kotlin/space/kscience/controls/api/DeviceHub.kt"){
|
||||
"""
|
||||
Grouping of devices into local tree-like hubs.
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
package space.kscience.controls.api
|
||||
|
||||
import io.ktor.utils.io.core.Closeable
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.cancel
|
||||
@ -17,10 +16,11 @@ import space.kscience.dataforge.names.Name
|
||||
|
||||
/**
|
||||
* General interface describing a managed Device.
|
||||
* Device is a supervisor scope encompassing all operations on a device. When canceled, cancels all running processes.
|
||||
* [Device] is a supervisor scope encompassing all operations on a device.
|
||||
* When canceled, cancels all running processes.
|
||||
*/
|
||||
@Type(DEVICE_TARGET)
|
||||
public interface Device : Closeable, ContextAware, CoroutineScope {
|
||||
public interface Device : AutoCloseable, ContextAware, CoroutineScope {
|
||||
|
||||
/**
|
||||
* Initial configuration meta for the device
|
||||
@ -97,9 +97,8 @@ public suspend fun Device.getOrReadProperty(propertyName: String): Meta =
|
||||
getProperty(propertyName) ?: readProperty(propertyName)
|
||||
|
||||
/**
|
||||
* Get a snapshot of logical state of the device
|
||||
* Get a snapshot of the device logical state
|
||||
*
|
||||
* TODO currently this
|
||||
*/
|
||||
public fun Device.getAllProperties(): Meta = Meta {
|
||||
for (descriptor in propertyDescriptors) {
|
||||
|
@ -3,6 +3,7 @@ package space.kscience.controls.manager
|
||||
import kotlinx.coroutines.launch
|
||||
import space.kscience.controls.api.Device
|
||||
import space.kscience.controls.api.DeviceHub
|
||||
import space.kscience.controls.api.getOrNull
|
||||
import space.kscience.dataforge.context.*
|
||||
import space.kscience.dataforge.meta.Meta
|
||||
import space.kscience.dataforge.meta.MutableMeta
|
||||
@ -12,6 +13,9 @@ import kotlin.collections.set
|
||||
import kotlin.properties.ReadOnlyProperty
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
/**
|
||||
* DataForge Context plugin that allows to manage devices locally
|
||||
*/
|
||||
public class DeviceManager : AbstractPlugin(), DeviceHub {
|
||||
override val tag: PluginTag get() = Companion.tag
|
||||
|
||||
@ -36,6 +40,9 @@ public class DeviceManager : AbstractPlugin(), DeviceHub {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Register and start a device built by [factory] with current [Context] and [meta].
|
||||
*/
|
||||
public fun <D : Device> DeviceManager.install(name: String, factory: Factory<D>, meta: Meta = Meta.EMPTY): D {
|
||||
val device = factory(meta, context)
|
||||
registerDevice(NameToken(name), device)
|
||||
@ -45,6 +52,9 @@ public fun <D : Device> DeviceManager.install(name: String, factory: Factory<D>,
|
||||
return device
|
||||
}
|
||||
|
||||
/**
|
||||
* A delegate that initializes device on the first use
|
||||
*/
|
||||
public inline fun <D : Device> DeviceManager.installing(
|
||||
factory: Factory<D>,
|
||||
builder: MutableMeta.() -> Unit = {},
|
||||
@ -52,7 +62,15 @@ public inline fun <D : Device> DeviceManager.installing(
|
||||
val meta = Meta(builder)
|
||||
return ReadOnlyProperty { _, property ->
|
||||
val name = property.name
|
||||
install(name, factory, meta)
|
||||
val current = getOrNull(name)
|
||||
if (current == null) {
|
||||
install(name, factory, meta)
|
||||
} else if (current.meta != meta) {
|
||||
error("Meta mismatch. Current device meta: ${current.meta}, but factory meta is $meta")
|
||||
} else {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
current as D
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,9 @@ import space.kscience.controls.api.*
|
||||
import space.kscience.dataforge.names.Name
|
||||
import space.kscience.dataforge.names.plus
|
||||
|
||||
/**
|
||||
* Process a message targeted at this [Device], assuming its name is [deviceTarget].
|
||||
*/
|
||||
public suspend fun Device.respondMessage(deviceTarget: Name, request: DeviceMessage): DeviceMessage? = try {
|
||||
when (request) {
|
||||
is PropertyGetMessage -> {
|
||||
@ -66,6 +69,9 @@ public suspend fun Device.respondMessage(deviceTarget: Name, request: DeviceMess
|
||||
DeviceMessage.error(ex, sourceDevice = deviceTarget, targetDevice = request.sourceDevice)
|
||||
}
|
||||
|
||||
/**
|
||||
* Process incoming [DeviceMessage], using hub naming to evaluate target.
|
||||
*/
|
||||
public suspend fun DeviceHub.respondHubMessage(request: DeviceMessage): DeviceMessage? {
|
||||
return try {
|
||||
val targetName = request.targetDevice ?: return null
|
||||
@ -77,7 +83,7 @@ public suspend fun DeviceHub.respondHubMessage(request: DeviceMessage): DeviceMe
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect all messages from given [DeviceHub], applying proper relative names
|
||||
* Collect all messages from given [DeviceHub], applying proper relative names.
|
||||
*/
|
||||
public fun DeviceHub.hubMessageFlow(scope: CoroutineScope): Flow<DeviceMessage> {
|
||||
|
@ -9,8 +9,14 @@ import space.kscience.dataforge.context.*
|
||||
import space.kscience.dataforge.misc.Type
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
/**
|
||||
* Raw [ByteArray] port
|
||||
*/
|
||||
public interface Port : ContextAware, Socket<ByteArray>
|
||||
|
||||
/**
|
||||
* A specialized factory for [Port]
|
||||
*/
|
||||
@Type(PortFactory.TYPE)
|
||||
public interface PortFactory: Factory<Port>{
|
||||
public val type: String
|
||||
@ -20,6 +26,9 @@ public interface PortFactory: Factory<Port>{
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Common abstraction for [Port] based on [Channel]
|
||||
*/
|
||||
public abstract class AbstractPort(
|
||||
override val context: Context,
|
||||
coroutineContext: CoroutineContext = context.coroutineContext,
|
||||
@ -72,7 +81,7 @@ public abstract class AbstractPort(
|
||||
|
||||
/**
|
||||
* Raw flow of incoming data chunks. The chunks are not guaranteed to be complete phrases.
|
||||
* In order to form phrases some condition should be used on top of it.
|
||||
* In order to form phrases, some condition should be used on top of it.
|
||||
* For example [delimitedIncoming] generates phrases with fixed delimiter.
|
||||
*/
|
||||
override fun receiving(): Flow<ByteArray> = incoming.receiveAsFlow()
|
||||
|
@ -5,6 +5,9 @@ import space.kscience.dataforge.meta.Meta
|
||||
import space.kscience.dataforge.meta.string
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
/**
|
||||
* A DataForge plugin for managing ports
|
||||
*/
|
||||
public class Ports : AbstractPlugin() {
|
||||
|
||||
override val tag: PluginTag get() = Companion.tag
|
||||
@ -15,6 +18,9 @@ public class Ports : AbstractPlugin() {
|
||||
|
||||
private val portCache = mutableMapOf<Meta, Port>()
|
||||
|
||||
/**
|
||||
* Create a new [Port] according to specification
|
||||
*/
|
||||
public fun buildPort(meta: Meta): Port = portCache.getOrPut(meta) {
|
||||
val type by meta.string { error("Port type is not defined") }
|
||||
val factory = portFactories.values.firstOrNull { it.type == type }
|
||||
|
@ -14,6 +14,9 @@ import space.kscience.dataforge.meta.Meta
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
|
||||
/**
|
||||
* A base abstractions for [Device], introducing specifications for properties
|
||||
*/
|
||||
@OptIn(InternalDeviceAPI::class)
|
||||
public abstract class DeviceBase<D : DeviceBase<D>>(
|
||||
override val context: Context = Global,
|
||||
|
@ -27,7 +27,7 @@ public interface DevicePropertySpec<in D : Device, T> {
|
||||
public val descriptor: PropertyDescriptor
|
||||
|
||||
/**
|
||||
* Meta item converter for resulting type
|
||||
* Meta item converter for the resulting type
|
||||
*/
|
||||
public val converter: MetaConverter<T>
|
||||
|
||||
@ -78,7 +78,7 @@ public interface DeviceActionSpec<in D : Device, I, O> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Action name, should be unique in device
|
||||
* Action name. Should be unique in the device
|
||||
*/
|
||||
public val DeviceActionSpec<*, *, *>.name: String get() = descriptor.name
|
||||
|
||||
|
@ -12,6 +12,8 @@ import kotlin.reflect.KMutableProperty1
|
||||
import kotlin.reflect.KProperty
|
||||
import kotlin.reflect.KProperty1
|
||||
|
||||
|
||||
|
||||
@OptIn(InternalDeviceAPI::class)
|
||||
public abstract class DeviceSpec<D : Device> {
|
||||
//initializing meta property for everyone
|
||||
|
4
controls-ktor-tcp/README.md
Normal file
4
controls-ktor-tcp/README.md
Normal file
@ -0,0 +1,4 @@
|
||||
# Module controls-ktor-tcp
|
||||
|
||||
|
||||
|
32
controls-magix-client/README.md
Normal file
32
controls-magix-client/README.md
Normal file
@ -0,0 +1,32 @@
|
||||
# Module controls-magix-client
|
||||
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
## Artifact:
|
||||
|
||||
The Maven coordinates of this project are `space.kscience:controls-magix-client:0.1.1-SNAPSHOT`.
|
||||
|
||||
**Gradle Groovy:**
|
||||
```groovy
|
||||
repositories {
|
||||
maven { url 'https://repo.kotlin.link' }
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'space.kscience:controls-magix-client:0.1.1-SNAPSHOT'
|
||||
}
|
||||
```
|
||||
**Gradle Kotlin DSL:**
|
||||
```kotlin
|
||||
repositories {
|
||||
maven("https://repo.kotlin.link")
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("space.kscience:controls-magix-client:0.1.1-SNAPSHOT")
|
||||
}
|
||||
```
|
4
controls-modbus/README.md
Normal file
4
controls-modbus/README.md
Normal file
@ -0,0 +1,4 @@
|
||||
# Module controls-modbus
|
||||
|
||||
A plugin for Controls-kt device server on top of modbus-rtu/modbus-tcp protocols
|
||||
|
13
controls-modbus/build.gradle.kts
Normal file
13
controls-modbus/build.gradle.kts
Normal file
@ -0,0 +1,13 @@
|
||||
plugins {
|
||||
id("space.kscience.gradle.jvm")
|
||||
}
|
||||
|
||||
description = """
|
||||
A plugin for Controls-kt device server on top of modbus-rtu/modbus-tcp protocols
|
||||
""".trimIndent()
|
||||
|
||||
|
||||
dependencies {
|
||||
api(projects.controlsCore)
|
||||
api("com.ghgande:j2mod:3.1.1")
|
||||
}
|
@ -0,0 +1,146 @@
|
||||
package space.kscience.controls.modbus
|
||||
|
||||
import com.ghgande.j2mod.modbus.facade.AbstractModbusMaster
|
||||
import com.ghgande.j2mod.modbus.procimg.InputRegister
|
||||
import com.ghgande.j2mod.modbus.procimg.Register
|
||||
import com.ghgande.j2mod.modbus.procimg.SimpleRegister
|
||||
import com.ghgande.j2mod.modbus.util.BitVector
|
||||
import space.kscience.controls.api.Device
|
||||
import java.nio.ByteBuffer
|
||||
import kotlin.properties.ReadWriteProperty
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
|
||||
/**
|
||||
* A Modbus device backed by j2mod client
|
||||
*/
|
||||
public interface ModbusDevice : Device {
|
||||
|
||||
/**
|
||||
* Client id for this specific device
|
||||
*/
|
||||
public val clientId: Int
|
||||
|
||||
/**
|
||||
* The OPC-UA client initialized on first use
|
||||
*/
|
||||
public val master: AbstractModbusMaster
|
||||
}
|
||||
|
||||
/**
|
||||
* Read multiple sequential modbus coils (bit-values)
|
||||
*/
|
||||
public fun ModbusDevice.readCoils(ref: Int, count: Int): BitVector =
|
||||
master.readCoils(clientId, ref, count)
|
||||
|
||||
public fun ModbusDevice.readCoil(ref: Int): Boolean =
|
||||
master.readCoils(clientId, ref, 1).getBit(0)
|
||||
|
||||
public fun ModbusDevice.writeCoils(ref: Int, values: BooleanArray) {
|
||||
val bitVector = BitVector(values.size)
|
||||
values.forEachIndexed { index, value ->
|
||||
bitVector.setBit(index, value)
|
||||
}
|
||||
master.writeMultipleCoils(clientId, ref, bitVector)
|
||||
}
|
||||
|
||||
public fun ModbusDevice.writeCoil(ref: Int, value: Boolean) {
|
||||
master.writeCoil(clientId, ref, value)
|
||||
}
|
||||
|
||||
public fun ModbusDevice.readInputDiscretes(ref: Int, count: Int): BitVector =
|
||||
master.readInputDiscretes(clientId, ref, count)
|
||||
|
||||
public fun ModbusDevice.readInputRegisters(ref: Int, count: Int): List<InputRegister> =
|
||||
master.readInputRegisters(clientId, ref, count).toList()
|
||||
|
||||
private fun Array<out InputRegister>.toBuffer(): ByteBuffer {
|
||||
val buffer: ByteBuffer = ByteBuffer.allocate(size * 2)
|
||||
forEachIndexed { index, value ->
|
||||
buffer.position(index * 2)
|
||||
buffer.put(value.toBytes())
|
||||
}
|
||||
buffer.flip()
|
||||
return buffer
|
||||
}
|
||||
|
||||
public fun ModbusDevice.readInputRegistersToBuffer(ref: Int, count: Int): ByteBuffer =
|
||||
master.readInputRegisters(clientId, ref, count).toBuffer()
|
||||
|
||||
public fun ModbusDevice.readDoubleInput(ref: Int): Double =
|
||||
readInputRegistersToBuffer(ref, Double.SIZE_BYTES).getDouble()
|
||||
|
||||
public fun ModbusDevice.readShortInput(ref: Int): Short =
|
||||
readInputRegisters(ref, 1).first().toShort()
|
||||
|
||||
public fun ModbusDevice.readHoldingRegisters(ref: Int, count: Int): List<Register> =
|
||||
master.readMultipleRegisters(clientId, ref, count).toList()
|
||||
|
||||
public fun ModbusDevice.readHoldingRegistersToBuffer(ref: Int, count: Int): ByteBuffer =
|
||||
master.readMultipleRegisters(clientId, ref, count).toBuffer()
|
||||
|
||||
public fun ModbusDevice.readDoubleRegister(ref: Int): Double =
|
||||
readHoldingRegistersToBuffer(ref, Double.SIZE_BYTES).getDouble()
|
||||
|
||||
public fun ModbusDevice.readShortRegister(ref: Int): Short =
|
||||
readHoldingRegisters(ref, 1).first().toShort()
|
||||
|
||||
public fun ModbusDevice.writeHoldingRegisters(ref: Int, values: ShortArray): Int =
|
||||
master.writeMultipleRegisters(
|
||||
clientId,
|
||||
ref,
|
||||
Array<Register>(values.size) { SimpleRegister().apply { setValue(values[it]) } }
|
||||
)
|
||||
|
||||
public fun ModbusDevice.writeHoldingRegister(ref: Int, value: Short): Int =
|
||||
master.writeSingleRegister(
|
||||
clientId,
|
||||
ref,
|
||||
SimpleRegister().apply { setValue(value) }
|
||||
)
|
||||
|
||||
public fun ModbusDevice.writeHoldingRegisters(ref: Int, buffer: ByteBuffer): Int {
|
||||
val array = ShortArray(buffer.limit().floorDiv(2)) { buffer.getShort(it * 2) }
|
||||
|
||||
return writeHoldingRegisters(ref, array)
|
||||
}
|
||||
|
||||
public fun ModbusDevice.writeShortRegister(ref: Int, value: Short) {
|
||||
master.writeSingleRegister(ref, SimpleRegister().apply { setValue(value) })
|
||||
}
|
||||
|
||||
public fun ModbusDevice.modBusRegister(
|
||||
ref: Int,
|
||||
): ReadWriteProperty<ModbusDevice, Short> = object : ReadWriteProperty<ModbusDevice, Short> {
|
||||
override fun getValue(thisRef: ModbusDevice, property: KProperty<*>): Short = readShortRegister(ref)
|
||||
|
||||
override fun setValue(thisRef: ModbusDevice, property: KProperty<*>, value: Short) {
|
||||
writeHoldingRegister(ref, value)
|
||||
}
|
||||
}
|
||||
|
||||
public fun ModbusDevice.modBusDoubleRegister(
|
||||
ref: Int,
|
||||
): ReadWriteProperty<ModbusDevice, Double> = object : ReadWriteProperty<ModbusDevice, Double> {
|
||||
override fun getValue(thisRef: ModbusDevice, property: KProperty<*>): Double = readDoubleRegister(ref)
|
||||
|
||||
override fun setValue(thisRef: ModbusDevice, property: KProperty<*>, value: Double) {
|
||||
val buffer = ByteBuffer.allocate(Double.SIZE_BYTES).apply { putDouble(value) }
|
||||
writeHoldingRegisters(ref, buffer)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
//public inline fun <reified T> ModbusDevice.opcDouble(
|
||||
//): ReadWriteProperty<Any?, Double> = ma
|
||||
//
|
||||
//public inline fun <reified T> ModbusDeviceBySpec<*>.opcInt(
|
||||
// nodeId: NodeId,
|
||||
// magAge: Double = 1.0,
|
||||
//): ReadWriteProperty<Any?, Int> = opc(nodeId, MetaConverter.int, magAge)
|
||||
//
|
||||
//public inline fun <reified T> ModbusDeviceBySpec<*>.opcString(
|
||||
// nodeId: NodeId,
|
||||
// magAge: Double = 1.0,
|
||||
//): ReadWriteProperty<Any?, String> = opc(nodeId, MetaConverter.string, magAge)
|
@ -0,0 +1,45 @@
|
||||
package space.kscience.controls.modbus
|
||||
|
||||
import com.ghgande.j2mod.modbus.facade.AbstractModbusMaster
|
||||
import space.kscience.controls.api.DeviceHub
|
||||
import space.kscience.controls.spec.DeviceBySpec
|
||||
import space.kscience.controls.spec.DeviceSpec
|
||||
import space.kscience.dataforge.context.Context
|
||||
import space.kscience.dataforge.meta.Meta
|
||||
import space.kscience.dataforge.names.NameToken
|
||||
|
||||
/**
|
||||
* A variant of [DeviceBySpec] that includes Modbus RTU/TCP/UDP client
|
||||
*/
|
||||
public open class ModbusDeviceBySpec(
|
||||
context: Context,
|
||||
spec: DeviceSpec<ModbusDeviceBySpec>,
|
||||
override val clientId: Int,
|
||||
override val master: AbstractModbusMaster,
|
||||
meta: Meta = Meta.EMPTY,
|
||||
) : ModbusDevice, DeviceBySpec<ModbusDeviceBySpec>(spec, context, meta)
|
||||
|
||||
|
||||
public class ModbusHub(
|
||||
public val context: Context,
|
||||
public val masterBuilder: () -> AbstractModbusMaster,
|
||||
public val specs: Map<NameToken, Pair<Int, DeviceSpec<ModbusDeviceBySpec>>>,
|
||||
) : DeviceHub, AutoCloseable {
|
||||
|
||||
public val master: AbstractModbusMaster by lazy(masterBuilder)
|
||||
|
||||
override val devices: Map<NameToken, ModbusDevice> by lazy {
|
||||
specs.mapValues { (_, pair) ->
|
||||
ModbusDeviceBySpec(
|
||||
context,
|
||||
pair.second,
|
||||
pair.first,
|
||||
master
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
master.disconnect()
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
package space.kscience.controls.modbus
|
||||
|
||||
|
||||
public sealed class ModbusRegistryKey {
|
||||
/**
|
||||
* Read-only boolean value
|
||||
*/
|
||||
public class Coil(public val address: Int) : ModbusRegistryKey() {
|
||||
init {
|
||||
require(address in 1..9999) { "Coil address must be in 1..9999 range" }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read-write boolean value
|
||||
*/
|
||||
public class DiscreteInput(public val address: Int) : ModbusRegistryKey() {
|
||||
init {
|
||||
require(address in 10001..19999) { "DiscreteInput address must be in 10001..19999 range" }
|
||||
}
|
||||
}
|
||||
|
||||
public class InputRegister(public val address: Int) : ModbusRegistryKey() {
|
||||
init {
|
||||
require(address in 20001..29999) { "InputRegister address must be in 20001..29999 range" }
|
||||
}
|
||||
}
|
||||
|
||||
public class HoldingRegister(public val address: Int) : ModbusRegistryKey() {
|
||||
init {
|
||||
require(address in 30001..39999) { "HoldingRegister address must be in 30001..39999 range" }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class ModbusRegistryMap {
|
||||
protected fun coil(address: Int): ModbusRegistryKey.Coil = ModbusRegistryKey.Coil(address)
|
||||
|
||||
protected fun discrete(address: Int): ModbusRegistryKey.DiscreteInput = ModbusRegistryKey.DiscreteInput(address)
|
||||
|
||||
protected fun input(address: Int): ModbusRegistryKey.InputRegister = ModbusRegistryKey.InputRegister(address)
|
||||
|
||||
protected fun register(address: Int): ModbusRegistryKey.HoldingRegister = ModbusRegistryKey.HoldingRegister(address)
|
||||
}
|
4
controls-opcua/README.md
Normal file
4
controls-opcua/README.md
Normal file
@ -0,0 +1,4 @@
|
||||
# Module controls-opcua
|
||||
|
||||
|
||||
|
@ -8,10 +8,7 @@ import space.kscience.controls.spec.DeviceBySpec
|
||||
import space.kscience.controls.spec.DeviceSpec
|
||||
import space.kscience.dataforge.context.Context
|
||||
import space.kscience.dataforge.context.Global
|
||||
import space.kscience.dataforge.meta.Scheme
|
||||
import space.kscience.dataforge.meta.SchemeSpec
|
||||
import space.kscience.dataforge.meta.specOrNull
|
||||
import space.kscience.dataforge.meta.string
|
||||
import space.kscience.dataforge.meta.*
|
||||
|
||||
|
||||
public sealed class MiloIdentity: Scheme()
|
||||
@ -35,6 +32,8 @@ public class MiloConfiguration : Scheme() {
|
||||
|
||||
public var username: MiloUsername? by specOrNull(MiloUsername)
|
||||
|
||||
public var securityPolicy: SecurityPolicy by enum(SecurityPolicy.None)
|
||||
|
||||
public companion object : SchemeSpec<MiloConfiguration>(::MiloConfiguration)
|
||||
}
|
||||
|
||||
@ -50,7 +49,7 @@ public open class MiloDeviceBySpec<D : MiloDeviceBySpec<D>>(
|
||||
override val client: OpcUaClient by lazy {
|
||||
context.createMiloClient(
|
||||
config.endpointUrl,
|
||||
securityPolicy = SecurityPolicy.None,
|
||||
securityPolicy = config.securityPolicy,
|
||||
identityProvider = config.username?.let {
|
||||
UsernameProvider(it.username,it.password)
|
||||
} ?: AnonymousProvider()
|
||||
|
@ -4,7 +4,6 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId
|
||||
import org.junit.jupiter.api.Test
|
||||
import space.kscience.controls.opcua.client.OpcUaClientTest.DemoMiloDevice.Companion.randomDouble
|
||||
import space.kscience.controls.spec.DeviceSpec
|
||||
import space.kscience.controls.spec.doubleProperty
|
||||
import space.kscience.dataforge.meta.transformations.MetaConverter
|
||||
@ -21,10 +20,6 @@ class OpcUaClientTest {
|
||||
fun build(): DemoMiloDevice {
|
||||
val config = MiloConfiguration {
|
||||
endpointUrl = "opc.tcp://milo.digitalpetri.com:62541/milo"
|
||||
// username = MiloUsername{
|
||||
// username = "user1"
|
||||
// password = "password"
|
||||
// }
|
||||
}
|
||||
return DemoMiloDevice(config)
|
||||
}
|
||||
@ -41,7 +36,7 @@ class OpcUaClientTest {
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@Test
|
||||
fun testReadDouble() = runTest {
|
||||
println(DemoMiloDevice.use { randomDouble.read() })
|
||||
println(DemoMiloDevice.use { DemoMiloDevice.randomDouble.read() })
|
||||
}
|
||||
|
||||
}
|
32
controls-serial/README.md
Normal file
32
controls-serial/README.md
Normal file
@ -0,0 +1,32 @@
|
||||
# Module controls-serial
|
||||
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
## Artifact:
|
||||
|
||||
The Maven coordinates of this project are `space.kscience:controls-serial:0.1.1-SNAPSHOT`.
|
||||
|
||||
**Gradle Groovy:**
|
||||
```groovy
|
||||
repositories {
|
||||
maven { url 'https://repo.kotlin.link' }
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'space.kscience:controls-serial:0.1.1-SNAPSHOT'
|
||||
}
|
||||
```
|
||||
**Gradle Kotlin DSL:**
|
||||
```kotlin
|
||||
repositories {
|
||||
maven("https://repo.kotlin.link")
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("space.kscience:controls-serial:0.1.1-SNAPSHOT")
|
||||
}
|
||||
```
|
32
controls-server/README.md
Normal file
32
controls-server/README.md
Normal file
@ -0,0 +1,32 @@
|
||||
# Module controls-server
|
||||
|
||||
A magix event loop server with web server for visualization.
|
||||
|
||||
## Usage
|
||||
|
||||
## Artifact:
|
||||
|
||||
The Maven coordinates of this project are `space.kscience:controls-server:0.1.1-SNAPSHOT`.
|
||||
|
||||
**Gradle Groovy:**
|
||||
```groovy
|
||||
repositories {
|
||||
maven { url 'https://repo.kotlin.link' }
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'space.kscience:controls-server:0.1.1-SNAPSHOT'
|
||||
}
|
||||
```
|
||||
**Gradle Kotlin DSL:**
|
||||
```kotlin
|
||||
repositories {
|
||||
maven("https://repo.kotlin.link")
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("space.kscience:controls-server:0.1.1-SNAPSHOT")
|
||||
}
|
||||
```
|
@ -1,12 +1,32 @@
|
||||
# Description
|
||||
# Module controls-storage
|
||||
|
||||
This module provides API to store [DeviceMessages](/controls-core/src/commonMain/kotlin/ru/mipt/npm/controls/api/DeviceMessage.kt)
|
||||
from certain [DeviceManager](/controls-core/src/commonMain/kotlin/ru/mipt/npm/controls/controllers/DeviceManager.kt)
|
||||
or [MagixMessages](magix/magix-api/src/commonMain/kotlin/ru/mipt/npm/magix/api/MagixMessage.kt)
|
||||
from certain [magix server](/magix/magix-server/src/main/kotlin/ru/mipt/npm/magix/server/server.kt).
|
||||
|
||||
# Usage
|
||||
|
||||
All usage examples can be found in [VirtualCarController](/demo/car/src/main/kotlin/ru/mipt/npm/controls/demo/car/VirtualCarController.kt).
|
||||
## Usage
|
||||
|
||||
For more details, you can see comments in source code of this module.
|
||||
## Artifact:
|
||||
|
||||
The Maven coordinates of this project are `space.kscience:controls-storage:0.1.1-SNAPSHOT`.
|
||||
|
||||
**Gradle Groovy:**
|
||||
```groovy
|
||||
repositories {
|
||||
maven { url 'https://repo.kotlin.link' }
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'space.kscience:controls-storage:0.1.1-SNAPSHOT'
|
||||
}
|
||||
```
|
||||
**Gradle Kotlin DSL:**
|
||||
```kotlin
|
||||
repositories {
|
||||
maven("https://repo.kotlin.link")
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("space.kscience:controls-storage:0.1.1-SNAPSHOT")
|
||||
}
|
||||
```
|
||||
|
32
controls-storage/controls-xodus/README.md
Normal file
32
controls-storage/controls-xodus/README.md
Normal file
@ -0,0 +1,32 @@
|
||||
# Module controls-xodus
|
||||
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
## Artifact:
|
||||
|
||||
The Maven coordinates of this project are `space.kscience:controls-xodus:0.1.1-SNAPSHOT`.
|
||||
|
||||
**Gradle Groovy:**
|
||||
```groovy
|
||||
repositories {
|
||||
maven { url 'https://repo.kotlin.link' }
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'space.kscience:controls-xodus:0.1.1-SNAPSHOT'
|
||||
}
|
||||
```
|
||||
**Gradle Kotlin DSL:**
|
||||
```kotlin
|
||||
repositories {
|
||||
maven("https://repo.kotlin.link")
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("space.kscience:controls-xodus:0.1.1-SNAPSHOT")
|
||||
}
|
||||
```
|
@ -16,7 +16,7 @@ import space.kscience.controls.storage.DeviceMessageStorage
|
||||
import space.kscience.controls.storage.workDirectory
|
||||
import space.kscience.dataforge.context.Context
|
||||
import space.kscience.dataforge.context.Factory
|
||||
import space.kscience.dataforge.context.fetch
|
||||
import space.kscience.dataforge.context.request
|
||||
import space.kscience.dataforge.io.IOPlugin
|
||||
import space.kscience.dataforge.meta.Meta
|
||||
import space.kscience.dataforge.meta.get
|
||||
@ -112,7 +112,7 @@ public class XodusDeviceMessageStorage(
|
||||
public val XODUS_STORE_PROPERTY: Name = Name.of("xodus", "storagePath")
|
||||
|
||||
override fun build(context: Context, meta: Meta): XodusDeviceMessageStorage {
|
||||
val io = context.fetch(IOPlugin)
|
||||
val io = context.request(IOPlugin)
|
||||
val storePath = io.workDirectory.resolve(
|
||||
meta[XODUS_STORE_PROPERTY]?.string
|
||||
?: context.properties[XODUS_STORE_PROPERTY]?.string ?: "storage"
|
||||
|
@ -8,9 +8,6 @@ import space.kscience.dataforge.meta.string
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.Path
|
||||
|
||||
//TODO remove on DF 0.6
|
||||
|
||||
internal val IOPlugin.Companion.WORK_DIRECTORY_KEY: String get() = ".dataforge"
|
||||
|
||||
public val IOPlugin.workDirectory: Path
|
||||
get() {
|
||||
|
4
demo/README.md
Normal file
4
demo/README.md
Normal file
@ -0,0 +1,4 @@
|
||||
# Module demo
|
||||
|
||||
|
||||
|
4
demo/all-things/README.md
Normal file
4
demo/all-things/README.md
Normal file
@ -0,0 +1,4 @@
|
||||
# Module all-things
|
||||
|
||||
|
||||
|
@ -24,9 +24,9 @@ dependencies {
|
||||
|
||||
implementation("io.ktor:ktor-client-cio:$ktorVersion")
|
||||
implementation("no.tornado:tornadofx:1.7.20")
|
||||
implementation("space.kscience:plotlykt-server:0.5.3-dev-1")
|
||||
implementation("space.kscience:plotlykt-server:0.5.3")
|
||||
// implementation("com.github.Ricky12Awesome:json-schema-serialization:0.6.6")
|
||||
implementation("ch.qos.logback:logback-classic:1.2.11")
|
||||
implementation(spclibs.logback.classic)
|
||||
}
|
||||
|
||||
kotlin{
|
||||
|
4
demo/car/README.md
Normal file
4
demo/car/README.md
Normal file
@ -0,0 +1,4 @@
|
||||
# Module car
|
||||
|
||||
|
||||
|
4
demo/echo/README.md
Normal file
4
demo/echo/README.md
Normal file
@ -0,0 +1,4 @@
|
||||
# Module echo
|
||||
|
||||
|
||||
|
4
demo/magix-demo/README.md
Normal file
4
demo/magix-demo/README.md
Normal file
@ -0,0 +1,4 @@
|
||||
# Module magix-demo
|
||||
|
||||
|
||||
|
4
demo/mks-pdr900/README.md
Normal file
4
demo/mks-pdr900/README.md
Normal file
@ -0,0 +1,4 @@
|
||||
# Module mks-pdr900
|
||||
|
||||
|
||||
|
4
demo/motors/README.md
Normal file
4
demo/motors/README.md
Normal file
@ -0,0 +1,4 @@
|
||||
# Module motors
|
||||
|
||||
|
||||
|
30
docs/templates/ARTIFACT-TEMPLATE.md
vendored
Normal file
30
docs/templates/ARTIFACT-TEMPLATE.md
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
## 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}")
|
||||
}
|
||||
```
|
48
docs/templates/README-TEMPLATE.md
vendored
Normal file
48
docs/templates/README-TEMPLATE.md
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
[![JetBrains Research](https://jb.gg/badges/research.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub)
|
||||
|
||||
# Controls.kt
|
||||
|
||||
Controls.kt (former DataForge-control) is a data acquisition framework (work in progress). It is based on DataForge, a software framework for automated data processing.
|
||||
This repository contains a prototype of API and simple implementation
|
||||
of a slow control system, including a demo.
|
||||
|
||||
Controls.kt uses some concepts and modules of DataForge,
|
||||
such as `Meta` (tree-like value structure).
|
||||
|
||||
To learn more about DataForge, please consult the following URLs:
|
||||
* [Kotlin multiplatform implementation of DataForge](https://github.com/mipt-npm/dataforge-core)
|
||||
* [DataForge documentation](http://npm.mipt.ru/dataforge/)
|
||||
* [Original implementation of DataForge](https://bitbucket.org/Altavir/dataforge/src/default/)
|
||||
|
||||
DataForge-control is a [Kotlin-multiplatform](https://kotlinlang.org/docs/reference/multiplatform.html)
|
||||
application. Asynchronous operations are implemented with
|
||||
[kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) library.
|
||||
|
||||
## Materials and publications
|
||||
|
||||
* Video - [A general overview seminar](https://youtu.be/LO-qjWgXMWc)
|
||||
* Video - [A seminar about the system mechanics](https://youtu.be/wES0RV5GpoQ)
|
||||
* Article - [A Novel Solution for Controlling Hardware Components of Accelerators and Beamlines](https://www.preprints.org/manuscript/202108.0336/v1)
|
||||
|
||||
### Features
|
||||
Among other things, you can:
|
||||
- Describe devices and their properties.
|
||||
- Collect data from devices and execute arbitrary actions supported by a device.
|
||||
- Property values can be cached in the system and requested from devices as needed, asynchronously.
|
||||
- Connect devices to event bus via bidirectional message flows.
|
||||
|
||||
Example view of a demo:
|
||||
|
||||
![](docs/pictures/demo-view.png)
|
||||
|
||||
## Modules
|
||||
|
||||
${modules}
|
||||
|
||||
### `demo` module
|
||||
|
||||
The demo includes a simple mock device with a few properties changing as `sin` and `cos` of
|
||||
the current time. The device is configurable via a simple TornadoFX-based control panel.
|
||||
You can run a demo by executing `application/run` Gradle task.
|
||||
|
||||
The graphs are displayed using [plotly.kt](https://github.com/mipt-npm/plotly.kt) library.
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,5 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
4
magix/README.md
Normal file
4
magix/README.md
Normal file
@ -0,0 +1,4 @@
|
||||
# Module magix
|
||||
|
||||
|
||||
|
32
magix/magix-api/README.md
Normal file
32
magix/magix-api/README.md
Normal file
@ -0,0 +1,32 @@
|
||||
# Module magix-api
|
||||
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
## Artifact:
|
||||
|
||||
The Maven coordinates of this project are `space.kscience:magix-api:0.1.1-SNAPSHOT`.
|
||||
|
||||
**Gradle Groovy:**
|
||||
```groovy
|
||||
repositories {
|
||||
maven { url 'https://repo.kotlin.link' }
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'space.kscience:magix-api:0.1.1-SNAPSHOT'
|
||||
}
|
||||
```
|
||||
**Gradle Kotlin DSL:**
|
||||
```kotlin
|
||||
repositories {
|
||||
maven("https://repo.kotlin.link")
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("space.kscience:magix-api:0.1.1-SNAPSHOT")
|
||||
}
|
||||
```
|
32
magix/magix-java-client/README.md
Normal file
32
magix/magix-java-client/README.md
Normal file
@ -0,0 +1,32 @@
|
||||
# Module magix-java-client
|
||||
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
## Artifact:
|
||||
|
||||
The Maven coordinates of this project are `space.kscience:magix-java-client:0.1.1-SNAPSHOT`.
|
||||
|
||||
**Gradle Groovy:**
|
||||
```groovy
|
||||
repositories {
|
||||
maven { url 'https://repo.kotlin.link' }
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'space.kscience:magix-java-client:0.1.1-SNAPSHOT'
|
||||
}
|
||||
```
|
||||
**Gradle Kotlin DSL:**
|
||||
```kotlin
|
||||
repositories {
|
||||
maven("https://repo.kotlin.link")
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("space.kscience:magix-java-client:0.1.1-SNAPSHOT")
|
||||
}
|
||||
```
|
32
magix/magix-mqtt/README.md
Normal file
32
magix/magix-mqtt/README.md
Normal file
@ -0,0 +1,32 @@
|
||||
# Module magix-mqtt
|
||||
|
||||
MQTT client magix endpoint
|
||||
|
||||
## Usage
|
||||
|
||||
## Artifact:
|
||||
|
||||
The Maven coordinates of this project are `space.kscience:magix-mqtt:0.1.1-SNAPSHOT`.
|
||||
|
||||
**Gradle Groovy:**
|
||||
```groovy
|
||||
repositories {
|
||||
maven { url 'https://repo.kotlin.link' }
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'space.kscience:magix-mqtt:0.1.1-SNAPSHOT'
|
||||
}
|
||||
```
|
||||
**Gradle Kotlin DSL:**
|
||||
```kotlin
|
||||
repositories {
|
||||
maven("https://repo.kotlin.link")
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("space.kscience:magix-mqtt:0.1.1-SNAPSHOT")
|
||||
}
|
||||
```
|
32
magix/magix-rabbit/README.md
Normal file
32
magix/magix-rabbit/README.md
Normal file
@ -0,0 +1,32 @@
|
||||
# Module magix-rabbit
|
||||
|
||||
RabbitMQ client magix endpoint
|
||||
|
||||
## Usage
|
||||
|
||||
## Artifact:
|
||||
|
||||
The Maven coordinates of this project are `space.kscience:magix-rabbit:0.1.1-SNAPSHOT`.
|
||||
|
||||
**Gradle Groovy:**
|
||||
```groovy
|
||||
repositories {
|
||||
maven { url 'https://repo.kotlin.link' }
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'space.kscience:magix-rabbit:0.1.1-SNAPSHOT'
|
||||
}
|
||||
```
|
||||
**Gradle Kotlin DSL:**
|
||||
```kotlin
|
||||
repositories {
|
||||
maven("https://repo.kotlin.link")
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("space.kscience:magix-rabbit:0.1.1-SNAPSHOT")
|
||||
}
|
||||
```
|
32
magix/magix-rsocket/README.md
Normal file
32
magix/magix-rsocket/README.md
Normal file
@ -0,0 +1,32 @@
|
||||
# Module magix-rsocket
|
||||
|
||||
Magix endpoint (client) based on RSocket
|
||||
|
||||
## Usage
|
||||
|
||||
## Artifact:
|
||||
|
||||
The Maven coordinates of this project are `space.kscience:magix-rsocket:0.1.1-SNAPSHOT`.
|
||||
|
||||
**Gradle Groovy:**
|
||||
```groovy
|
||||
repositories {
|
||||
maven { url 'https://repo.kotlin.link' }
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'space.kscience:magix-rsocket:0.1.1-SNAPSHOT'
|
||||
}
|
||||
```
|
||||
**Gradle Kotlin DSL:**
|
||||
```kotlin
|
||||
repositories {
|
||||
maven("https://repo.kotlin.link")
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("space.kscience:magix-rsocket:0.1.1-SNAPSHOT")
|
||||
}
|
||||
```
|
32
magix/magix-server/README.md
Normal file
32
magix/magix-server/README.md
Normal file
@ -0,0 +1,32 @@
|
||||
# Module magix-server
|
||||
|
||||
A magix event loop implementation in Kotlin. Includes HTTP/SSE and RSocket routes.
|
||||
|
||||
## Usage
|
||||
|
||||
## Artifact:
|
||||
|
||||
The Maven coordinates of this project are `space.kscience:magix-server:0.1.1-SNAPSHOT`.
|
||||
|
||||
**Gradle Groovy:**
|
||||
```groovy
|
||||
repositories {
|
||||
maven { url 'https://repo.kotlin.link' }
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'space.kscience:magix-server:0.1.1-SNAPSHOT'
|
||||
}
|
||||
```
|
||||
**Gradle Kotlin DSL:**
|
||||
```kotlin
|
||||
repositories {
|
||||
maven("https://repo.kotlin.link")
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("space.kscience:magix-server:0.1.1-SNAPSHOT")
|
||||
}
|
||||
```
|
4
magix/magix-storage/README.md
Normal file
4
magix/magix-storage/README.md
Normal file
@ -0,0 +1,4 @@
|
||||
# Module magix-storage
|
||||
|
||||
|
||||
|
32
magix/magix-storage/magix-storage-xodus/README.md
Normal file
32
magix/magix-storage/magix-storage-xodus/README.md
Normal file
@ -0,0 +1,32 @@
|
||||
# Module magix-storage-xodus
|
||||
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
## Artifact:
|
||||
|
||||
The Maven coordinates of this project are `space.kscience:magix-storage-xodus:0.1.1-SNAPSHOT`.
|
||||
|
||||
**Gradle Groovy:**
|
||||
```groovy
|
||||
repositories {
|
||||
maven { url 'https://repo.kotlin.link' }
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'space.kscience:magix-storage-xodus:0.1.1-SNAPSHOT'
|
||||
}
|
||||
```
|
||||
**Gradle Kotlin DSL:**
|
||||
```kotlin
|
||||
repositories {
|
||||
maven("https://repo.kotlin.link")
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("space.kscience:magix-storage-xodus:0.1.1-SNAPSHOT")
|
||||
}
|
||||
```
|
32
magix/magix-zmq/README.md
Normal file
32
magix/magix-zmq/README.md
Normal file
@ -0,0 +1,32 @@
|
||||
# Module magix-zmq
|
||||
|
||||
ZMQ client endpoint for Magix
|
||||
|
||||
## Usage
|
||||
|
||||
## Artifact:
|
||||
|
||||
The Maven coordinates of this project are `space.kscience:magix-zmq:0.1.1-SNAPSHOT`.
|
||||
|
||||
**Gradle Groovy:**
|
||||
```groovy
|
||||
repositories {
|
||||
maven { url 'https://repo.kotlin.link' }
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'space.kscience:magix-zmq:0.1.1-SNAPSHOT'
|
||||
}
|
||||
```
|
||||
**Gradle Kotlin DSL:**
|
||||
```kotlin
|
||||
repositories {
|
||||
maven("https://repo.kotlin.link")
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("space.kscience:magix-zmq:0.1.1-SNAPSHOT")
|
||||
}
|
||||
```
|
@ -45,6 +45,7 @@ include(
|
||||
":controls-serial",
|
||||
":controls-server",
|
||||
":controls-opcua",
|
||||
":controls-modbus",
|
||||
// ":controls-mongo",
|
||||
":controls-storage",
|
||||
":controls-storage:controls-xodus",
|
||||
|
Loading…
Reference in New Issue
Block a user