modbus registry to json rendering

This commit is contained in:
Alexander Nozik 2023-10-20 10:14:14 +03:00
parent 290010fc8c
commit 7f71d0c9e9
5 changed files with 107 additions and 45 deletions

View File

@ -1,4 +1,3 @@
import space.kscience.gradle.isInDevelopment
import space.kscience.gradle.useApache2Licence import space.kscience.gradle.useApache2Licence
import space.kscience.gradle.useSPCTeam import space.kscience.gradle.useSPCTeam
@ -14,25 +13,18 @@ val xodusVersion by extra("2.0.1")
allprojects { allprojects {
group = "space.kscience" group = "space.kscience"
version = "0.2.2-dev-2" version = "0.2.2-dev-3"
repositories{ repositories{
maven("https://maven.pkg.jetbrains.space/spc/p/sci/dev") maven("https://maven.pkg.jetbrains.space/spc/p/sci/dev")
} }
} }
ksciencePublish { ksciencePublish {
pom("https://github.com/SciProgCentre/controls.kt") { pom("https://github.com/SciProgCentre/controls-kt") {
useApache2Licence() useApache2Licence()
useSPCTeam() useSPCTeam()
} }
github("controls.kt", "SciProgCentre") repository("spc","https://maven.sciprog.center/kscience")
space(
if (isInDevelopment) {
"https://maven.pkg.jetbrains.space/spc/p/sci/dev"
} else {
"https://maven.pkg.jetbrains.space/spc/p/sci/maven"
}
)
sonatype("https://oss.sonatype.org") sonatype("https://oss.sonatype.org")
} }

View File

@ -5,6 +5,7 @@ import io.ktor.utils.io.core.readBytes
import io.ktor.utils.io.core.reset import io.ktor.utils.io.core.reset
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onCompletion
import kotlinx.coroutines.flow.transform import kotlinx.coroutines.flow.transform
/** /**
@ -16,6 +17,10 @@ public fun Flow<ByteArray>.withDelimiter(delimiter: ByteArray): Flow<ByteArray>
val output = BytePacketBuilder() val output = BytePacketBuilder()
var matcherPosition = 0 var matcherPosition = 0
onCompletion {
output.close()
}
return transform { chunk -> return transform { chunk ->
chunk.forEach { byte -> chunk.forEach { byte ->
output.writeByte(byte) output.writeByte(byte)

View File

@ -12,7 +12,7 @@ description = """
dependencies { dependencies {
api(projects.controlsCore) api(projects.controlsCore)
api("com.ghgande:j2mod:3.1.1") api("com.ghgande:j2mod:3.2.0")
} }
readme{ readme{

View File

@ -1,8 +1,15 @@
package space.kscience.controls.modbus 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 import space.kscience.dataforge.io.IOFormat
/**
* Modbus registry key
*/
public sealed class ModbusRegistryKey { public sealed class ModbusRegistryKey {
public abstract val address: Int public abstract val address: Int
public open val count: Int = 1 public open val count: Int = 1
@ -25,6 +32,9 @@ public sealed class ModbusRegistryKey {
override fun toString(): String = "InputRegister(address=$address)" override fun toString(): String = "InputRegister(address=$address)"
} }
/**
* A range of read-only register encoding a single value
*/
public class InputRange<T>( public class InputRange<T>(
address: Int, address: Int,
override val count: 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() { public open class HoldingRegister(override val address: Int) : ModbusRegistryKey() {
override fun toString(): String = "HoldingRegister(address=$address)" override fun toString(): String = "HoldingRegister(address=$address)"
} }
/**
* A range of read-write registers encoding a single value
*/
public class HoldingRange<T>( public class HoldingRange<T>(
address: Int, address: Int,
override val count: Int, override val count: Int,
@ -52,6 +68,9 @@ public sealed class ModbusRegistryKey {
} }
} }
/**
* A base class for modbus registers
*/
public abstract class ModbusRegistryMap { public abstract class ModbusRegistryMap {
private val _entries: MutableMap<ModbusRegistryKey, String> = mutableMapOf<ModbusRegistryKey, String>() private val _entries: MutableMap<ModbusRegistryKey, String> = mutableMapOf<ModbusRegistryKey, String>()
@ -63,36 +82,56 @@ public abstract class ModbusRegistryMap {
return key return key
} }
/**
* Register a [ModbusRegistryKey.Coil] key and return it
*/
protected fun coil(address: Int, description: String = ""): ModbusRegistryKey.Coil = protected fun coil(address: Int, description: String = ""): ModbusRegistryKey.Coil =
register(ModbusRegistryKey.Coil(address), description) register(ModbusRegistryKey.Coil(address), description)
/**
* Register a [ModbusRegistryKey.DiscreteInput] key and return it
*/
protected fun discrete(address: Int, description: String = ""): ModbusRegistryKey.DiscreteInput = protected fun discrete(address: Int, description: String = ""): ModbusRegistryKey.DiscreteInput =
register(ModbusRegistryKey.DiscreteInput(address), description) register(ModbusRegistryKey.DiscreteInput(address), description)
/**
* Register a [ModbusRegistryKey.InputRegister] key and return it
*/
protected fun input(address: Int, description: String = ""): ModbusRegistryKey.InputRegister = protected fun input(address: Int, description: String = ""): ModbusRegistryKey.InputRegister =
register(ModbusRegistryKey.InputRegister(address), description) register(ModbusRegistryKey.InputRegister(address), description)
/**
* Register a [ModbusRegistryKey.InputRange] key and return it
*/
protected fun <T> input( protected fun <T> input(
address: Int, address: Int,
count: Int, count: Int,
reader: IOFormat<T>, reader: IOFormat<T>,
description: String = "", description: String = "",
): ModbusRegistryKey.InputRange<T> = ): ModbusRegistryKey.InputRange<T> = register(ModbusRegistryKey.InputRange(address, count, reader), description)
register(ModbusRegistryKey.InputRange(address, count, reader), description)
/**
* Register a [ModbusRegistryKey.HoldingRegister] key and return it
*/
protected fun register(address: Int, description: String = ""): ModbusRegistryKey.HoldingRegister = protected fun register(address: Int, description: String = ""): ModbusRegistryKey.HoldingRegister =
register(ModbusRegistryKey.HoldingRegister(address), description) register(ModbusRegistryKey.HoldingRegister(address), description)
/**
* Register a [ModbusRegistryKey.HoldingRange] key and return it
*/
protected fun <T> register( protected fun <T> register(
address: Int, address: Int,
count: Int, count: Int,
format: IOFormat<T>, format: IOFormat<T>,
description: String = "", description: String = "",
): ModbusRegistryKey.HoldingRange<T> = ): ModbusRegistryKey.HoldingRange<T> = register(ModbusRegistryKey.HoldingRange(address, count, format), description)
register(ModbusRegistryKey.HoldingRange(address, count, format), description)
public companion object { public companion object {
/**
* Validate the register map. Throw an error if the map is invalid
*/
public fun validate(map: ModbusRegistryMap) { public fun validate(map: ModbusRegistryMap) {
var lastCoil: ModbusRegistryKey.Coil? = null var lastCoil: ModbusRegistryKey.Coil? = null
var lastDiscreteInput: ModbusRegistryKey.DiscreteInput? = 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) { private val ModbusRegistryKey.sectionNumber
validate(map) get() = when (this) {
map.entries.entries is ModbusRegistryKey.Coil -> 1
.sortedWith( is ModbusRegistryKey.DiscreteInput -> 2
Comparator.comparingInt<Map.Entry<ModbusRegistryKey, String>?> { it.key.sectionNumber } is ModbusRegistryKey.HoldingRegister -> 4
.thenComparingInt { it.key.address } is ModbusRegistryKey.InputRegister -> 3
) }
.forEach { (key, description) ->
val typeString = when (key) { public fun ModbusRegistryMap.print(to: Appendable = System.out) {
is ModbusRegistryKey.Coil -> "Coil" ModbusRegistryMap.validate(this)
is ModbusRegistryKey.DiscreteInput -> "Discrete" entries.entries
is ModbusRegistryKey.HoldingRegister -> "Register" .sortedWith(
is ModbusRegistryKey.InputRegister -> "Input" Comparator.comparingInt<Map.Entry<ModbusRegistryKey, String>?> { it.key.sectionNumber }
} .thenComparingInt { it.key.address }
val rangeString = if (key.count == 1) { )
key.address.toString() .forEach { (key, description) ->
} else { val typeString = when (key) {
"${key.address} - ${key.address + key.count - 1}" is ModbusRegistryKey.Coil -> "Coil"
} is ModbusRegistryKey.DiscreteInput -> "Discrete"
to.appendLine("${typeString}\t$rangeString\t$description") 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)
} }
} }

View File

@ -10,4 +10,4 @@ publishing.sonatype=false
org.gradle.configureondemand=true org.gradle.configureondemand=true
org.gradle.jvmargs=-Xmx4096m org.gradle.jvmargs=-Xmx4096m
toolsVersion=0.14.10-kotlin-1.9.0 toolsVersion=0.15.0-kotlin-1.9.20-RC