# HG changeset patch # User Edouard Tisserant <edouard.tisserant@gmail.com> # Date 1712244709 -7200 # Node ID a6ec38dcbfb5f7675b5790620f86a84154483819 # Parent 1d383b4c0a2351854185492c90d9d1b0250affec Modbus: add CI test + test project diff -r 1d383b4c0a23 -r a6ec38dcbfb5 tests/Makefile --- a/tests/Makefile Wed Apr 03 13:02:50 2024 +0200 +++ b/tests/Makefile Thu Apr 04 17:31:49 2024 +0200 @@ -71,7 +71,7 @@ # SOURCE and BUILD # -BUILT_PROJECTS=beremiz matiec open62541 +BUILT_PROJECTS=beremiz matiec open62541 Modbus tar_opts=--absolute-names --exclude=.hg --exclude=.git --exclude=.*.pyc --exclude=.*.swp @@ -105,7 +105,12 @@ cmake -D UA_ENABLE_ENCRYPTION=OPENSSL .. && \ make -built_apps: $(build_dir)/matiec/iec2c $(build_dir)/beremiz/$(beremiz_checksum).sha1 $(build_dir)/open62541/build/bin/libopen62541.a +$(build_dir)/Modbus/libmb.a: | $(build_dir)/Modbus/$(Modbus_checksum).sha1 + cd $(build_dir)/Modbus && \ + make + + +built_apps: $(build_dir)/matiec/iec2c $(build_dir)/beremiz/$(beremiz_checksum).sha1 $(build_dir)/open62541/build/bin/libopen62541.a $(build_dir)/Modbus/libmb.a touch $@ define log_command diff -r 1d383b4c0a23 -r a6ec38dcbfb5 tests/cli_tests/modbus_test_tcp.bash --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/cli_tests/modbus_test_tcp.bash Thu Apr 04 17:31:49 2024 +0200 @@ -0,0 +1,15 @@ +#!/bin/bash + +# Run python example throug command line, and check usual output + +coproc setsid $BEREMIZPYTHONPATH $BEREMIZPATH/Beremiz_cli.py -k --project-home $BEREMIZPATH/tests/projects/modbus_test_tcp build transfer run; + +while read -u ${COPROC[0]} line; do + echo "$line" + if [[ "$line" == "TEST OK" ]]; then + pkill -9 -s $COPROC_PID + exit 0 + fi +done + +exit 42 diff -r 1d383b4c0a23 -r a6ec38dcbfb5 tests/projects/modbus_test_tcp/beremiz.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/projects/modbus_test_tcp/beremiz.xml Thu Apr 04 17:31:49 2024 +0200 @@ -0,0 +1,6 @@ +<?xml version='1.0' encoding='utf-8'?> +<BeremizRoot xmlns:xsd="http://www.w3.org/2001/XMLSchema" URI_location="LOCAL://"> + <TargetType> + <Linux/> + </TargetType> +</BeremizRoot> diff -r 1d383b4c0a23 -r a6ec38dcbfb5 tests/projects/modbus_test_tcp/modbus_0@modbus/baseconfnode.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/projects/modbus_test_tcp/modbus_0@modbus/baseconfnode.xml Thu Apr 04 17:31:49 2024 +0200 @@ -0,0 +1,2 @@ +<?xml version='1.0' encoding='utf-8'?> +<BaseParams xmlns:xsd="http://www.w3.org/2001/XMLSchema" IEC_Channel="0" Name="modbus_0"/> diff -r 1d383b4c0a23 -r a6ec38dcbfb5 tests/projects/modbus_test_tcp/modbus_0@modbus/confnode.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/projects/modbus_test_tcp/modbus_0@modbus/confnode.xml Thu Apr 04 17:31:49 2024 +0200 @@ -0,0 +1,2 @@ +<?xml version='1.0' encoding='utf-8'?> +<ModbusRoot xmlns:xsd="http://www.w3.org/2001/XMLSchema"/> diff -r 1d383b4c0a23 -r a6ec38dcbfb5 tests/projects/modbus_test_tcp/plc.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/projects/modbus_test_tcp/plc.xml Thu Apr 04 17:31:49 2024 +0200 @@ -0,0 +1,390 @@ +<?xml version='1.0' encoding='utf-8'?> +<project xmlns:ns1="http://www.plcopen.org/xml/tc6_0201" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.plcopen.org/xml/tc6_0201"> + <fileHeader companyName="Beremiz" productName="Beremiz" productVersion="1" creationDateTime="2018-07-27T13:19:12"/> + <contentHeader name="Modbus" modificationDateTime="2024-04-04T17:20:49"> + <coordinateInfo> + <fbd> + <scaling x="0" y="0"/> + </fbd> + <ld> + <scaling x="0" y="0"/> + </ld> + <sfc> + <scaling x="0" y="0"/> + </sfc> + </coordinateInfo> + </contentHeader> + <types> + <dataTypes/> + <pous> + <pou name="program0" pouType="program"> + <interface> + <localVars> + <variable name="Counter"> + <type> + <INT/> + </type> + </variable> + <variable name="CounterReadBack"> + <type> + <INT/> + </type> + </variable> + </localVars> + <localVars> + <variable name="MasterWriteToReg0" address="%QW0.0.0.0"> + <type> + <INT/> + </type> + </variable> + <variable name="MasterReadFromReg1" address="%IW0.0.1.0"> + <type> + <INT/> + </type> + </variable> + <variable name="SlaveHoldReg0" address="%IW0.1.0.0"> + <type> + <WORD/> + </type> + </variable> + <variable name="SlaveInputReg0" address="%QW0.1.1.0"> + <type> + <WORD/> + </type> + </variable> + </localVars> + <localVars> + <variable name="CTU0"> + <type> + <derived name="CTU"/> + </type> + </variable> + <variable name="Generator0"> + <type> + <derived name="Generator"/> + </type> + </variable> + <variable name="TestAllEqual0"> + <type> + <derived name="TestAllEqual"/> + </type> + </variable> + </localVars> + </interface> + <body> + <FBD> + <comment localId="4" height="109" width="350"> + <position x="102" y="438"/> + <content> + <xhtml:p><![CDATA[Modbus TCP Master writes counter value to one holding register on Modbus TCP Slave and reads it back from other input register.]]></xhtml:p> + </content> + </comment> + <comment localId="3" height="407" width="680"> + <position x="21" y="15"/> + <content> + <xhtml:p><![CDATA[This examples shows how to work with Modbus extension. It uses Modbus TCP, but the same functions are available for Modbus RTU as well. Buth protocols are supported. + +Modbus extensions requires native Modbus RTU/TCP library to be installed nearby Beremiz. +Following directory structure is expected: +<Parent directory> + "beremiz" + "Modbus" + +If Modbus library is installed elsewhere, then place corresponding paths +in CFLAGS/LDFLAGS in project settings. + +For GNU/Linux to install Modbus library in parent directory run following commands: +$ hg clone https://bitbucket.org/mjsousa/modbus Modbus +$ cd Modbus +$ make + +After that Modbus extension is ready to be used in Beremiz projects.]]></xhtml:p> + </content> + </comment> + <block localId="5" typeName="CTU" instanceName="CTU0" executionOrderId="0" height="80" width="52"> + <position x="346" y="605"/> + <inputVariables> + <variable formalParameter="CU" edge="rising"> + <connectionPointIn> + <relPosition x="0" y="30"/> + <connection refLocalId="6" formalParameter="OUT"> + <position x="346" y="635"/> + <position x="303" y="635"/> + </connection> + </connectionPointIn> + </variable> + <variable formalParameter="R"> + <connectionPointIn> + <relPosition x="0" y="50"/> + </connectionPointIn> + </variable> + <variable formalParameter="PV"> + <connectionPointIn> + <relPosition x="0" y="70"/> + <connection refLocalId="7"> + <position x="346" y="675"/> + <position x="324" y="675"/> + <position x="324" y="703"/> + <position x="302" y="703"/> + </connection> + </connectionPointIn> + </variable> + </inputVariables> + <inOutVariables/> + <outputVariables> + <variable formalParameter="Q"> + <connectionPointOut> + <relPosition x="52" y="30"/> + </connectionPointOut> + </variable> + <variable formalParameter="CV"> + <connectionPointOut> + <relPosition x="52" y="50"/> + </connectionPointOut> + </variable> + </outputVariables> + </block> + <block localId="6" typeName="Generator" instanceName="Generator0" executionOrderId="0" height="60" width="82"> + <position x="224" y="605"/> + <inputVariables> + <variable formalParameter="PON"> + <connectionPointIn> + <relPosition x="0" y="30"/> + <connection refLocalId="1"> + <position x="224" y="635"/> + <position x="154" y="635"/> + </connection> + </connectionPointIn> + </variable> + <variable formalParameter="POFF"> + <connectionPointIn> + <relPosition x="0" y="50"/> + <connection refLocalId="1"> + <position x="224" y="655"/> + <position x="189" y="655"/> + <position x="189" y="635"/> + <position x="154" y="635"/> + </connection> + </connectionPointIn> + </variable> + </inputVariables> + <inOutVariables/> + <outputVariables> + <variable formalParameter="OUT"> + <connectionPointOut> + <relPosition x="82" y="30"/> + </connectionPointOut> + </variable> + </outputVariables> + </block> + <inVariable localId="1" executionOrderId="0" height="30" width="138" negated="false"> + <position x="16" y="620"/> + <connectionPointOut> + <relPosition x="138" y="15"/> + </connectionPointOut> + <expression>T#1s</expression> + </inVariable> + <inVariable localId="7" executionOrderId="0" height="30" width="138" negated="false"> + <position x="164" y="688"/> + <connectionPointOut> + <relPosition x="138" y="15"/> + </connectionPointOut> + <expression>32767</expression> + </inVariable> + <inOutVariable localId="2" executionOrderId="0" height="30" width="138" negatedOut="false" negatedIn="false"> + <position x="544" y="640"/> + <connectionPointIn> + <relPosition x="0" y="15"/> + <connection refLocalId="5" formalParameter="CV"> + <position x="544" y="655"/> + <position x="398" y="655"/> + </connection> + </connectionPointIn> + <connectionPointOut> + <relPosition x="138" y="15"/> + </connectionPointOut> + <expression>Counter</expression> + </inOutVariable> + <outVariable localId="8" executionOrderId="0" height="30" width="146" negated="false"> + <position x="762" y="640"/> + <connectionPointIn> + <relPosition x="0" y="15"/> + <connection refLocalId="2"> + <position x="762" y="655"/> + <position x="682" y="655"/> + </connection> + </connectionPointIn> + <expression>MasterWriteToReg0</expression> + </outVariable> + <inVariable localId="9" executionOrderId="0" height="30" width="154" negated="false"> + <position x="81" y="747"/> + <connectionPointOut> + <relPosition x="154" y="15"/> + </connectionPointOut> + <expression>MasterReadFromReg1</expression> + </inVariable> + <comment localId="11" height="109" width="350"> + <position x="85" y="825"/> + <content> + <xhtml:p><![CDATA[Modbus TCP Slave just copies received register value from holding register to input register.]]></xhtml:p> + </content> + </comment> + <inVariable localId="12" executionOrderId="0" height="30" width="152" negated="false"> + <position x="82" y="970"/> + <connectionPointOut> + <relPosition x="152" y="15"/> + </connectionPointOut> + <expression>SlaveHoldReg0</expression> + </inVariable> + <outVariable localId="13" executionOrderId="0" height="30" width="123" negated="false"> + <position x="548" y="970"/> + <connectionPointIn> + <relPosition x="0" y="15"/> + <connection refLocalId="12"> + <position x="548" y="985"/> + <position x="234" y="985"/> + </connection> + </connectionPointIn> + <expression>SlaveInputReg0</expression> + </outVariable> + <block localId="14" typeName="TestAllEqual" instanceName="TestAllEqual0" executionOrderId="0" width="106" height="100"> + <position x="763" y="712"/> + <inputVariables> + <variable formalParameter="in0"> + <connectionPointIn> + <relPosition x="0" y="30"/> + </connectionPointIn> + </variable> + <variable formalParameter="in1"> + <connectionPointIn> + <relPosition x="0" y="50"/> + </connectionPointIn> + </variable> + <variable formalParameter="in2"> + <connectionPointIn> + <relPosition x="0" y="70"/> + </connectionPointIn> + </variable> + <variable formalParameter="success"> + <connectionPointIn> + <relPosition x="0" y="90"/> + </connectionPointIn> + </variable> + </inputVariables> + <inOutVariables/> + <outputVariables/> + </block> + <inOutVariable localId="10" executionOrderId="0" width="137" height="30" negatedOut="false" negatedIn="false"> + <position x="547" y="747"/> + <connectionPointIn> + <relPosition x="0" y="15"/> + <connection refLocalId="9"> + <position x="547" y="762"/> + <position x="235" y="762"/> + </connection> + </connectionPointIn> + <connectionPointOut> + <relPosition x="137" y="15"/> + </connectionPointOut> + <expression>CounterReadBack</expression> + </inOutVariable> + <inVariable localId="15" executionOrderId="0" width="26" height="24" negated="false"> + <position x="705" y="770"/> + <connectionPointOut> + <relPosition x="26" y="12"/> + </connectionPointOut> + <expression>5</expression> + </inVariable> + </FBD> + </body> + </pou> + <pou name="Generator" pouType="functionBlock"> + <interface> + <outputVars> + <variable name="OUT"> + <type> + <BOOL/> + </type> + </variable> + </outputVars> + <inputVars> + <variable name="PON"> + <type> + <TIME/> + </type> + </variable> + <variable name="POFF"> + <type> + <TIME/> + </type> + </variable> + </inputVars> + <localVars> + <variable name="T1"> + <type> + <derived name="TON"/> + </type> + </variable> + <variable name="T2"> + <type> + <derived name="TOF"/> + </type> + </variable> + </localVars> + </interface> + <body> + <ST> + <xhtml:p><![CDATA[T1( IN := NOT T2.Q, PT := POFF); +T2( IN := T1.Q, PT := PON); +OUT := T2.Q;]]></xhtml:p> + </ST> + </body> + </pou> + <pou name="TestAllEqual" pouType="functionBlock"> + <interface> + <inputVars> + <variable name="in0"> + <type> + <INT/> + </type> + </variable> + <variable name="in1"> + <type> + <INT/> + </type> + </variable> + <variable name="in2"> + <type> + <INT/> + </type> + </variable> + <variable name="success"> + <type> + <BOOL/> + </type> + </variable> + </inputVars> + </interface> + <body> + <ST> + <xhtml:p><![CDATA[IF in0 = in1 AND in1 = in2 AND NOT(success) THEN + success := TRUE; + { printf("TEST OK\n"); fflush(stdout); } +END_IF;]]></xhtml:p> + </ST> + </body> + </pou> + </pous> + </types> + <instances> + <configurations> + <configuration name="config"> + <resource name="resource1"> + <task name="task0" priority="0" interval="T#20ms"> + <pouInstance name="instance0" typeName="program0"/> + </task> + </resource> + </configuration> + </configurations> + </instances> +</project>