Skip to content

Commit 50f9e03

Browse files
authored
Merge pull request #4 from paulorb/IfEqual
If equal
2 parents acdde29 + 08d5225 commit 50f9e03

File tree

11 files changed

+510
-165
lines changed

11 files changed

+510
-165
lines changed

examples/configuration_simulation.xml

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
<?xml version="1.0" encoding="US-ASCII" ?>
22
<device ip="0.0.0.0" port="502">
3+
<parameters>
4+
<parameter symbol="PARAM_CURRENT_SELECTION" datatype="INT16">15</parameter>
5+
<parameter symbol="PARAM_SET_TEMPERATURE" datatype="FLOAT32">5.45</parameter>
6+
<parameter symbol="PARAM_ENABLE_FAST_MODE" datatype="BOOL">1</parameter>
7+
</parameters>
38
<configuration initializeUndefinedRegisters="true" initialValue="0">
49
<registers>
510
<register addressType="HOLDING_REGISTER" address="14" symbol="RPM_MOTOR">500</register>
@@ -9,6 +14,7 @@
914
<register addressType="HOLDING_REGISTER" address="14" datatype="FLOAT32" symbol="TEMPERATURE_MOTOR2">-12.5</register>
1015
<register addressType="HOLDING_REGISTER" address="16" datatype="FLOAT32" symbol="TEMPERATURE_MOTOR3">-12.5</register>
1116
<register addressType="HOLDING_REGISTER" address="18" datatype="FLOAT32" symbol="TEMPERATURE_MOTOR4">-12.5</register>
17+
<register addressType="HOLDING_REGISTER" address="20" datatype="FLOAT32" symbol="TEMPERATURE_MOTOR5">-12.5</register>
1218
<register addressType="HOLDING_REGISTER" address="1" datatype="INT16" symbol="RPM_MOTOR1">1</register>
1319
<register addressType="HOLDING_REGISTER" address="2" datatype="INT16" symbol="RPM_MOTOR2">-2</register>
1420
<register addressType="HOLDING_REGISTER" address="3" datatype="INT16" symbol="RPM_MOTOR3">3</register>
@@ -17,6 +23,7 @@
1723
<register addressType="HOLDING_REGISTER" address="6" datatype="INT16" symbol="RPM_MOTOR6">6</register>
1824
<register addressType="HOLDING_REGISTER" address="7" datatype="INT16" symbol="RPM_MOTOR7">7</register>
1925
<register addressType="HOLDING_REGISTER" address="8" datatype="INT16" symbol="RPM_MOTOR8">8</register>
26+
<register addressType="HOLDING_REGISTER" address="22" datatype="INT16" symbol="RPM_MOTOR9">9</register>
2027
<register addressType="COIL" address="1" symbol="RELAYON">1</register>
2128
<register addressType="COIL" address="2" symbol="RELAYON2">1</register>
2229
<register addressType="COIL" address="3" symbol="RELAYON3">1</register>
@@ -36,7 +43,6 @@
3643
</configuration>
3744
<simulation plcScanTime="1000">
3845
<delay>500</delay>
39-
<set symbol="RPM">50</set>
4046
<set symbol="RELAYON">0</set>
4147
<set symbol="RELAY_STATUS">0</set>
4248
<set symbol="RPM_MOTOR">100</set>
@@ -45,6 +51,27 @@
4551
<delay>500</delay>
4652
<set symbol="RPM">60</set>
4753
<set symbol="MOTOR_SPEED1">190.5</set>
54+
<ifEqual symbol="RPM_MOTOR1" value="1">
55+
<set symbol="RPM_MOTOR1">777</set>
56+
<ifEqual symbol="RPM_MOTOR1" value="777">
57+
<set symbol="RPM_MOTOR1">888</set>
58+
<ifEqual symbol="RPM_MOTOR1" value="888">
59+
<set symbol="RPM_MOTOR1">999</set>
60+
</ifEqual>
61+
</ifEqual>
62+
</ifEqual>
63+
<ifEqual symbol="TEMPERATURE_MOTOR5" value="-12.5">
64+
<set symbol="TEMPERATURE_MOTOR5">777</set>
65+
<ifEqual symbol="TEMPERATURE_MOTOR5" value="777">
66+
<set symbol="TEMPERATURE_MOTOR5">888</set>
67+
<ifEqual symbol="TEMPERATURE_MOTOR5" value="888">
68+
<set symbol="TEMPERATURE_MOTOR5">999</set>
69+
</ifEqual>
70+
</ifEqual>
71+
</ifEqual>
72+
<ifEqual symbol="PARAM_CURRENT_SELECTION" value="15">
73+
<set symbol="RPM_MOTOR9">15</set>
74+
</ifEqual>
4875
<linear symbol="TEMPERATURE_MOTOR1" a="3" b="2" startX="0" endX="12" replay="true" step="1.5"/>
4976
<linear symbol="TEMPERATURE_MOTOR2" a="3" b="2" startX="12" endX="0" replay="true" step="1.5"/>
5077
<csv symbol="TEMPERATURE_MOTOR3" file="test_data.csv" column="1" replay="true"/>

src/main/kotlin/ConfigurationParser.kt

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ class ConfigurationParser {
1717
}
1818
private fun load(): Device? {
1919
try {
20-
val context = JAXBContext.newInstance(Device::class.java, Set::class.java, Random::class.java, Delay::class.java, Linear::class.java, Add::class.java, Sub::class.java, Csv::class.java)
20+
val context = JAXBContext.newInstance(Device::class.java, Set::class.java, Random::class.java, Delay::class.java, Linear::class.java, Add::class.java, Sub::class.java, Csv::class.java, IfEqual::class.java, Parameters::class.java, Parameter::class.java)
2121
val unmarshaller = context.createUnmarshaller()
2222
if(fileName.isEmpty()) {
2323
val reader = StringReader(this::class.java.classLoader.getResource("configuration.xml")!!.readText())
@@ -47,12 +47,14 @@ data class Device(
4747
var ip: String,
4848
@field:XmlAttribute(required = false)
4949
var port: String,
50+
@field:XmlElement(required = false)
51+
val parameters: Parameters,
5052
@field:XmlElement
5153
val configuration: Configuration,
5254
@field:XmlElement
5355
val simulation: Simulation,
5456
){
55-
constructor() : this("", "", Configuration(true,0, Registers(mutableListOf())), Simulation(1000,mutableListOf()))
57+
constructor() : this("", "", Parameters(), Configuration(true,0, Registers(mutableListOf())), Simulation(1000,mutableListOf()))
5658
}
5759

5860
@XmlAccessorType(XmlAccessType.NONE)
@@ -66,6 +68,21 @@ class Simulation(
6668

6769
}
6870

71+
//<ifEqual symbol="TEMP" value="12.4">
72+
// <sub symbol="MOTOR_SPEED1">12</sub>
73+
// any other operation ...
74+
//</ifEqual>
75+
@XmlRootElement(name="ifEqual")
76+
data class IfEqual(
77+
@field:XmlAttribute(required = true)
78+
val symbol: String,
79+
@field:XmlAttribute(required = true)
80+
val value: String,
81+
@XmlAnyElement(lax = true)
82+
var randomElements: List<Any>
83+
){
84+
constructor() : this("","",mutableListOf())
85+
}
6986

7087
//<csv symbol="TEMPERATURE_MOTOR4" file="test.csv" column="0" step="2" startRow="2" endRow="100" replay="true"/>
7188
@XmlRootElement(name="csv")
@@ -164,6 +181,34 @@ data class Set(
164181
constructor(): this("", "0")
165182
}
166183

184+
@XmlAccessorType(XmlAccessType.NONE)
185+
data class Parameters(
186+
@field:XmlElement(name = "parameter")
187+
val parameters: MutableList<Parameter>
188+
) {
189+
constructor(): this(mutableListOf())
190+
fun getParametersConfiguration(symbolName: String) : Parameter? {
191+
parameters.forEach {register ->
192+
if(register.symbol == symbolName){
193+
return register
194+
}
195+
}
196+
return null
197+
}
198+
}
199+
200+
@XmlAccessorType(XmlAccessType.NONE)
201+
data class Parameter(
202+
@XmlAttribute
203+
val symbol: String,
204+
@XmlAttribute(required = true)
205+
val datatype: String,
206+
@XmlValue
207+
val value: String
208+
) {
209+
constructor() : this( "","","")
210+
}
211+
167212
data class Configuration(
168213
@field:XmlAttribute(required = false)
169214
val initializeUndefinedRegisters: Boolean,
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import java.util.*
2+
3+
class EnvironmentVariables(
4+
parameters: List<EnvParameter>,
5+
private val configurationParser: ConfigurationParser)
6+
{
7+
private var enviromentVars = mutableListOf<EnvParameter>()
8+
init {
9+
var found = false
10+
configurationParser.getConfiguredDevice().parameters.parameters.forEach { jsonParameter ->
11+
found = false
12+
parameters.forEach { envParameter ->
13+
if (envParameter.symbol == jsonParameter.symbol) {
14+
if(jsonParameter.datatype == "INT16" && envParameter.value.toIntOrNull() == null){
15+
throw InvalidPropertiesFormatException("Environment variable for parameter ${jsonParameter.symbol} has value ${envParameter.value} which does not conform with its datatype INT16")
16+
}
17+
if(jsonParameter.datatype == "FLOAT32" && envParameter.value.toFloatOrNull() == null){
18+
throw InvalidPropertiesFormatException("Environment variable for parameter ${jsonParameter.symbol} has value ${envParameter.value} which does not conform with its datatype FLOAT32")
19+
}
20+
if(jsonParameter.datatype == "BOOL" && envParameter.value != "0" && envParameter.value != "1"){
21+
throw InvalidPropertiesFormatException("Environment variable for parameter ${jsonParameter.symbol} has value ${envParameter.value} which does not conform with its datatype BOOL")
22+
}
23+
enviromentVars.add(EnvParameter(envParameter.symbol, envParameter.value, envParameter.type))
24+
found = true
25+
}
26+
}
27+
if (!found) {
28+
if (jsonParameter.value.isEmpty()) {
29+
throw InvalidPropertiesFormatException("Environment variable for parameter ${jsonParameter.symbol} not found, json definition do not have a default value, which makes it mandatory")
30+
} else {
31+
enviromentVars.add(EnvParameter(jsonParameter.symbol, jsonParameter.value, jsonParameter.datatype))
32+
}
33+
}
34+
}
35+
}
36+
fun resolveEnvVar(variableName: String): EnvParameter? {
37+
enviromentVars.forEach {parameter ->
38+
if(parameter.symbol == variableName)
39+
return parameter
40+
}
41+
return null
42+
}
43+
}

src/main/kotlin/Main.kt

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,15 @@ import kotlinx.coroutines.Dispatchers
33
import picocli.CommandLine
44
import picocli.CommandLine.Command
55
import picocli.CommandLine.Option
6-
import picocli.CommandLine.Parameters
7-
8-
import java.io.File
9-
import java.math.BigInteger
10-
import java.nio.file.Files
11-
import java.security.MessageDigest
6+
import java.util.InvalidPropertiesFormatException
127
import java.util.concurrent.Callable
138
import kotlin.system.exitProcess
149

15-
10+
data class EnvParameter(
11+
var symbol : String,
12+
var value: String,
13+
var type: String
14+
)
1615
@Command(name = "modbussimulatorcli", mixinStandardHelpOptions = true, version = ["CLI 0.0.99"],
1716
description = ["Modbus TCP Simulator"])
1817
class Checksum : Callable<Int> {
@@ -26,11 +25,29 @@ class Checksum : Callable<Int> {
2625
@Option(names = ["-sr", "--simulation-random"], description = ["random number simulation"])
2726
var simulationRandomValues = false
2827

29-
28+
//-e CUSTOM_VALUE=12 -e MOTOR_VAL=12.2
29+
@Option(names = ["-e", "--env"], description = ["environment variables"])
30+
var parameters: MutableList<String?>? = null
3031

3132
private lateinit var plcMemory: PlcMemory
3233
private lateinit var plcSimulation: PlcSimulation
3334
private lateinit var modbusServer: ModbusServer
35+
private lateinit var environmentParameters: List<EnvParameter>
36+
37+
private fun processEnvironmentParameters(parameters: MutableList<String?>?): List<EnvParameter> {
38+
val envParameter = mutableListOf<EnvParameter>()
39+
parameters?.forEach { param ->
40+
val parts = param?.split('=')
41+
if (parts != null) {
42+
if(parts.count() != 2){
43+
throw InvalidPropertiesFormatException("Environment parameter does not follow the format NAME=VALUE")
44+
}else{
45+
envParameter.add(EnvParameter(parts[0],parts[1], ""))
46+
}
47+
}
48+
}
49+
return envParameter.toList()
50+
}
3451

3552
override fun call(): Int {
3653
val mainCoroutineScope = CoroutineScope(Dispatchers.Default)
@@ -40,6 +57,9 @@ class Checksum : Callable<Int> {
4057
println("-f and -sr cannot be mixed, one of the simulations must be chosen")
4158
return -1
4259
}
60+
61+
environmentParameters = processEnvironmentParameters(parameters)
62+
4363
//val fileContents = Files.readAllBytes(file.toPath())
4464
//val digest = MessageDigest.getInstance(port).digest(fileContents)
4565
//println(("%0" + digest.size * 2 + "x").format(BigInteger(1, digest)))
@@ -52,7 +72,8 @@ class Checksum : Callable<Int> {
5272
}
5373
// if not set default, reading internal xml
5474
plcMemory = PlcMemory(configuration)
55-
plcSimulation = PlcSimulation(configuration, plcMemory, mainCoroutineScope)
75+
var envVariables = EnvironmentVariables(environmentParameters, configuration)
76+
plcSimulation = PlcSimulation(configuration, plcMemory,envVariables, mainCoroutineScope)
5677
modbusServer = ModbusServer(plcMemory)
5778
}
5879

@@ -64,6 +85,8 @@ class Checksum : Callable<Int> {
6485
}
6586
return 0
6687
}
88+
89+
6790
}
6891

6992
fun main(args: Array<String>) : Unit = exitProcess(CommandLine(Checksum()).execute(*args))

src/main/kotlin/PlcMemory.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import java.util.InvalidPropertiesFormatException
12
import java.util.concurrent.ConcurrentHashMap
23

34

0 commit comments

Comments
 (0)