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")
|
||||||
|
}
|
164
README.md
164
README.md
@ -7,14 +7,12 @@ This repository contains a prototype of API and simple implementation
|
|||||||
of a slow control system, including a demo.
|
of a slow control system, including a demo.
|
||||||
|
|
||||||
Controls.kt uses some concepts and modules of DataForge,
|
Controls.kt uses some concepts and modules of DataForge,
|
||||||
such as `Meta` (immutable tree-like structure) and `Meta` (which
|
such as `Meta` (tree-like value structure).
|
||||||
includes a scalar value, or a tree of values, easily convertable to/from JSON
|
|
||||||
if needed).
|
|
||||||
|
|
||||||
To learn more about DataForge, please consult the following URLs:
|
To learn more about DataForge, please consult the following URLs:
|
||||||
* [Kotlin multiplatform implementation of DataForge](https://github.com/mipt-npm/dataforge-core)
|
* [Kotlin multiplatform implementation of DataForge](https://github.com/mipt-npm/dataforge-core)
|
||||||
* [DataForge documentation](http://npm.mipt.ru/dataforge/)
|
* [DataForge documentation](http://npm.mipt.ru/dataforge/)
|
||||||
* [Original implementation of DataForge](https://bitbucket.org/Altavir/dataforge/src/default/)
|
* [Original implementation of DataForge](https://bitbucket.org/Altavir/dataforge/src/default/)
|
||||||
|
|
||||||
DataForge-control is a [Kotlin-multiplatform](https://kotlinlang.org/docs/reference/multiplatform.html)
|
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
|
||||||
@ -33,19 +31,149 @@ Among other things, you can:
|
|||||||
- Property values can be cached in the system and requested from devices as needed, asynchronously.
|
- Property values can be cached in the system and requested from devices as needed, asynchronously.
|
||||||
- Connect devices to event bus via bidirectional message flows.
|
- 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
|
![](docs/pictures/demo-view.png)
|
||||||
[`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).
|
|
||||||
|
|
||||||
- `base` - contains baseline `Device` implementation
|
## Modules
|
||||||
[`DeviceBase`](controls-core/src/commonMain/kotlin/ru/mipt/npm/controls/base/DeviceBase.kt)
|
|
||||||
and property implementation, including property asynchronous flows.
|
|
||||||
|
### [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
|
### `demo` module
|
||||||
|
|
||||||
@ -54,7 +182,3 @@ the current time. The device is configurable via a simple TornadoFX-based contro
|
|||||||
You can run a demo by executing `application/run` Gradle task.
|
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.
|
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")
|
space("https://maven.pkg.jetbrains.space/spc/p/controls/maven")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
readme.readmeTemplate = file("docs/templates/README-TEMPLATE.md")
|
||||||
|
|
||||||
apiValidation {
|
apiValidation {
|
||||||
validationDisabled = true
|
validationDisabled = true
|
||||||
}
|
}
|
@ -18,3 +18,28 @@ kscience {
|
|||||||
api(spclibs.kotlinx.datetime)
|
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
|
package space.kscience.controls.api
|
||||||
|
|
||||||
import io.ktor.utils.io.core.Closeable
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.cancel
|
import kotlinx.coroutines.cancel
|
||||||
@ -17,10 +16,11 @@ import space.kscience.dataforge.names.Name
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* General interface describing a managed Device.
|
* 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)
|
@Type(DEVICE_TARGET)
|
||||||
public interface Device : Closeable, ContextAware, CoroutineScope {
|
public interface Device : AutoCloseable, ContextAware, CoroutineScope {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initial configuration meta for the device
|
* Initial configuration meta for the device
|
||||||
@ -97,9 +97,8 @@ public suspend fun Device.getOrReadProperty(propertyName: String): Meta =
|
|||||||
getProperty(propertyName) ?: readProperty(propertyName)
|
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 {
|
public fun Device.getAllProperties(): Meta = Meta {
|
||||||
for (descriptor in propertyDescriptors) {
|
for (descriptor in propertyDescriptors) {
|
||||||
|
@ -3,6 +3,7 @@ package space.kscience.controls.manager
|
|||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import space.kscience.controls.api.Device
|
import space.kscience.controls.api.Device
|
||||||
import space.kscience.controls.api.DeviceHub
|
import space.kscience.controls.api.DeviceHub
|
||||||
|
import space.kscience.controls.api.getOrNull
|
||||||
import space.kscience.dataforge.context.*
|
import space.kscience.dataforge.context.*
|
||||||
import space.kscience.dataforge.meta.Meta
|
import space.kscience.dataforge.meta.Meta
|
||||||
import space.kscience.dataforge.meta.MutableMeta
|
import space.kscience.dataforge.meta.MutableMeta
|
||||||
@ -12,6 +13,9 @@ import kotlin.collections.set
|
|||||||
import kotlin.properties.ReadOnlyProperty
|
import kotlin.properties.ReadOnlyProperty
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DataForge Context plugin that allows to manage devices locally
|
||||||
|
*/
|
||||||
public class DeviceManager : AbstractPlugin(), DeviceHub {
|
public class DeviceManager : AbstractPlugin(), DeviceHub {
|
||||||
override val tag: PluginTag get() = Companion.tag
|
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 {
|
public fun <D : Device> DeviceManager.install(name: String, factory: Factory<D>, meta: Meta = Meta.EMPTY): D {
|
||||||
val device = factory(meta, context)
|
val device = factory(meta, context)
|
||||||
registerDevice(NameToken(name), device)
|
registerDevice(NameToken(name), device)
|
||||||
@ -45,6 +52,9 @@ public fun <D : Device> DeviceManager.install(name: String, factory: Factory<D>,
|
|||||||
return device
|
return device
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A delegate that initializes device on the first use
|
||||||
|
*/
|
||||||
public inline fun <D : Device> DeviceManager.installing(
|
public inline fun <D : Device> DeviceManager.installing(
|
||||||
factory: Factory<D>,
|
factory: Factory<D>,
|
||||||
builder: MutableMeta.() -> Unit = {},
|
builder: MutableMeta.() -> Unit = {},
|
||||||
@ -52,7 +62,15 @@ public inline fun <D : Device> DeviceManager.installing(
|
|||||||
val meta = Meta(builder)
|
val meta = Meta(builder)
|
||||||
return ReadOnlyProperty { _, property ->
|
return ReadOnlyProperty { _, property ->
|
||||||
val name = property.name
|
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.Name
|
||||||
import space.kscience.dataforge.names.plus
|
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 {
|
public suspend fun Device.respondMessage(deviceTarget: Name, request: DeviceMessage): DeviceMessage? = try {
|
||||||
when (request) {
|
when (request) {
|
||||||
is PropertyGetMessage -> {
|
is PropertyGetMessage -> {
|
||||||
@ -66,6 +69,9 @@ public suspend fun Device.respondMessage(deviceTarget: Name, request: DeviceMess
|
|||||||
DeviceMessage.error(ex, sourceDevice = deviceTarget, targetDevice = request.sourceDevice)
|
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? {
|
public suspend fun DeviceHub.respondHubMessage(request: DeviceMessage): DeviceMessage? {
|
||||||
return try {
|
return try {
|
||||||
val targetName = request.targetDevice ?: return null
|
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> {
|
public fun DeviceHub.hubMessageFlow(scope: CoroutineScope): Flow<DeviceMessage> {
|
||||||
|
|
@ -9,8 +9,14 @@ import space.kscience.dataforge.context.*
|
|||||||
import space.kscience.dataforge.misc.Type
|
import space.kscience.dataforge.misc.Type
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Raw [ByteArray] port
|
||||||
|
*/
|
||||||
public interface Port : ContextAware, Socket<ByteArray>
|
public interface Port : ContextAware, Socket<ByteArray>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A specialized factory for [Port]
|
||||||
|
*/
|
||||||
@Type(PortFactory.TYPE)
|
@Type(PortFactory.TYPE)
|
||||||
public interface PortFactory: Factory<Port>{
|
public interface PortFactory: Factory<Port>{
|
||||||
public val type: String
|
public val type: String
|
||||||
@ -20,6 +26,9 @@ public interface PortFactory: Factory<Port>{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Common abstraction for [Port] based on [Channel]
|
||||||
|
*/
|
||||||
public abstract class AbstractPort(
|
public abstract class AbstractPort(
|
||||||
override val context: Context,
|
override val context: Context,
|
||||||
coroutineContext: CoroutineContext = context.coroutineContext,
|
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.
|
* 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.
|
* For example [delimitedIncoming] generates phrases with fixed delimiter.
|
||||||
*/
|
*/
|
||||||
override fun receiving(): Flow<ByteArray> = incoming.receiveAsFlow()
|
override fun receiving(): Flow<ByteArray> = incoming.receiveAsFlow()
|
||||||
|
@ -5,6 +5,9 @@ import space.kscience.dataforge.meta.Meta
|
|||||||
import space.kscience.dataforge.meta.string
|
import space.kscience.dataforge.meta.string
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A DataForge plugin for managing ports
|
||||||
|
*/
|
||||||
public class Ports : AbstractPlugin() {
|
public class Ports : AbstractPlugin() {
|
||||||
|
|
||||||
override val tag: PluginTag get() = Companion.tag
|
override val tag: PluginTag get() = Companion.tag
|
||||||
@ -15,6 +18,9 @@ public class Ports : AbstractPlugin() {
|
|||||||
|
|
||||||
private val portCache = mutableMapOf<Meta, Port>()
|
private val portCache = mutableMapOf<Meta, Port>()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new [Port] according to specification
|
||||||
|
*/
|
||||||
public fun buildPort(meta: Meta): Port = portCache.getOrPut(meta) {
|
public fun buildPort(meta: Meta): Port = portCache.getOrPut(meta) {
|
||||||
val type by meta.string { error("Port type is not defined") }
|
val type by meta.string { error("Port type is not defined") }
|
||||||
val factory = portFactories.values.firstOrNull { it.type == type }
|
val factory = portFactories.values.firstOrNull { it.type == type }
|
||||||
|
@ -14,6 +14,9 @@ import space.kscience.dataforge.meta.Meta
|
|||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A base abstractions for [Device], introducing specifications for properties
|
||||||
|
*/
|
||||||
@OptIn(InternalDeviceAPI::class)
|
@OptIn(InternalDeviceAPI::class)
|
||||||
public abstract class DeviceBase<D : DeviceBase<D>>(
|
public abstract class DeviceBase<D : DeviceBase<D>>(
|
||||||
override val context: Context = Global,
|
override val context: Context = Global,
|
||||||
|
@ -27,7 +27,7 @@ public interface DevicePropertySpec<in D : Device, T> {
|
|||||||
public val descriptor: PropertyDescriptor
|
public val descriptor: PropertyDescriptor
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Meta item converter for resulting type
|
* Meta item converter for the resulting type
|
||||||
*/
|
*/
|
||||||
public val converter: MetaConverter<T>
|
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
|
public val DeviceActionSpec<*, *, *>.name: String get() = descriptor.name
|
||||||
|
|
||||||
|
@ -12,6 +12,8 @@ import kotlin.reflect.KMutableProperty1
|
|||||||
import kotlin.reflect.KProperty
|
import kotlin.reflect.KProperty
|
||||||
import kotlin.reflect.KProperty1
|
import kotlin.reflect.KProperty1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@OptIn(InternalDeviceAPI::class)
|
@OptIn(InternalDeviceAPI::class)
|
||||||
public abstract class DeviceSpec<D : Device> {
|
public abstract class DeviceSpec<D : Device> {
|
||||||
//initializing meta property for everyone
|
//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.controls.spec.DeviceSpec
|
||||||
import space.kscience.dataforge.context.Context
|
import space.kscience.dataforge.context.Context
|
||||||
import space.kscience.dataforge.context.Global
|
import space.kscience.dataforge.context.Global
|
||||||
import space.kscience.dataforge.meta.Scheme
|
import space.kscience.dataforge.meta.*
|
||||||
import space.kscience.dataforge.meta.SchemeSpec
|
|
||||||
import space.kscience.dataforge.meta.specOrNull
|
|
||||||
import space.kscience.dataforge.meta.string
|
|
||||||
|
|
||||||
|
|
||||||
public sealed class MiloIdentity: Scheme()
|
public sealed class MiloIdentity: Scheme()
|
||||||
@ -35,6 +32,8 @@ public class MiloConfiguration : Scheme() {
|
|||||||
|
|
||||||
public var username: MiloUsername? by specOrNull(MiloUsername)
|
public var username: MiloUsername? by specOrNull(MiloUsername)
|
||||||
|
|
||||||
|
public var securityPolicy: SecurityPolicy by enum(SecurityPolicy.None)
|
||||||
|
|
||||||
public companion object : SchemeSpec<MiloConfiguration>(::MiloConfiguration)
|
public companion object : SchemeSpec<MiloConfiguration>(::MiloConfiguration)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,7 +49,7 @@ public open class MiloDeviceBySpec<D : MiloDeviceBySpec<D>>(
|
|||||||
override val client: OpcUaClient by lazy {
|
override val client: OpcUaClient by lazy {
|
||||||
context.createMiloClient(
|
context.createMiloClient(
|
||||||
config.endpointUrl,
|
config.endpointUrl,
|
||||||
securityPolicy = SecurityPolicy.None,
|
securityPolicy = config.securityPolicy,
|
||||||
identityProvider = config.username?.let {
|
identityProvider = config.username?.let {
|
||||||
UsernameProvider(it.username,it.password)
|
UsernameProvider(it.username,it.password)
|
||||||
} ?: AnonymousProvider()
|
} ?: AnonymousProvider()
|
||||||
|
@ -4,7 +4,6 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
|
|||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId
|
import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId
|
||||||
import org.junit.jupiter.api.Test
|
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.DeviceSpec
|
||||||
import space.kscience.controls.spec.doubleProperty
|
import space.kscience.controls.spec.doubleProperty
|
||||||
import space.kscience.dataforge.meta.transformations.MetaConverter
|
import space.kscience.dataforge.meta.transformations.MetaConverter
|
||||||
@ -21,10 +20,6 @@ class OpcUaClientTest {
|
|||||||
fun build(): DemoMiloDevice {
|
fun build(): DemoMiloDevice {
|
||||||
val config = MiloConfiguration {
|
val config = MiloConfiguration {
|
||||||
endpointUrl = "opc.tcp://milo.digitalpetri.com:62541/milo"
|
endpointUrl = "opc.tcp://milo.digitalpetri.com:62541/milo"
|
||||||
// username = MiloUsername{
|
|
||||||
// username = "user1"
|
|
||||||
// password = "password"
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
return DemoMiloDevice(config)
|
return DemoMiloDevice(config)
|
||||||
}
|
}
|
||||||
@ -41,7 +36,7 @@ class OpcUaClientTest {
|
|||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
@Test
|
@Test
|
||||||
fun testReadDouble() = runTest {
|
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.controls.storage.workDirectory
|
||||||
import space.kscience.dataforge.context.Context
|
import space.kscience.dataforge.context.Context
|
||||||
import space.kscience.dataforge.context.Factory
|
import space.kscience.dataforge.context.Factory
|
||||||
import space.kscience.dataforge.context.fetch
|
import space.kscience.dataforge.context.request
|
||||||
import space.kscience.dataforge.io.IOPlugin
|
import space.kscience.dataforge.io.IOPlugin
|
||||||
import space.kscience.dataforge.meta.Meta
|
import space.kscience.dataforge.meta.Meta
|
||||||
import space.kscience.dataforge.meta.get
|
import space.kscience.dataforge.meta.get
|
||||||
@ -112,7 +112,7 @@ public class XodusDeviceMessageStorage(
|
|||||||
public val XODUS_STORE_PROPERTY: Name = Name.of("xodus", "storagePath")
|
public val XODUS_STORE_PROPERTY: Name = Name.of("xodus", "storagePath")
|
||||||
|
|
||||||
override fun build(context: Context, meta: Meta): XodusDeviceMessageStorage {
|
override fun build(context: Context, meta: Meta): XodusDeviceMessageStorage {
|
||||||
val io = context.fetch(IOPlugin)
|
val io = context.request(IOPlugin)
|
||||||
val storePath = io.workDirectory.resolve(
|
val storePath = io.workDirectory.resolve(
|
||||||
meta[XODUS_STORE_PROPERTY]?.string
|
meta[XODUS_STORE_PROPERTY]?.string
|
||||||
?: context.properties[XODUS_STORE_PROPERTY]?.string ?: "storage"
|
?: context.properties[XODUS_STORE_PROPERTY]?.string ?: "storage"
|
||||||
|
@ -8,9 +8,6 @@ import space.kscience.dataforge.meta.string
|
|||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import kotlin.io.path.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
|
public val IOPlugin.workDirectory: Path
|
||||||
get() {
|
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("io.ktor:ktor-client-cio:$ktorVersion")
|
||||||
implementation("no.tornado:tornadofx:1.7.20")
|
implementation("no.tornado:tornadofx:1.7.20")
|
||||||
implementation("space.kscience:plotlykt-server:0.5.3-dev-1")
|
implementation("space.kscience:plotlykt-server:0.5.3")
|
||||||
// implementation("com.github.Ricky12Awesome:json-schema-serialization:0.6.6")
|
// implementation("com.github.Ricky12Awesome:json-schema-serialization:0.6.6")
|
||||||
implementation("ch.qos.logback:logback-classic:1.2.11")
|
implementation(spclibs.logback.classic)
|
||||||
}
|
}
|
||||||
|
|
||||||
kotlin{
|
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
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
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
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
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-serial",
|
||||||
":controls-server",
|
":controls-server",
|
||||||
":controls-opcua",
|
":controls-opcua",
|
||||||
|
":controls-modbus",
|
||||||
// ":controls-mongo",
|
// ":controls-mongo",
|
||||||
":controls-storage",
|
":controls-storage",
|
||||||
":controls-storage:controls-xodus",
|
":controls-storage:controls-xodus",
|
||||||
|
Loading…
Reference in New Issue
Block a user