Skip to content

Commit ca5b495

Browse files
authored
Merge pull request #19 from paulorb/17-add-possibility-of-toggling-boolean-values
17 add possibility of toggling boolean values
2 parents f0a87bf + 9e27d7e commit ca5b495

File tree

8 files changed

+121
-73
lines changed

8 files changed

+121
-73
lines changed

docs/getting-started/operations.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,16 @@ follow the same type of the specified **symbol** definition. In case the variabl
1515

1616
Supported registers: **HOLDING_REGISTER**, **COIL**, **DISCRETE_INPUT**, **INPUT_REGISTER**
1717

18+
## Toggle
19+
Toggle acts as a NOT inverting the logic of the COIL
20+
21+
```xml
22+
<toggle symbol="COIL_REGISTER" />
23+
```
24+
25+
Supported registers: **COIL**
26+
27+
1828
## Add
1929
Add (as the name implies) add a certain value to a variable, like the example below:
2030

examples/configuration_simulation.xml

Lines changed: 11 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
<registers>
1010
<register addressType="HOLDING_REGISTER" address="14" symbol="RPM_MOTOR">500</register>
1111
<register addressType="HOLDING_REGISTER" address="8" datatype="FLOAT32" symbol="MOTOR_SPEED1">123.7</register>
12-
<register addressType="HOLDING_REGISTER" address="10" datatype="FLOAT32" symbol="TEMPERATURE1">-12.5</register>
12+
<register addressType="HOLDING_REGISTER" address="10" datatype="FLOAT32" symbol="TEMPERATURE1">100.0</register>
1313
<register addressType="HOLDING_REGISTER" address="12" datatype="FLOAT32" symbol="TEMPERATURE_MOTOR1">-12.5</register>
1414
<register addressType="HOLDING_REGISTER" address="14" datatype="FLOAT32" symbol="TEMPERATURE_MOTOR2">-12.5</register>
1515
<register addressType="HOLDING_REGISTER" address="16" datatype="FLOAT32" symbol="TEMPERATURE_MOTOR3">-12.5</register>
@@ -39,81 +39,21 @@
3939
<register addressType="INPUT_REGISTER" address="8" symbol="RPM5">5</register>
4040
<register addressType="INPUT_REGISTER" address="10" symbol="RPM6">6</register>
4141
<register addressType="INPUT_REGISTER" address="12" symbol="RPM7">7</register>
42+
<register addressType="HOLDING_REGISTER" address="200" datatype="FLOAT32" symbol="VAR_TEMP">123.7</register>
43+
<register addressType="COIL" address="0" symbol="TEST">0</register>
4244
</registers>
4345
</configuration>
4446
<simulation plcScanTime="1000">
45-
<delay>500</delay>
46-
<set symbol="RELAYON">0</set>
47-
<set symbol="RELAY_STATUS">0</set>
48-
<set symbol="RPM_MOTOR">100</set>
49-
<set symbol="MOTOR_SPEED1">100.5</set>
50-
<random symbol="TEMPERATURE1" valueMin="-50.0" valueMax="10.0"/>
51-
<trace symbol="TEMPERATURE1" />
52-
<delay>500</delay>
53-
<set symbol="RPM">60</set>
54-
<set symbol="MOTOR_SPEED1">190.5</set>
55-
<mult symbol="MOTOR_SPEED1">2.5</mult>
56-
<trace symbol="MOTOR_SPEED1" />
57-
<ifGreater symbol="MOTOR_SPEED1" value="470.0">
58-
<trace symbol="MOTOR_SPEED1" />
59-
</ifGreater>
60-
<div symbol="MOTOR_SPEED1">3.5</div>
61-
<ifLess symbol="MOTOR_SPEED1" value="470.0">
62-
<trace symbol="MOTOR_SPEED1" />
63-
</ifLess>
64-
<trace symbol="MOTOR_SPEED1" />
65-
<ifEqual symbol="RPM_MOTOR1" value="1">
66-
<set symbol="RPM_MOTOR1">777</set>
67-
<ifEqual symbol="RPM_MOTOR1" value="777">
68-
<set symbol="RPM_MOTOR1">888</set>
69-
<ifEqual symbol="RPM_MOTOR1" value="888">
70-
<set symbol="RPM_MOTOR1">999</set>
71-
</ifEqual>
47+
<add symbol="RPM_MOTOR1">1</add>
48+
<ifEqual symbol="RPM_MOTOR1" value="10">
49+
<ifEqual symbol="TEST" value="1">
50+
<set symbol="TEST">0</set>
7251
</ifEqual>
73-
</ifEqual>
74-
<ifEqual symbol="TEMPERATURE_MOTOR5" value="-12.5">
75-
<set symbol="TEMPERATURE_MOTOR5">777</set>
76-
<ifEqual symbol="TEMPERATURE_MOTOR5" value="777">
77-
<set symbol="TEMPERATURE_MOTOR5">888</set>
78-
<ifEqual symbol="TEMPERATURE_MOTOR5" value="888">
79-
<set symbol="TEMPERATURE_MOTOR5">999</set>
80-
</ifEqual>
52+
<ifEqual symbol="TEST" value="0">
53+
<set symbol="TEST">1</set>
8154
</ifEqual>
55+
<set symbol="RPM_MOTOR1">0</set>
56+
<toggle symbol="RELAYON" />
8257
</ifEqual>
83-
<ifEqual symbol="PARAM_CURRENT_SELECTION" value="15">
84-
<set symbol="RPM_MOTOR9">15</set>
85-
</ifEqual>
86-
<linear symbol="TEMPERATURE_MOTOR1" a="3" b="2" startX="0" endX="12" replay="true" step="1.5"/>
87-
<linear symbol="TEMPERATURE_MOTOR2" a="3" b="2" startX="12" endX="0" replay="true" step="1.5"/>
88-
<trace symbol="TEMPERATURE_MOTOR2" />
89-
<csv symbol="TEMPERATURE_MOTOR3" file="test_data.csv" column="1" replay="true"/>
90-
<csv symbol="TEMPERATURE_MOTOR4" file="test_data.csv" column="2" step="2" startRow="2" endRow="5" replay="true"/>
91-
<set symbol="RELAYON">1</set>
92-
<trace symbol="RELAYON" />
93-
<set symbol="RELAY_STATUS">1</set>
94-
<trace symbol="RPM_MOTOR" />
95-
<set symbol="RPM_MOTOR">400</set>
96-
<trace symbol="RPM_MOTOR" />
97-
<delay>1000</delay>
98-
<add symbol="MOTOR_SPEED1">15</add>
99-
<add symbol="RPM7">1</add>
100-
<delay>1000</delay>
101-
<add symbol="MOTOR_SPEED1">15</add>
102-
<add symbol="RPM7">1</add>
103-
<delay>1000</delay>
104-
<add symbol="MOTOR_SPEED1">15</add>
105-
<add symbol="RPM7">1</add>
106-
<delay>1000</delay>
107-
<add symbol="MOTOR_SPEED1">15</add>
108-
<add symbol="RPM7">1</add>
109-
<delay>1000</delay>
110-
<add symbol="MOTOR_SPEED1">15</add>
111-
<add symbol="RPM7">1</add>
112-
<delay>1000</delay>
113-
<add symbol="MOTOR_SPEED1">15</add>
114-
<add symbol="RPM7">1</add>
115-
<delay>1000</delay>
116-
<add symbol="RPM_MOTOR4">12</add>
117-
<sub symbol="RPM_MOTOR1">12</sub>
11858
</simulation>
11959
</device>

src/main/kotlin/ConfigurationParser.kt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ class ConfigurationParser {
2323
}
2424
private fun load(): Device? {
2525
try {
26-
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, Trace::class.java, Mult::class.java, Div::class.java, IfGreater::class.java, IfLess::class.java)
26+
val context = JAXBContext.newInstance(Device::class.java, Set::class.java, Toggle::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, Trace::class.java, Mult::class.java, Div::class.java, IfGreater::class.java, IfLess::class.java)
2727
val unmarshaller = context.createUnmarshaller()
2828
return if(fileName.isEmpty() ) {
2929
val reader = StringReader(this::class.java.classLoader.getResource("configuration.xml")!!.readText())
@@ -262,6 +262,15 @@ data class Set(
262262
constructor(): this("", "0")
263263
}
264264

265+
//<toggle symbol="MOTOR_SPEED1" />
266+
@XmlRootElement(name="toggle")
267+
data class Toggle(
268+
@field:XmlAttribute(required = true)
269+
val symbol: String
270+
){
271+
constructor(): this("")
272+
}
273+
265274
@XmlAccessorType(XmlAccessType.NONE)
266275
data class Parameters(
267276
@field:XmlElement(name = "parameter")

src/main/kotlin/PlcSimulation.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ class PlcSimulation(
2020
val subOperation = SubOperation(configurationParser.getConfiguredDevice().configuration, memory, parameters)
2121
val multOperation = MultOperation(configurationParser.getConfiguredDevice().configuration, memory, parameters)
2222
val divOperation = DivOperation(configurationParser.getConfiguredDevice().configuration, memory, parameters)
23-
23+
val toggleOperation = ToggleOperation(configurationParser.getConfiguredDevice().configuration, memory, parameters)
2424
companion object {
2525
val logger = LoggerFactory.getLogger("PlcSimulation")
2626
}
@@ -61,6 +61,10 @@ class PlcSimulation(
6161
randomOperation(element, configuration, memory)
6262
}
6363

64+
is Toggle -> {
65+
toggleOperation.toggleOperation(element)
66+
}
67+
6468
is Delay -> {
6569
logger.info("Delay value ${element.value}")
6670
delay(element.value.toLong())
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package operations
2+
3+
import Configuration
4+
import EnvironmentVariables
5+
import PlcMemory
6+
import Toggle
7+
import org.slf4j.LoggerFactory
8+
import java.util.concurrent.CancellationException
9+
10+
class ToggleOperation(private val configuration: Configuration,private val memory: PlcMemory, environmentVariables: EnvironmentVariables
11+
) : BaseOperation(environmentVariables, configuration, memory)
12+
{
13+
companion object {
14+
val logger = LoggerFactory.getLogger("ToggleOperation")
15+
}
16+
17+
fun toggleOperation(element: Toggle) {
18+
logger.info("Toggle symbol ${element.symbol}")
19+
val variable = configuration.registers.getVarConfiguration(element.symbol)
20+
if (variable == null) {
21+
SubOperation.logger.error("Symbol ${element.symbol} not found during Set execution")
22+
throw CancellationException("Error - Sub")
23+
} else {
24+
if (variable.addressType != AddressType.COIL) {
25+
SubOperation.logger.error("Symbol ${element.symbol} is not of type COIL, only COIL is supported by Toggle operation")
26+
throw CancellationException("Error - Toggle")
27+
}
28+
29+
when (variable.addressType) {
30+
AddressType.COIL -> {
31+
if (variable.datatype == "BOOL" || variable.datatype == "") {
32+
val currentValue = memory.readCoilStatus(variable.address.toInt(), 1)
33+
memory.forceSingleCoil(variable.address.toInt(), currentValue.first().not())
34+
} else {
35+
throw CancellationException("Error - Toggle - Invalid datatype")
36+
}
37+
}
38+
39+
else -> {
40+
throw CancellationException("Error - Toggle")
41+
}
42+
}
43+
}
44+
}
45+
}

src/test/kotlin/ConfigurationParserTest.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import org.junit.jupiter.api.Test
22
import org.junit.jupiter.api.assertThrows
3+
import kotlin.test.assertTrue
34

45
class ConfigurationParserTest {
56

@@ -12,4 +13,12 @@ class ConfigurationParserTest {
1213
configuration.setFileName("invalid_missing_device.xml")
1314
assertThrows<NullPointerException> { configuration.getConfiguredDevice() }
1415
}
16+
17+
@Test
18+
fun `Parse must be able to parse toggle operations`() {
19+
val configuration = ConfigurationParser()
20+
configuration.setReadFromResources(true)
21+
configuration.setFileName("toggle_operation.xml")
22+
assertTrue(configuration.getConfiguredDevice().simulation.randomElements[0] is Toggle)
23+
}
1524
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import operations.ToggleOperation
2+
import org.junit.jupiter.api.Test
3+
import kotlin.test.assertEquals
4+
import kotlin.test.assertTrue
5+
6+
class ToggleOperationTest {
7+
8+
@Test
9+
fun `Toggle must invert the boolean value`() {
10+
val configuration = ConfigurationParser()
11+
configuration.setReadFromResources(true)
12+
configuration.setFileName("toggle_operation.xml")
13+
val plcMemory = PlcMemory(configuration)
14+
val toggleOperation = ToggleOperation(configuration.getConfiguredDevice().configuration, plcMemory, EnvironmentVariables(listOf<EnvParameter>(),ConfigurationParser() ))
15+
assertTrue(configuration.getConfiguredDevice().simulation.randomElements[0] is Toggle)
16+
assertEquals(plcMemory.readCoilStatus(configuration.getConfiguredDevice().configuration.registers.register.first().address.toInt(), 1).first(), false)
17+
toggleOperation.toggleOperation(configuration.getConfiguredDevice().simulation.randomElements[0] as Toggle)
18+
assertEquals(plcMemory.readCoilStatus(configuration.getConfiguredDevice().configuration.registers.register.first().address.toInt(), 1).first(), true)
19+
}
20+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?xml version="1.0" encoding="US-ASCII" ?>
2+
<device ip="0.0.0.0" port="502">
3+
<configuration initializeUndefinedRegisters="true" initialValue="0">
4+
<registers>
5+
<register addressType="COIL" address="0" symbol="RELAYON">0</register>
6+
</registers>
7+
</configuration>
8+
<simulation plcScanTime="1000">
9+
<toggle symbol="RELAYON" />
10+
</simulation>
11+
</device>

0 commit comments

Comments
 (0)