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.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")
}

View File

@ -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<ByteArray>.withDelimiter(delimiter: ByteArray): Flow<ByteArray>
val output = BytePacketBuilder()
var matcherPosition = 0
onCompletion {
output.close()
}
return transform { chunk ->
chunk.forEach { byte ->
output.writeByte(byte)

View File

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

View File

@ -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<T>(
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<T>(
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<ModbusRegistryKey, String> = mutableMapOf<ModbusRegistryKey, String>()
@ -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 <T> input(
address: Int,
count: Int,
reader: IOFormat<T>,
description: String = "",
): ModbusRegistryKey.InputRange<T> =
register(ModbusRegistryKey.InputRange(address, count, reader), description)
): ModbusRegistryKey.InputRange<T> = 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 <T> register(
address: Int,
count: Int,
format: IOFormat<T>,
description: String = "",
): ModbusRegistryKey.HoldingRange<T> =
register(ModbusRegistryKey.HoldingRange(address, count, format), description)
): ModbusRegistryKey.HoldingRange<T> = 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<Map.Entry<ModbusRegistryKey, String>?> { 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<Map.Entry<ModbusRegistryKey, String>?> { 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)
}
}

View File

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