Closed engineerjoe440 closed 3 years ago
I think it is possible to support SEL-styled XML files in the iec-checker
.
Do SEL provide a specification for the XML format they use? Unfortunately, I couldn't find this in the documentation on their site. Maybe this document is only provided to end users?
Furthermore, I think that it would be relatively easy to differentiate "SEL-styled" XML from "PLCOpen" XML due to the usage of the root XML tag being RTACModule.
This is not a problem at all. We can specify the format of the input XML via a command-line argument, or, as you suggest, parse the XML root and detect it automatically.
I do foresee challenges in the implementation regarding object-oriented structures (namely "class" FUNCTION_BLOCKs) in the various structures that are required to define properties, methods, actions, etc.
What does this mean? Do they have some special implementation of object-oriented features? The IEC61131-3 standard defines the concept of the classes, which work in much the same way as in the mainstream object-oriented languages. Using them, the user can define methods, properties, etc. Do SEL support the classes, or do they have something special?
If I'm honest, I think a lot of this could be done on the Python side, making the implementation relatively easy with some regex, but to be truly open, I think that it would be ideal to implement in the OCaml (which is not a language I'm familiar with, but would be more than willing to help contribute towards).
This will be easier to implement in OCaml, as we already have an implementation of PLCopen XML support. The key idea here is to generate the source code in StructuredText from XML.
Gosh... I've been wanting to address your questions since Friday, but I keep finding myself worn out. So I hope that I'll be able to get some examples, and a more well-thought-out response here in the next few days. Thank you so much for your openness and patience. I'm very excited to work with you on this very exciting project!
This is not a problem at all, take your time.
Well, I've finally had some time to recreate the demo function-blocks and programs that you've used in the demo-site as SEL AcSELerator RTAC IEC 61131-3 files. I'm attaching a zipped folder which contains a generic project layout with these files demonstrated in two ways. IEC Checker.zip
The reason for these multiple "demonstrations" is that AcSELerator RTAC software exposes two methods of creating logic, which I'll explain.
The folder structure is as follows:
─ IEC Checker/
└┬─ Navigator Layout.xml
├─ Project Info.xml
├─ POUs/ ( this is the "POUs Space" I'd mentioned )
│ └┬─ Project Information.xml
│ └─ POUs Space/ ( this is just a sub-directory )
│ └┬─ POUSpace_Example.xml
│ ├─ POUSpace_GVL.xml
│ ├─ POUSpace_MAIN_POU.xml
│ ├─ POUSpace_Minimal.xml
│ └─ POUSpace_Simple.xml
│
└─ SEL_RTAC/ ( this is the "Project Space" I'd mentioned )
└┬─ ProjSpace_Example.xml
├─ ProjSpace_GVL1.xml
├─ ProjSpace_MAIN_POU.xml
├─ ProjSpace_Minimal.xml
├─ ProjSpace_Simple.xml
├─ Tag Processor.xml (can be ignored for our purposes - this is specific to the SEL RTAC)
└─ System/ (can be ignored for our purposes - this is specific to the SEL RTAC)
I would think that the most sensible area to focus would be the POUs space, since that's where most advanced 61131 logic is applied. User-logic in the Project Space is normally simple by comparison, and is often not subjected to traditional code review practices. Reducing the scope in this way would also help to make the static analysis focus on variables which have been declared in 61131 logic, rather than custom tags built by the SEL RTAC.
Please let me know what questions you have, I'm sure this is more of a "knowledge dump" than anything else, so I'll be happy to contribute additional thoughts!
Thank you for these examples.
As far as I see, each XML file with IEC61131-3 source code stores it inside two XML tags: <Interface>
and <Implementation>
. <Interface>
have the name of the POU and the variables declaration, whereas <Implementation>
contains the body. This makes sense, because this may be convenient in the implementation of the tooling. We are using something similar in our IDE.
The corresponding enhancement of the iec-checker
will then consist in adding the functionality for traversing a given directory path and parse each file with the .xml
extension. In parsing routine, we will try to find both <Interface>
and <Implementation>
tags and recreate the appropriate POU to run the analysis. If there are no such tags in the file, we are skipping it.
It looks simple and can be implemented. But I want to clarify a few questions first.
Can a single XML file contain more than one POU definition?
Are there any features that allow a user to "import" POUs from other files in the project? For example, can a user uses Function or Function Block POUs defined in the other file? If so, are there some special XML tags, that specify such "include" location, for example, a path to the XML file that contains the imported function?
Is it possible to have the <Interface>
and <Implementation>
tags in the different files? For example, one file contains only the <Interface>
, like C/C++ header (or OCaml's .mli
signature), and another one implements this interface.
Hi @jubnzv ! Thank you for your continued engagement! To answer your questions:
Can a single XML file contain more than one POU definition?
No.
A single XML file will only contain a single POU. That is, however, with the caveat that a single XML file may contain a 61131 class where there are multiple method definitions along with multiple parameters which may have both GET and/or SET methods. Admittedly, this isn't very clear without an example, so I will supply one when I return to my Windows machine on Monday. :)
Are there any features that allow a user to "import" POUs from other files in the project? For example, can a user uses Function or Function Block POUs defined in the other file? If so, are there some special XML tags, that specify such "include" location, for example, a path to the XML file that contains the imported function?
Yes.
It is possible to "import" POUs between files. There are no special XML tags to represent this; rather, it's simply up to the 61131 declaration to call out these operations. By this, I mean that if a POU is going to use a function, the function's call is all that's needed to reference it (i.e., myReturn := myFunctionCall( myArgument );
) Similarly, for function blocks, or classes, they need only be declared in the <Interface>
declaration.
Relating to this, the one item I could potentially see causing concern would be GVL-defined function-block instances. I think that in many cases, this is something that could potentially be treated as an enhancement.
Is it possible to have the
<Interface>
and<Implementation>
tags in the different files? For example, one file contains only the<Interface>
, like C/C++ header (or OCaml's.mli
signature), and another one implements this interface.
No.
Interface and Implementation tags must both be contained within the same file. The only caveat to this is what I mention above where a function block or structure could be instantiated in a GVL, and referenced in a separate POU. Still, those instances of any FB or struct will be required to be defined in a <Interface>
section like they might be declared anywhere else.
I hope that I've answered your preliminary questions. I'm sure that if you're anything like me, you'll have more, so please don't hesitate to ask! I'll do my best to continue providing reasonable answers and example files!
@engineerjoe440 Thank you. I'm going to implement this this week, but I may not have time, because I'm switching a job these days.
I'm not sure about the implementation of the imports, probably they could be implemented later as an improvement.
Thank you @jubnzv! I really appreciate your ongoing support, and your patience with my delayed responses.
I'm attaching a set of files that exemplifies two things:
Please let me know if these examples prompt additional questions, or if there's anything else that I might be able to provide as assistance!
@engineerjoe440 I merged the initial SEL XML format support to the master.
Could you please try it? You'll need to run the following command with the latest version of iec-checker
:
iec-checker -i selxml /path/to/IEC\ Checker/SEL_RTAC
It seems the only thing I'm succeeding with here is falling further behind with fewer responses. Thank you for your patience @jubnzv
I'm very excited to see this progress! It's terrific! I just built locally on Ubuntu and tested, and it worked wonderfully for project-based 61131 evaluation. I did see that I was running into some issues with some content that is utilized in the section of SEL's XML that's used for 61131-library-development, but I think I can help to summarize those items.
For the project checks, here are my results (very exciting!)
output/bin/iec_checker -i selxml /<path>/IEC\ Checker/ -v
Parsing /<path>/Downloads/IEC Checker/Navigator Layout.xml ...
Parsing /<path>/Downloads/IEC Checker/SEL_RTAC/ProjSpace_Minimal.xml ...
Running check for program PROJSPACE_MINIMAL
Parsing /<path>/Downloads/IEC Checker/SEL_RTAC/ProjSpace_Example.xml ...
Running check for function block PROJSPACE_EXAMPLE
4:15 UnusedVariable: Found unused local variable: SOME_OTHER_VAR
4:15 PLCOPEN-CP6: External variables in functions, function blocks and classes should be avoided
3:11 PLCOPEN-CP6: External variables in functions, function blocks and classes should be avoided
4:15 PLCOPEN-CP3: Variable SOME_OTHER_VAR shall be initialized before being used
3:11 PLCOPEN-CP3: Variable GLOBAL_VAR shall be initialized before being used
Parsing /<path>/Downloads/IEC Checker/SEL_RTAC/ProjSpace_MAIN_POU.xml ...
Running check for function block PROJSPACE_MAIN_POU
9:42 UnusedVariable: Found unused local variable: FB4_POPULATE_INTERMEDIATE_CALL_LIST_CALL
10:32 UnusedVariable: Found unused local variable: FB5_TRIGGER_FB2_CALL_FIFO_CALL
29:17 UnusedVariable: Found unused local variable: LASTTARGETFLOOR
19:11 UnusedVariable: Found unused local variable: MAINMOTOR
15:13 UnusedVariable: Found unused local variable: MC_HALT_JOG
14:8 UnusedVariable: Found unused local variable: MC_JOG
18:21 UnusedVariable: Found unused local variable: MC_MOVEABSOLUTE_JOG
11:13 UnusedVariable: Found unused local variable: MC_POWER_X1
12:25 UnusedVariable: Found unused local variable: MC_READAXISPOSITION_JOG
13:19 UnusedVariable: Found unused local variable: MC_READSTATUS_JOG
17:14 UnusedVariable: Found unused local variable: MC_RESET_JOG
16:13 UnusedVariable: Found unused local variable: MC_STOP_JOG
26:32 UnusedVariable: Found unused local variable: NEXTINTERMEDIATETARGETPOSITION
25:20 UnusedVariable: Found unused local variable: NEXTTARGETPOSITION
34:14 UnusedVariable: Found unused local variable: TEST_FORWARD
33:11 UnusedVariable: Found unused local variable: TEST_READ
20:7 UnusedVariable: Found unused local variable: TON_0
21:7 UnusedVariable: Found unused local variable: TON_1
22:7 UnusedVariable: Found unused local variable: TON_2
46:2 PLCOPEN-L17: Each IF instruction should have an ELSE clause
78:5 PLCOPEN-L17: Each IF instruction should have an ELSE clause
80:6 PLCOPEN-L17: Each IF instruction should have an ELSE clause
88:6 PLCOPEN-L17: Each IF instruction should have an ELSE clause
107:6 PLCOPEN-L17: Each IF instruction should have an ELSE clause
127:5 PLCOPEN-L17: Each IF instruction should have an ELSE clause
130:8 PLCOPEN-L17: Each IF instruction should have an ELSE clause
140:6 PLCOPEN-L17: Each IF instruction should have an ELSE clause
145:6 PLCOPEN-L17: Each IF instruction should have an ELSE clause
150:5 PLCOPEN-L17: Each IF instruction should have an ELSE clause
153:8 PLCOPEN-L17: Each IF instruction should have an ELSE clause
163:6 PLCOPEN-L17: Each IF instruction should have an ELSE clause
168:6 PLCOPEN-L17: Each IF instruction should have an ELSE clause
182:5 PLCOPEN-L17: Each IF instruction should have an ELSE clause
197:5 PLCOPEN-L17: Each IF instruction should have an ELSE clause
214:5 PLCOPEN-L17: Each IF instruction should have an ELSE clause
219:5 PLCOPEN-L17: Each IF instruction should have an ELSE clause
0:0 PLCOPEN-CP9: Code is too complex (173 statements)
0:0 PLCOPEN-CP9: Code is too complex (148 McCabe complexity)
34:14 PLCOPEN-CP3: Variable TEST_FORWARD shall be initialized before being used
33:11 PLCOPEN-CP3: Variable TEST_READ shall be initialized before being used
31:3 PLCOPEN-CP3: Variable I shall be initialized before being used
30:21 PLCOPEN-CP3: Variable CURRENTFLOORNUMBER_ shall be initialized before being used
29:17 PLCOPEN-CP3: Variable LASTTARGETFLOOR shall be initialized before being used
28:38 PLCOPEN-CP3: Variable NEXTINTERMEDIATETARGETFLOORAVAILABLE shall be initialized before being used
27:29 PLCOPEN-CP3: Variable NEXTINTERMEDIATETARGETFLOOR shall be initialized before being used
26:32 PLCOPEN-CP3: Variable NEXTINTERMEDIATETARGETPOSITION shall be initialized before being used
25:20 PLCOPEN-CP3: Variable NEXTTARGETPOSITION shall be initialized before being used
24:17 PLCOPEN-CP3: Variable NEXTTARGETFLOOR shall be initialized before being used
23:14 PLCOPEN-CP3: Variable AXISPOSITION shall be initialized before being used
22:7 PLCOPEN-CP3: Variable TON_2 shall be initialized before being used
21:7 PLCOPEN-CP3: Variable TON_1 shall be initialized before being used
20:7 PLCOPEN-CP3: Variable TON_0 shall be initialized before being used
19:11 PLCOPEN-CP3: Variable MAINMOTOR shall be initialized before being used
18:21 PLCOPEN-CP3: Variable MC_MOVEABSOLUTE_JOG shall be initialized before being used
17:14 PLCOPEN-CP3: Variable MC_RESET_JOG shall be initialized before being used
16:13 PLCOPEN-CP3: Variable MC_STOP_JOG shall be initialized before being used
15:13 PLCOPEN-CP3: Variable MC_HALT_JOG shall be initialized before being used
14:8 PLCOPEN-CP3: Variable MC_JOG shall be initialized before being used
13:19 PLCOPEN-CP3: Variable MC_READSTATUS_JOG shall be initialized before being used
12:25 PLCOPEN-CP3: Variable MC_READAXISPOSITION_JOG shall be initialized before being used
11:13 PLCOPEN-CP3: Variable MC_POWER_X1 shall be initialized before being used
10:32 PLCOPEN-CP3: Variable FB5_TRIGGER_FB2_CALL_FIFO_CALL shall be initialized before being used
9:42 PLCOPEN-CP3: Variable FB4_POPULATE_INTERMEDIATE_CALL_LIST_CALL shall be initialized before being used
Parsing /<path>/Downloads/IEC Checker/SEL_RTAC/ProjSpace_GVL1.xml ...
Parsing /<path>/Downloads/IEC Checker/SEL_RTAC/Tag Processor.xml ...
Parsing /<path>/Downloads/IEC Checker/SEL_RTAC/System/System_Time_Control.xml ...
Parsing /<path>/Downloads/IEC Checker/SEL_RTAC/System/Main Controller.xml ...
Parsing /<path>/Downloads/IEC Checker/SEL_RTAC/System/Contact I_O.xml ...
Parsing /<path>/Downloads/IEC Checker/SEL_RTAC/System/SystemTags.xml ...
Parsing /<path>/Downloads/IEC Checker/SEL_RTAC/ProjSpace_Simple.xml ...
Running check for program PROJSPACE_SIMPLE
9:11 UnusedVariable: Found unused local variable: UNUSED_VAR
22:4 OutOfBounds: ARR1 is addressed to 2 dimension, but array was defined with 1 dimensions
21:4 OutOfBounds: ARR1 index 3 is out of range [1 .. 2]
13:3 PLCOPEN-L17: Each IF instruction should have an ELSE clause
23:2 PLCOPEN-L17: Each IF instruction should have an ELSE clause
15:7 PLCOPEN-L10: Usage of CONTINUE and EXIT instruction should be avoid
23:4 PLCOPEN-CP28: Time and physical measures comparissons shall not be equality or inequality
23:4 PLCOPEN-CP28: Time and physical measures comparissons shall not be equality or inequality
3:2 PLCOPEN-CP3: Variable X shall be initialized before being used
10:5 PLCOPEN-CP3: Variable HEAD shall be initialized before being used
8:5 PLCOPEN-CP3: Variable ARR1 shall be initialized before being used
7:2 PLCOPEN-CP3: Variable I shall be initialized before being used
6:5 PLCOPEN-CP3: Variable TEMP shall be initialized before being used
16:4 PLCOPEN-CP2: All code shall be used in the application
Parsing /<path>/Downloads/IEC Checker/POUs/POUs Space/POUSpace_GVL.xml ...
Parsing /<path>/Downloads/IEC Checker/POUs/POUs Space/POUSpace_Simple.xml ...
Running check for program POUSPACE_SIMPLE
9:11 UnusedVariable: Found unused local variable: UNUSED_VAR
23:4 OutOfBounds: ARR1 is addressed to 2 dimension, but array was defined with 1 dimensions
22:4 OutOfBounds: ARR1 index 3 is out of range [1 .. 2]
14:3 PLCOPEN-L17: Each IF instruction should have an ELSE clause
24:2 PLCOPEN-L17: Each IF instruction should have an ELSE clause
16:7 PLCOPEN-L10: Usage of CONTINUE and EXIT instruction should be avoid
24:4 PLCOPEN-CP28: Time and physical measures comparissons shall not be equality or inequality
24:4 PLCOPEN-CP28: Time and physical measures comparissons shall not be equality or inequality
3:2 PLCOPEN-CP3: Variable X shall be initialized before being used
10:5 PLCOPEN-CP3: Variable HEAD shall be initialized before being used
8:5 PLCOPEN-CP3: Variable ARR1 shall be initialized before being used
7:2 PLCOPEN-CP3: Variable I shall be initialized before being used
6:5 PLCOPEN-CP3: Variable TEMP shall be initialized before being used
17:4 PLCOPEN-CP2: All code shall be used in the application
Parsing /<path>/Downloads/IEC Checker/POUs/POUs Space/POUSpace_Minimal.xml ...
Running check for program POUSPACE_MINIMAL
Parsing /<path>/Downloads/IEC Checker/POUs/POUs Space/POUSpace_Example.xml ...
Running check for function block POUSPACE_EXAMPLE
3:11 PLCOPEN-CP6: External variables in functions, function blocks and classes should be avoided
3:11 PLCOPEN-CP3: Variable GLOBAL_VAR shall be initialized before being used
Parsing /<path>/Downloads/IEC Checker/POUs/POUs Space/POUSpace_MAIN_POU.xml ...
Running check for function block POUSPACE_MAIN_POU
9:42 UnusedVariable: Found unused local variable: FB4_POPULATE_INTERMEDIATE_CALL_LIST_CALL
10:32 UnusedVariable: Found unused local variable: FB5_TRIGGER_FB2_CALL_FIFO_CALL
29:17 UnusedVariable: Found unused local variable: LASTTARGETFLOOR
19:11 UnusedVariable: Found unused local variable: MAINMOTOR
15:13 UnusedVariable: Found unused local variable: MC_HALT_JOG
14:8 UnusedVariable: Found unused local variable: MC_JOG
18:21 UnusedVariable: Found unused local variable: MC_MOVEABSOLUTE_JOG
11:13 UnusedVariable: Found unused local variable: MC_POWER_X1
12:25 UnusedVariable: Found unused local variable: MC_READAXISPOSITION_JOG
13:19 UnusedVariable: Found unused local variable: MC_READSTATUS_JOG
17:14 UnusedVariable: Found unused local variable: MC_RESET_JOG
16:13 UnusedVariable: Found unused local variable: MC_STOP_JOG
26:32 UnusedVariable: Found unused local variable: NEXTINTERMEDIATETARGETPOSITION
25:20 UnusedVariable: Found unused local variable: NEXTTARGETPOSITION
34:14 UnusedVariable: Found unused local variable: TEST_FORWARD
33:11 UnusedVariable: Found unused local variable: TEST_READ
20:7 UnusedVariable: Found unused local variable: TON_0
21:7 UnusedVariable: Found unused local variable: TON_1
22:7 UnusedVariable: Found unused local variable: TON_2
46:2 PLCOPEN-L17: Each IF instruction should have an ELSE clause
78:5 PLCOPEN-L17: Each IF instruction should have an ELSE clause
80:6 PLCOPEN-L17: Each IF instruction should have an ELSE clause
88:6 PLCOPEN-L17: Each IF instruction should have an ELSE clause
107:6 PLCOPEN-L17: Each IF instruction should have an ELSE clause
127:5 PLCOPEN-L17: Each IF instruction should have an ELSE clause
130:8 PLCOPEN-L17: Each IF instruction should have an ELSE clause
140:6 PLCOPEN-L17: Each IF instruction should have an ELSE clause
145:6 PLCOPEN-L17: Each IF instruction should have an ELSE clause
150:5 PLCOPEN-L17: Each IF instruction should have an ELSE clause
153:8 PLCOPEN-L17: Each IF instruction should have an ELSE clause
163:6 PLCOPEN-L17: Each IF instruction should have an ELSE clause
168:6 PLCOPEN-L17: Each IF instruction should have an ELSE clause
182:5 PLCOPEN-L17: Each IF instruction should have an ELSE clause
197:5 PLCOPEN-L17: Each IF instruction should have an ELSE clause
214:5 PLCOPEN-L17: Each IF instruction should have an ELSE clause
219:5 PLCOPEN-L17: Each IF instruction should have an ELSE clause
0:0 PLCOPEN-CP9: Code is too complex (173 statements)
0:0 PLCOPEN-CP9: Code is too complex (148 McCabe complexity)
34:14 PLCOPEN-CP3: Variable TEST_FORWARD shall be initialized before being used
33:11 PLCOPEN-CP3: Variable TEST_READ shall be initialized before being used
31:3 PLCOPEN-CP3: Variable I shall be initialized before being used
30:21 PLCOPEN-CP3: Variable CURRENTFLOORNUMBER_ shall be initialized before being used
29:17 PLCOPEN-CP3: Variable LASTTARGETFLOOR shall be initialized before being used
28:38 PLCOPEN-CP3: Variable NEXTINTERMEDIATETARGETFLOORAVAILABLE shall be initialized before being used
27:29 PLCOPEN-CP3: Variable NEXTINTERMEDIATETARGETFLOOR shall be initialized before being used
26:32 PLCOPEN-CP3: Variable NEXTINTERMEDIATETARGETPOSITION shall be initialized before being used
25:20 PLCOPEN-CP3: Variable NEXTTARGETPOSITION shall be initialized before being used
24:17 PLCOPEN-CP3: Variable NEXTTARGETFLOOR shall be initialized before being used
23:14 PLCOPEN-CP3: Variable AXISPOSITION shall be initialized before being used
22:7 PLCOPEN-CP3: Variable TON_2 shall be initialized before being used
21:7 PLCOPEN-CP3: Variable TON_1 shall be initialized before being used
20:7 PLCOPEN-CP3: Variable TON_0 shall be initialized before being used
19:11 PLCOPEN-CP3: Variable MAINMOTOR shall be initialized before being used
18:21 PLCOPEN-CP3: Variable MC_MOVEABSOLUTE_JOG shall be initialized before being used
17:14 PLCOPEN-CP3: Variable MC_RESET_JOG shall be initialized before being used
16:13 PLCOPEN-CP3: Variable MC_STOP_JOG shall be initialized before being used
15:13 PLCOPEN-CP3: Variable MC_HALT_JOG shall be initialized before being used
14:8 PLCOPEN-CP3: Variable MC_JOG shall be initialized before being used
13:19 PLCOPEN-CP3: Variable MC_READSTATUS_JOG shall be initialized before being used
12:25 PLCOPEN-CP3: Variable MC_READAXISPOSITION_JOG shall be initialized before being used
11:13 PLCOPEN-CP3: Variable MC_POWER_X1 shall be initialized before being used
10:32 PLCOPEN-CP3: Variable FB5_TRIGGER_FB2_CALL_FIFO_CALL shall be initialized before being used
9:42 PLCOPEN-CP3: Variable FB4_POPULATE_INTERMEDIATE_CALL_LIST_CALL shall be initialized before being used
Parsing /<path>/Downloads/IEC Checker/POUs/Project Information.xml ...
Parsing /<path>/Downloads/IEC Checker/Project Info.xml ...
MARVELOUS!!!!
As I mentioned in my previous comment; while testing, I observed that the XML files under "POUs" folder were not parsed, I think in a large part, that's due to 2 items.
<RTACModule>
<LogicEngineObject>
<Name>class_ExampleWithMethodsAndProperties</Name>
<Type>FunctionBlock</Type>
<Interface><![CDATA[FUNCTION_BLOCK class_ExampleWithMethodsAndProperties
VAR_INPUT
END_VAR
VAR_OUTPUT
END_VAR
VAR
_aClassVariable : UDINT;
anotherClasVar : UDINT;
END_VAR
]]></Interface>
<Metadata><![CDATA[<Single xml:space="preserve" Type="{81297157-7ec9-45ce-845e-84cab2b88ade}" Method="IArchivable">
<Dictionary Type="{2c41fa04-1834-41c1-816e-303c7aa2c05b}" Name="Properties" />
<Single Name="TypeGuid" Type="System.Guid">6f9dac99-8de1-4efc-8465-68ac443b7d08</Single>
</Single>]]></Metadata>
<ChildObjects>
<LogicEngineObject>
<Name>MyMethod</Name>
<Type>PouMethod</Type>
<Interface><![CDATA[METHOD PUBLIC MyMethod : UDINT
VAR_INPUT
Input1 : BOOL;
Input2 : INT;
END_VAR
]]></Interface>
<Implementation><![CDATA[MyMethod := TO_UDINT( BOOL_TO_INT(Input1) + Input2 );]]></Implementation>
<Metadata><![CDATA[<Single xml:space="preserve" Type="{81297157-7ec9-45ce-845e-84cab2b88ade}" Method="IArchivable">
<Dictionary Type="{2c41fa04-1834-41c1-816e-303c7aa2c05b}" Name="Properties" />
<Single Name="TypeGuid" Type="System.Guid">f8a58466-d7f6-439f-bbb8-d4600e41d099</Single>
</Single>]]></Metadata>
</LogicEngineObject>
<LogicEngineObject>
<Name>MyProperty</Name>
<Type>PouProperty</Type>
<Interface><![CDATA[PROPERTY PUBLIC MyProperty : UDINT]]></Interface>
<Metadata><![CDATA[<Single xml:space="preserve" Type="{81297157-7ec9-45ce-845e-84cab2b88ade}" Method="IArchivable">
<Dictionary Type="{2c41fa04-1834-41c1-816e-303c7aa2c05b}" Name="Properties" />
<Single Name="TypeGuid" Type="System.Guid">5a3b8626-d3e9-4f37-98b5-66420063d91e</Single>
</Single>]]></Metadata>
<ChildObjects>
<LogicEngineObject>
<Name>Set</Name>
<Type>PouPropertySetter</Type>
<Interface><![CDATA[VAR
END_VAR
]]></Interface>
<Implementation><![CDATA[// Load the class' variable
_aClassVariable := MyProperty;]]></Implementation>
<Metadata><![CDATA[<Single xml:space="preserve" Type="{81297157-7ec9-45ce-845e-84cab2b88ade}" Method="IArchivable">
<Dictionary Type="{2c41fa04-1834-41c1-816e-303c7aa2c05b}" Name="Properties" />
<Single Name="TypeGuid" Type="System.Guid">792f2eb6-721e-4e64-ba20-bc98351056db</Single>
</Single>]]></Metadata>
</LogicEngineObject>
<LogicEngineObject>
<Name>Get</Name>
<Type>PouPropertyGetter</Type>
<Interface><![CDATA[VAR
END_VAR
]]></Interface>
<Implementation><![CDATA[// Return the class' internal variable
MyProperty := _aClassVariable;]]></Implementation>
<Metadata><![CDATA[<Single xml:space="preserve" Type="{81297157-7ec9-45ce-845e-84cab2b88ade}" Method="IArchivable">
<Dictionary Type="{2c41fa04-1834-41c1-816e-303c7aa2c05b}" Name="Properties" />
<Single Name="TypeGuid" Type="System.Guid">792f2eb6-721e-4e64-ba20-bc98351056db</Single>
</Single>]]></Metadata>
</LogicEngineObject>
</ChildObjects>
</LogicEngineObject>
</ChildObjects>
</LogicEngineObject>
</RTACModule>
Thank you again!
Hi @engineerjoe440,
I'm glad something is working here.
- First, I think that the difference in the XML tags is causing some problems. See in the screenshot below how the POU type is contained in a "Type" tag, not the "POUKind" like the other files.
1f98e83837b3348b6d491795dc77361a1fed9bff should fix it.
- Second, it seems that there is only support for standard structures. Items like functions/function-blocks/gvls/etc., not more advanced structures like function-block oriented classes like the following. I suspect that's just an intentional focus on the standard formats, were there plans on enhancing to support class-like structures?
No, I have no plans to add support for non-standard structures.
The point is that I'm not sure how these structures are internally implemented, and what pitfalls could be there. It is also not possible to properly maintain such functionality for me, because the implementation is proprietary, and I've never even seen these PLCs.
But I am open to contributions, if they do not break the existing functionality. If you have the time and desire to extend SEL support, this is more than welcome. You can create PRs and ask questions about the implementation, and I will try to help as soon as possible.
Thank you for all of your efforts and willingness to help! I think that this is a great point to call victory on this issue. I'm sure I'll be back with more, but I've got to learn more about OCaml first!
Thank you agaian!
Request:
I wonder if it might be possible to explore adding parsing support for SEL-styled XML files which are the standard export format for the SEL RTAC platform. The SEL RTAC uses the CODESYS logic engine to support 61131-3 development, so any syntactical differences encountered would likely apply to both the RTAC and CODESYS, leading to better support for both platforms as a whole.
Benefit:
I believe that this would help expand the adoption of this tool to parties interested in "linting" their RTAC logic configurations and developed libraries. Additionally, I think it would help to improve open-standards for development style by providing a more consistent base from which engineers can build upon.
Concept and Challenges:
I think for "flat" POUs and DUTs, the development of the parser would be quite simple (for the most part) as the files tend to exhibit the standard "interface/implementation" keyword-marked sections.
Furthermore, I think that it would be relatively easy to differentiate "SEL-styled" XML from "PLCOpen" XML due to the usage of the root XML tag being
RTACModule
.I do foresee challenges in the implementation regarding object-oriented structures (namely "class" FUNCTION_BLOCKs) in the various structures that are required to define properties, methods, actions, etc.
If I'm honest, I think a lot of this could be done on the Python side, making the implementation relatively easy with some regex, but to be truly open, I think that it would be ideal to implement in the OCaml (which is not a language I'm familiar with, but would be more than willing to help contribute towards).