Modbus registry validation and print
This commit is contained in:
parent
b8a82feed0
commit
0612c6e3a2
@ -5,10 +5,13 @@ import space.kscience.dataforge.io.IOReader
|
||||
|
||||
|
||||
public sealed class ModbusRegistryKey {
|
||||
public abstract val address: Int
|
||||
public open val count: Int = 1
|
||||
|
||||
/**
|
||||
* Read-only boolean value
|
||||
*/
|
||||
public class Coil(public val address: Int) : ModbusRegistryKey() {
|
||||
public data class Coil(override val address: Int) : ModbusRegistryKey() {
|
||||
init {
|
||||
require(address in 1..9999) { "Coil address must be in 1..9999 range" }
|
||||
}
|
||||
@ -17,7 +20,7 @@ public sealed class ModbusRegistryKey {
|
||||
/**
|
||||
* Read-write boolean value
|
||||
*/
|
||||
public class DiscreteInput(public val address: Int) : ModbusRegistryKey() {
|
||||
public data class DiscreteInput(override val address: Int) : ModbusRegistryKey() {
|
||||
init {
|
||||
require(address in 10001..19999) { "DiscreteInput address must be in 10001..19999 range" }
|
||||
}
|
||||
@ -26,13 +29,17 @@ public sealed class ModbusRegistryKey {
|
||||
/**
|
||||
* Read-only binary value
|
||||
*/
|
||||
public class InputRegister(public val address: Int) : ModbusRegistryKey() {
|
||||
public data class InputRegister(override val address: Int) : ModbusRegistryKey() {
|
||||
init {
|
||||
require(address in 20001..29999) { "InputRegister address must be in 20001..29999 range" }
|
||||
}
|
||||
}
|
||||
|
||||
public class InputRange<T>(public val address: Int, public val count: Int, public val format: IOReader<T>) {
|
||||
public data class InputRange<T>(
|
||||
override val address: Int,
|
||||
override val count: Int,
|
||||
public val format: IOReader<T>,
|
||||
) : ModbusRegistryKey() {
|
||||
public val endAddress: Int get() = address + count
|
||||
|
||||
init {
|
||||
@ -41,13 +48,17 @@ public sealed class ModbusRegistryKey {
|
||||
}
|
||||
}
|
||||
|
||||
public class HoldingRegister(public val address: Int) : ModbusRegistryKey() {
|
||||
public data class HoldingRegister(override val address: Int) : ModbusRegistryKey() {
|
||||
init {
|
||||
require(address in 30001..39999) { "HoldingRegister address must be in 30001..39999 range" }
|
||||
}
|
||||
}
|
||||
|
||||
public class HoldingRange<T>(public val address: Int, public val count: Int, public val format: IOFormat<T>) {
|
||||
public data class HoldingRange<T>(
|
||||
override val address: Int,
|
||||
override val count: Int,
|
||||
public val format: IOFormat<T>,
|
||||
) : ModbusRegistryKey() {
|
||||
public val endAddress: Int get() = address + count
|
||||
|
||||
init {
|
||||
@ -58,35 +69,96 @@ public sealed class ModbusRegistryKey {
|
||||
}
|
||||
|
||||
public abstract class ModbusRegistryMap {
|
||||
protected fun coil(address: Int): ModbusRegistryKey.Coil = ModbusRegistryKey.Coil(address)
|
||||
|
||||
protected fun coilByOffset(offset: Int): ModbusRegistryKey.Coil = ModbusRegistryKey.Coil(offset)
|
||||
private val _entries: MutableMap<ModbusRegistryKey, String> = mutableMapOf<ModbusRegistryKey, String>()
|
||||
|
||||
protected fun discrete(address: Int): ModbusRegistryKey.DiscreteInput = ModbusRegistryKey.DiscreteInput(address)
|
||||
public val entries: Map<ModbusRegistryKey, String> get() = _entries
|
||||
|
||||
protected fun discreteByOffset(offset: Int): ModbusRegistryKey.DiscreteInput =
|
||||
ModbusRegistryKey.DiscreteInput(10000 + offset)
|
||||
protected fun <T : ModbusRegistryKey> register(key: T, description: String): T {
|
||||
_entries[key] = description
|
||||
return key
|
||||
}
|
||||
|
||||
protected fun input(address: Int): ModbusRegistryKey.InputRegister = ModbusRegistryKey.InputRegister(address)
|
||||
protected fun coil(address: Int, description: String = ""): ModbusRegistryKey.Coil =
|
||||
register(ModbusRegistryKey.Coil(address), description)
|
||||
|
||||
protected fun <T> input(address: Int, count: Int, reader: IOReader<T>): ModbusRegistryKey.InputRange<T> =
|
||||
ModbusRegistryKey.InputRange(address, count, reader)
|
||||
protected fun coilByOffset(offset: Int, description: String = ""): ModbusRegistryKey.Coil =
|
||||
register(ModbusRegistryKey.Coil(offset), description)
|
||||
|
||||
protected fun discrete(address: Int, description: String = ""): ModbusRegistryKey.DiscreteInput =
|
||||
register(ModbusRegistryKey.DiscreteInput(address), description)
|
||||
|
||||
protected fun inputByOffset(offset: Int): ModbusRegistryKey.InputRegister =
|
||||
ModbusRegistryKey.InputRegister(20000 + offset)
|
||||
protected fun discreteByOffset(offset: Int, description: String = ""): ModbusRegistryKey.DiscreteInput =
|
||||
register(ModbusRegistryKey.DiscreteInput(10000 + offset), description)
|
||||
|
||||
protected fun <T> inputByOffset(offset: Int, count: Int, reader: IOReader<T>): ModbusRegistryKey.InputRange<T> =
|
||||
ModbusRegistryKey.InputRange(20000 + offset, count, reader)
|
||||
protected fun input(address: Int, description: String = ""): ModbusRegistryKey.InputRegister =
|
||||
register(ModbusRegistryKey.InputRegister(address), description)
|
||||
|
||||
protected fun register(address: Int): ModbusRegistryKey.HoldingRegister = ModbusRegistryKey.HoldingRegister(address)
|
||||
protected fun <T> input(
|
||||
address: Int,
|
||||
count: Int,
|
||||
reader: IOReader<T>,
|
||||
description: String = "",
|
||||
): ModbusRegistryKey.InputRange<T> =
|
||||
register(ModbusRegistryKey.InputRange(address, count, reader), description)
|
||||
|
||||
protected fun <T> register(address: Int, count: Int, format: IOFormat<T>): ModbusRegistryKey.HoldingRange<T> =
|
||||
ModbusRegistryKey.HoldingRange(address, count, format)
|
||||
protected fun inputByOffset(offset: Int, description: String = ""): ModbusRegistryKey.InputRegister =
|
||||
register(ModbusRegistryKey.InputRegister(20000 + offset), description)
|
||||
|
||||
protected fun registerByOffset(offset: Int): ModbusRegistryKey.HoldingRegister =
|
||||
ModbusRegistryKey.HoldingRegister(30000 + offset)
|
||||
protected fun <T> inputByOffset(
|
||||
offset: Int,
|
||||
count: Int,
|
||||
reader: IOReader<T>,
|
||||
description: String = "",
|
||||
): ModbusRegistryKey.InputRange<T> =
|
||||
register(ModbusRegistryKey.InputRange(20000 + offset, count, reader), description)
|
||||
|
||||
protected fun <T> registerByOffset(offset: Int, count: Int, format: IOFormat<T>): ModbusRegistryKey.HoldingRange<T> =
|
||||
ModbusRegistryKey.HoldingRange(offset + 30000, count, format)
|
||||
protected fun register(address: Int, description: String = ""): ModbusRegistryKey.HoldingRegister =
|
||||
register(ModbusRegistryKey.HoldingRegister(address), description)
|
||||
|
||||
protected fun <T> register(
|
||||
address: Int,
|
||||
count: Int,
|
||||
format: IOFormat<T>,
|
||||
description: String = "",
|
||||
): ModbusRegistryKey.HoldingRange<T> =
|
||||
register(ModbusRegistryKey.HoldingRange(address, count, format), description)
|
||||
|
||||
protected fun registerByOffset(offset: Int, description: String = ""): ModbusRegistryKey.HoldingRegister =
|
||||
register(ModbusRegistryKey.HoldingRegister(30000 + offset), description)
|
||||
|
||||
protected fun <T> registerByOffset(
|
||||
offset: Int,
|
||||
count: Int,
|
||||
format: IOFormat<T>,
|
||||
description: String = "",
|
||||
): ModbusRegistryKey.HoldingRange<T> =
|
||||
register(ModbusRegistryKey.HoldingRange(offset + 30000, count, format), description)
|
||||
|
||||
public companion object {
|
||||
public fun validate(map: ModbusRegistryMap) {
|
||||
map.entries.keys.sortedBy { it.address }.zipWithNext().forEach { (l, r) ->
|
||||
if (l.address + l.count > r.address) error("Key $l overlaps with key $r")
|
||||
}
|
||||
}
|
||||
|
||||
public fun print(map: ModbusRegistryMap, to: Appendable = System.out) {
|
||||
map.entries.entries.sortedBy { it.key.address }.forEach { (key, description) ->
|
||||
val typeString = when (key) {
|
||||
is ModbusRegistryKey.Coil -> "Coil"
|
||||
is ModbusRegistryKey.DiscreteInput -> "Discrete"
|
||||
is ModbusRegistryKey.HoldingRange<*>, is ModbusRegistryKey.HoldingRegister -> "Register"
|
||||
is ModbusRegistryKey.InputRange<*>, is ModbusRegistryKey.InputRegister -> "Input"
|
||||
}
|
||||
val rangeString = if (key.count == 1) {
|
||||
key.address.toString()
|
||||
} else {
|
||||
"${key.address} - ${key.address + key.count}"
|
||||
}
|
||||
to.appendLine("${typeString}\t$rangeString\t$description")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -8,6 +8,7 @@ import space.kscience.controls.spec.DeviceSpec
|
||||
import space.kscience.controls.spec.doubleProperty
|
||||
import space.kscience.controls.spec.read
|
||||
import space.kscience.dataforge.meta.transformations.MetaConverter
|
||||
import kotlin.test.Ignore
|
||||
|
||||
class OpcUaClientTest {
|
||||
class DemoOpcUaDevice(config: MiloConfiguration) : OpcUaDeviceBySpec<DemoOpcUaDevice>(DemoOpcUaDevice, config) {
|
||||
@ -37,6 +38,7 @@ class OpcUaClientTest {
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@Test
|
||||
@Ignore
|
||||
fun testReadDouble() = runTest {
|
||||
DemoOpcUaDevice.build().use{
|
||||
println(it.read(DemoOpcUaDevice.randomDouble))
|
||||
|
Loading…
Reference in New Issue
Block a user