From 7f71d0c9e998eab4c27873071c9668a31cd74e50 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Fri, 20 Oct 2023 10:14:14 +0300 Subject: [PATCH] modbus registry to json rendering --- build.gradle.kts | 14 +- .../space/kscience/controls/ports/phrases.kt | 5 + controls-modbus/build.gradle.kts | 2 +- .../controls/modbus/ModbusRegistryMap.kt | 129 +++++++++++++----- gradle.properties | 2 +- 5 files changed, 107 insertions(+), 45 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index f88ec4b..347a66e 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,4 +1,3 @@ -import space.kscience.gradle.isInDevelopment import space.kscience.gradle.useApache2Licence import space.kscience.gradle.useSPCTeam @@ -14,25 +13,18 @@ val xodusVersion by extra("2.0.1") allprojects { group = "space.kscience" - version = "0.2.2-dev-2" + version = "0.2.2-dev-3" repositories{ maven("https://maven.pkg.jetbrains.space/spc/p/sci/dev") } } ksciencePublish { - pom("https://github.com/SciProgCentre/controls.kt") { + pom("https://github.com/SciProgCentre/controls-kt") { useApache2Licence() useSPCTeam() } - github("controls.kt", "SciProgCentre") - space( - if (isInDevelopment) { - "https://maven.pkg.jetbrains.space/spc/p/sci/dev" - } else { - "https://maven.pkg.jetbrains.space/spc/p/sci/maven" - } - ) + repository("spc","https://maven.sciprog.center/kscience") sonatype("https://oss.sonatype.org") } diff --git a/controls-core/src/commonMain/kotlin/space/kscience/controls/ports/phrases.kt b/controls-core/src/commonMain/kotlin/space/kscience/controls/ports/phrases.kt index 1214d01..02a0058 100644 --- a/controls-core/src/commonMain/kotlin/space/kscience/controls/ports/phrases.kt +++ b/controls-core/src/commonMain/kotlin/space/kscience/controls/ports/phrases.kt @@ -5,6 +5,7 @@ import io.ktor.utils.io.core.readBytes import io.ktor.utils.io.core.reset import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.onCompletion import kotlinx.coroutines.flow.transform /** @@ -16,6 +17,10 @@ public fun Flow.withDelimiter(delimiter: ByteArray): Flow val output = BytePacketBuilder() var matcherPosition = 0 + onCompletion { + output.close() + } + return transform { chunk -> chunk.forEach { byte -> output.writeByte(byte) diff --git a/controls-modbus/build.gradle.kts b/controls-modbus/build.gradle.kts index aee64d5..1ec39d6 100644 --- a/controls-modbus/build.gradle.kts +++ b/controls-modbus/build.gradle.kts @@ -12,7 +12,7 @@ description = """ dependencies { api(projects.controlsCore) - api("com.ghgande:j2mod:3.1.1") + api("com.ghgande:j2mod:3.2.0") } readme{ diff --git a/controls-modbus/src/main/kotlin/space/kscience/controls/modbus/ModbusRegistryMap.kt b/controls-modbus/src/main/kotlin/space/kscience/controls/modbus/ModbusRegistryMap.kt index 6e3c1da..1d81d1b 100644 --- a/controls-modbus/src/main/kotlin/space/kscience/controls/modbus/ModbusRegistryMap.kt +++ b/controls-modbus/src/main/kotlin/space/kscience/controls/modbus/ModbusRegistryMap.kt @@ -1,8 +1,15 @@ package space.kscience.controls.modbus +import kotlinx.serialization.json.JsonArray +import kotlinx.serialization.json.buildJsonArray +import kotlinx.serialization.json.buildJsonObject +import kotlinx.serialization.json.put import space.kscience.dataforge.io.IOFormat +/** + * Modbus registry key + */ public sealed class ModbusRegistryKey { public abstract val address: Int public open val count: Int = 1 @@ -25,6 +32,9 @@ public sealed class ModbusRegistryKey { override fun toString(): String = "InputRegister(address=$address)" } + /** + * A range of read-only register encoding a single value + */ public class InputRange( address: Int, override val count: Int, @@ -36,10 +46,16 @@ public sealed class ModbusRegistryKey { } + /** + * A single read-write register + */ public open class HoldingRegister(override val address: Int) : ModbusRegistryKey() { override fun toString(): String = "HoldingRegister(address=$address)" } + /** + * A range of read-write registers encoding a single value + */ public class HoldingRange( address: Int, override val count: Int, @@ -52,6 +68,9 @@ public sealed class ModbusRegistryKey { } } +/** + * A base class for modbus registers + */ public abstract class ModbusRegistryMap { private val _entries: MutableMap = mutableMapOf() @@ -63,36 +82,56 @@ public abstract class ModbusRegistryMap { return key } + /** + * Register a [ModbusRegistryKey.Coil] key and return it + */ protected fun coil(address: Int, description: String = ""): ModbusRegistryKey.Coil = register(ModbusRegistryKey.Coil(address), description) + /** + * Register a [ModbusRegistryKey.DiscreteInput] key and return it + */ protected fun discrete(address: Int, description: String = ""): ModbusRegistryKey.DiscreteInput = register(ModbusRegistryKey.DiscreteInput(address), description) + /** + * Register a [ModbusRegistryKey.InputRegister] key and return it + */ protected fun input(address: Int, description: String = ""): ModbusRegistryKey.InputRegister = register(ModbusRegistryKey.InputRegister(address), description) + /** + * Register a [ModbusRegistryKey.InputRange] key and return it + */ protected fun input( address: Int, count: Int, reader: IOFormat, description: String = "", - ): ModbusRegistryKey.InputRange = - register(ModbusRegistryKey.InputRange(address, count, reader), description) + ): ModbusRegistryKey.InputRange = register(ModbusRegistryKey.InputRange(address, count, reader), description) + /** + * Register a [ModbusRegistryKey.HoldingRegister] key and return it + */ protected fun register(address: Int, description: String = ""): ModbusRegistryKey.HoldingRegister = register(ModbusRegistryKey.HoldingRegister(address), description) + /** + * Register a [ModbusRegistryKey.HoldingRange] key and return it + */ protected fun register( address: Int, count: Int, format: IOFormat, description: String = "", - ): ModbusRegistryKey.HoldingRange = - register(ModbusRegistryKey.HoldingRange(address, count, format), description) + ): ModbusRegistryKey.HoldingRange = register(ModbusRegistryKey.HoldingRange(address, count, format), description) public companion object { + + /** + * Validate the register map. Throw an error if the map is invalid + */ public fun validate(map: ModbusRegistryMap) { var lastCoil: ModbusRegistryKey.Coil? = null var lastDiscreteInput: ModbusRegistryKey.DiscreteInput? = null @@ -127,36 +166,62 @@ public abstract class ModbusRegistryMap { } } - private val ModbusRegistryKey.sectionNumber - get() = when (this) { - is ModbusRegistryKey.Coil -> 1 - is ModbusRegistryKey.DiscreteInput -> 2 - is ModbusRegistryKey.HoldingRegister -> 4 - is ModbusRegistryKey.InputRegister -> 3 - } + } +} - public fun print(map: ModbusRegistryMap, to: Appendable = System.out) { - validate(map) - map.entries.entries - .sortedWith( - Comparator.comparingInt?> { it.key.sectionNumber } - .thenComparingInt { it.key.address } - ) - .forEach { (key, description) -> - val typeString = when (key) { - is ModbusRegistryKey.Coil -> "Coil" - is ModbusRegistryKey.DiscreteInput -> "Discrete" - is ModbusRegistryKey.HoldingRegister -> "Register" - is ModbusRegistryKey.InputRegister -> "Input" - } - val rangeString = if (key.count == 1) { - key.address.toString() - } else { - "${key.address} - ${key.address + key.count - 1}" - } - to.appendLine("${typeString}\t$rangeString\t$description") - } +private val ModbusRegistryKey.sectionNumber + get() = when (this) { + is ModbusRegistryKey.Coil -> 1 + is ModbusRegistryKey.DiscreteInput -> 2 + is ModbusRegistryKey.HoldingRegister -> 4 + is ModbusRegistryKey.InputRegister -> 3 + } + +public fun ModbusRegistryMap.print(to: Appendable = System.out) { + ModbusRegistryMap.validate(this) + entries.entries + .sortedWith( + Comparator.comparingInt?> { it.key.sectionNumber } + .thenComparingInt { it.key.address } + ) + .forEach { (key, description) -> + val typeString = when (key) { + is ModbusRegistryKey.Coil -> "Coil" + is ModbusRegistryKey.DiscreteInput -> "Discrete" + is ModbusRegistryKey.HoldingRegister -> "Register" + is ModbusRegistryKey.InputRegister -> "Input" + } + val rangeString = if (key.count == 1) { + key.address.toString() + } else { + "${key.address} - ${key.address + key.count - 1}" + } + to.appendLine("${typeString}\t$rangeString\t$description") } +} + +public fun ModbusRegistryMap.toJson(): JsonArray = buildJsonArray { + ModbusRegistryMap.validate(this@toJson) + entries.forEach { (key, description) -> + + val entry = buildJsonObject { + put( + "type", + when (key) { + is ModbusRegistryKey.Coil -> "Coil" + is ModbusRegistryKey.DiscreteInput -> "Discrete" + is ModbusRegistryKey.HoldingRegister -> "Register" + is ModbusRegistryKey.InputRegister -> "Input" + } + ) + put("address", key.address) + if (key.count > 1) { + put("count", key.count) + } + put("description", description) + } + + add(entry) } } diff --git a/gradle.properties b/gradle.properties index 5b956f1..c7e0d88 100644 --- a/gradle.properties +++ b/gradle.properties @@ -10,4 +10,4 @@ publishing.sonatype=false org.gradle.configureondemand=true org.gradle.jvmargs=-Xmx4096m -toolsVersion=0.14.10-kotlin-1.9.0 \ No newline at end of file +toolsVersion=0.15.0-kotlin-1.9.20-RC \ No newline at end of file