Published on

Why we need LadderScript

Authors
  • avatar
    Name
    Szymon Palczynski
    Twitter

Introduction

In PLC programming, managing ladder logic files can be tricky. Different PLC vendors store their files in various formats, often using binary files that make it hard to use tools like Git for version control. Some vendors offer XML exports, but these are still difficult to read and handle. LadderScript aims to fix this by providing a standard, easy-to-read text format for ladder logic.

How different PLC vendors store Ladder Logic

Binary Formats

Most PLC vendors use binary formats to store their project files. This makes it tough to use version control tools because binary files are not easy to compare or merge. This is very different from traditional software development, where text-based code is the norm.

XML Formats

Some vendors allow projects to be exported in XML format, which is better but still not ideal. Each vendor uses a different XML format, and these files are often hard to read. Here are some examples of how different PLC vendors store their project files in XML.

Sample ladder logic diagram

PLCopenXML

PLCopen XML tries to set a standard for storing ladder logic in XML. While it is better than binary, it is still complicated and hard to read.

<FunctionBlock name="LD_FB">
  <Parameters>
    <OutputVars>
      <Variable name="Output" orderWithinParamSet="1">
        <Type>
          <TypeName>BOOL</TypeName>
        </Type>
      </Variable>
    </OutputVars>
  </Parameters>
  <Vars accessSpecifier="private">
    <Variable name="S1">
      <Type>
        <TypeName>BOOL</TypeName>
      </Type>
      <InitialValue>
        <SimpleValue value="TRUE" />
      </InitialValue>
    </Variable>
    <Variable name="S2">
      <Type>
        <TypeName>BOOL</TypeName>
      </Type>
    </Variable>
    <Variable name="S1TON">
      <Type>
        <TypeName>TON</TypeName>
      </Type>
    </Variable>
    <Variable name="S2TON">
      <Type>
        <TypeName>TON</TypeName>
      </Type>
    </Variable>
  </Vars>
  <MainBody>
    <BodyContent xsi:type="LD">
      <Rung evaluationOrder="1">
        <RelPosition x="1" y="1" />
        <CommonObject xsi:type="Comment">
          <RelPosition x="1" y="0" />
          <Content xsi:type="SimpleText">S1 -> S2</Content>
        </CommonObject>
        <LdObject xsi:type="LeftPowerRail">
          <RelPosition x="1" y="0" />
          <ConnectionPointOut connectionPointOutId="1">
            <RelPosition x="0" y="7" />
          </ConnectionPointOut>
          <ConnectionPointOut connectionPointOutId="2">
            <RelPosition x="0" y="15" />
          </ConnectionPointOut>
        </LdObject>
        <LdObject xsi:type="Contact" operand="S1">
          <RelPosition x="4" y="4" />
          <ConnectionPointIn>
            <RelPosition x="2" y="3" />
            <Connection refConnectionPointOutId="1" />
          </ConnectionPointIn>
          <ConnectionPointOut connectionPointOutId="3">
            <RelPosition x="4" y="3" />
          </ConnectionPointOut>
        </LdObject>
        <FbdObject xsi:type="DataSource" identifier="T#1s">
          <RelPosition x="8" y="9" />
          <ConnectionPointOut connectionPointOutId="4">
            <RelPosition x="4.2" y="1" />
          </ConnectionPointOut>
        </FbdObject>
        <FbdObject xsi:type="Block" typeName="TON" instanceName="S1TON">
          <RelPosition x="13" y="4" />
          <InputVariables>
            <InputVariable parameterName="IN">
              <ConnectionPointIn>
                <RelPosition x="0" y="3" />
                <Connection refConnectionPointOutId="3" />
              </ConnectionPointIn>
            </InputVariable>
            <InputVariable parameterName="PT">
              <ConnectionPointIn>
                <RelPosition x="0" y="6" />
                <Connection refConnectionPointOutId="4" />
              </ConnectionPointIn>
            </InputVariable>
          </InputVariables>
          <OutputVariables>
            <OutputVariable parameterName="Q">
              <ConnectionPointOut connectionPointOutId="5">
                <RelPosition x="5" y="3" />
              </ConnectionPointOut>
            </OutputVariable>
            <OutputVariable parameterName="ET">
              <ConnectionPointOut connectionPointOutId="6">
                <RelPosition x="5" y="6" />
              </ConnectionPointOut>
            </OutputVariable>
          </OutputVariables>
        </FbdObject>
        <LdObject xsi:type="Contact" operand="S2">
          <RelPosition x="4" y="12" />
          <ConnectionPointIn>
            <RelPosition x="2" y="3" />
            <Connection refConnectionPointOutId="2"></Connection>
          </ConnectionPointIn>
          <ConnectionPointOut connectionPointOutId="7">
            <RelPosition x="4" y="3" />
          </ConnectionPointOut>
        </LdObject>
        <LdObject xsi:type="Coil" operand="S2">
          <RelPosition x="32" y="4" />
          <ConnectionPointIn>
            <RelPosition x="2" y="3" />
            <Connection refConnectionPointOutId="5" />
            <Connection refConnectionPointOutId="7">
              <RelPosition x="-10" y="0" />
              <RelPosition x="-10" y="8" />
            </Connection>
          </ConnectionPointIn>
          <ConnectionPointOut connectionPointOutId="8">
            <RelPosition x="4" y="3" />
          </ConnectionPointOut>
        </LdObject>
        <LdObject xsi:type="RightPowerRail">
          <RelPosition x="40" y="0" />
          <ConnectionPointIn>
            <RelPosition x="0" y="7" />
            <Connection refConnectionPointOutId="8" />
          </ConnectionPointIn>
        </LdObject>
      </Rung>
      <Rung evaluationOrder="2">
        <RelPosition x="1" y="18" />
        <LdObject xsi:type="LeftPowerRail">
          <RelPosition x="1" y="0" />
          <ConnectionPointOut connectionPointOutId="1">
            <RelPosition x="0" y="5" />
          </ConnectionPointOut>
        </LdObject>
        <LdObject xsi:type="Contact" negated="true" operand="S1TON.Q">
          <RelPosition x="4" y="2" />
          <ConnectionPointIn>
            <RelPosition x="2" y="3" />
            <Connection refConnectionPointOutId="1" />
          </ConnectionPointIn>
          <ConnectionPointOut connectionPointOutId="2">
            <RelPosition x="4" y="3" />
          </ConnectionPointOut>
        </LdObject>
        <LdObject xsi:type="Contact" operand="S1">
          <RelPosition x="11" y="2" />
          <ConnectionPointIn>
            <RelPosition x="2" y="3" />
            <Connection refConnectionPointOutId="2" />
          </ConnectionPointIn>
          <ConnectionPointOut connectionPointOutId="3">
            <RelPosition x="4" y="3" />
          </ConnectionPointOut>
        </LdObject>
        <LdObject xsi:type="Coil" operand="S1">
          <RelPosition x="32" y="2" />
          <ConnectionPointIn>
            <RelPosition x="2" y="3" />
            <Connection refConnectionPointOutId="3" />
          </ConnectionPointIn>
          <ConnectionPointOut connectionPointOutId="4">
            <RelPosition x="4" y="3" />
          </ConnectionPointOut>
        </LdObject>
        <LdObject xsi:type="RightPowerRail">
          <RelPosition x="40" y="0" />
          <ConnectionPointIn>
            <RelPosition x="0" y="5" />
            <Connection refConnectionPointOutId="4" />
          </ConnectionPointIn>
        </LdObject>
      </Rung>
      <Rung evaluationOrder="3">
        <RelPosition x="1" y="26" />
        <CommonObject xsi:type="Comment">
          <RelPosition x="1" y="0" />
          <Content xsi:type="SimpleText">S2 -> S1</Content>
        </CommonObject>
        <LdObject xsi:type="LeftPowerRail">
          <RelPosition x="1" y="0" />
          <ConnectionPointOut connectionPointOutId="1">
            <RelPosition x="0" y="7" />
          </ConnectionPointOut>
          <ConnectionPointOut connectionPointOutId="2">
            <RelPosition x="0" y="15" />
          </ConnectionPointOut>
        </LdObject>
        <LdObject xsi:type="Contact" operand="S2">
          <RelPosition x="4" y="4" />
          <ConnectionPointIn>
            <RelPosition x="2" y="3" />
            <Connection refConnectionPointOutId="1" />
          </ConnectionPointIn>
          <ConnectionPointOut connectionPointOutId="3">
            <RelPosition x="4" y="3" />
          </ConnectionPointOut>
        </LdObject>
        <FbdObject xsi:type="DataSource" identifier="T#1s">
          <RelPosition x="8" y="9" />
          <ConnectionPointOut connectionPointOutId="4">
            <RelPosition x="4.2" y="1" />
          </ConnectionPointOut>
        </FbdObject>
        <FbdObject xsi:type="Block" typeName="TON" instanceName="S2TON">
          <RelPosition x="13" y="4" />
          <InputVariables>
            <InputVariable parameterName="IN">
              <ConnectionPointIn>
                <RelPosition x="0" y="3" />
                <Connection refConnectionPointOutId="3" />
              </ConnectionPointIn>
            </InputVariable>
            <InputVariable parameterName="PT">
              <ConnectionPointIn>
                <RelPosition x="0" y="6" />
                <Connection refConnectionPointOutId="4" />
              </ConnectionPointIn>
            </InputVariable>
          </InputVariables>
          <OutputVariables>
            <OutputVariable parameterName="Q">
              <ConnectionPointOut connectionPointOutId="5">
                <RelPosition x="5" y="3" />
              </ConnectionPointOut>
            </OutputVariable>
            <OutputVariable parameterName="ET">
              <ConnectionPointOut connectionPointOutId="6">
                <RelPosition x="5" y="6" />
              </ConnectionPointOut>
            </OutputVariable>
          </OutputVariables>
        </FbdObject>
        <LdObject xsi:type="Contact" operand="S1">
          <RelPosition x="4" y="12" />
          <ConnectionPointIn>
            <RelPosition x="2" y="3" />
            <Connection refConnectionPointOutId="2"></Connection>
          </ConnectionPointIn>
          <ConnectionPointOut connectionPointOutId="7">
            <RelPosition x="4" y="3" />
          </ConnectionPointOut>
        </LdObject>
        <LdObject xsi:type="Coil" operand="S1">
          <RelPosition x="32" y="4" />
          <ConnectionPointIn>
            <RelPosition x="2" y="3" />
            <Connection refConnectionPointOutId="5" />
            <Connection refConnectionPointOutId="7">
              <RelPosition x="-10" y="0" />
              <RelPosition x="-10" y="8" />
            </Connection>
          </ConnectionPointIn>
          <ConnectionPointOut connectionPointOutId="8">
            <RelPosition x="4" y="3" />
          </ConnectionPointOut>
        </LdObject>
        <LdObject xsi:type="RightPowerRail">
          <RelPosition x="40" y="0" />
          <ConnectionPointIn>
            <RelPosition x="0" y="7" />
            <Connection refConnectionPointOutId="8" />
          </ConnectionPointIn>
        </LdObject>
      </Rung>
      <Rung evaluationOrder="4">
        <RelPosition x="1" y="43" />
        <LdObject xsi:type="LeftPowerRail">
          <RelPosition x="1" y="0" />
          <ConnectionPointOut connectionPointOutId="1">
            <RelPosition x="0" y="5" />
          </ConnectionPointOut>
        </LdObject>
        <LdObject xsi:type="Contact" negated="true" operand="S2TON.Q">
          <RelPosition x="4" y="2" />
          <ConnectionPointIn>
            <RelPosition x="2" y="3" />
            <Connection refConnectionPointOutId="1" />
          </ConnectionPointIn>
          <ConnectionPointOut connectionPointOutId="2">
            <RelPosition x="4" y="3" />
          </ConnectionPointOut>
        </LdObject>
        <LdObject xsi:type="Contact" operand="S2">
          <RelPosition x="11" y="2" />
          <ConnectionPointIn>
            <RelPosition x="2" y="3" />
            <Connection refConnectionPointOutId="2" />
          </ConnectionPointIn>
          <ConnectionPointOut connectionPointOutId="3">
            <RelPosition x="4" y="3" />
          </ConnectionPointOut>
        </LdObject>
        <LdObject xsi:type="Coil" operand="S2">
          <RelPosition x="32" y="2" />
          <ConnectionPointIn>
            <RelPosition x="2" y="3" />
            <Connection refConnectionPointOutId="3" />
          </ConnectionPointIn>
          <ConnectionPointOut connectionPointOutId="4">
            <RelPosition x="4" y="3" />
          </ConnectionPointOut>
        </LdObject>
        <LdObject xsi:type="RightPowerRail">
          <RelPosition x="40" y="0" />
          <ConnectionPointIn>
            <RelPosition x="0" y="5" />
            <Connection refConnectionPointOutId="4" />
          </ConnectionPointIn>
        </LdObject>
      </Rung>
      <Rung evaluationOrder="5">
        <RelPosition x="1" y="51" />
        <CommonObject xsi:type="Comment">
          <RelPosition x="1" y="0" />
          <Content xsi:type="SimpleText">Output</Content>
        </CommonObject>
        <LdObject xsi:type="LeftPowerRail">
          <RelPosition x="1" y="0" />
          <ConnectionPointOut connectionPointOutId="1">
            <RelPosition x="0" y="5" />
          </ConnectionPointOut>
        </LdObject>
        <LdObject xsi:type="Contact" operand="S1">
          <RelPosition x="4" y="2" />
          <ConnectionPointIn>
            <RelPosition x="2" y="3" />
            <Connection refConnectionPointOutId="1" />
          </ConnectionPointIn>
          <ConnectionPointOut connectionPointOutId="2">
            <RelPosition x="4" y="3" />
          </ConnectionPointOut>
        </LdObject>
        <LdObject xsi:type="Coil" operand="Output">
          <RelPosition x="32" y="2" />
          <ConnectionPointIn>
            <RelPosition x="2" y="3" />
            <Connection refConnectionPointOutId="2" />
          </ConnectionPointIn>
          <ConnectionPointOut connectionPointOutId="3">
            <RelPosition x="4" y="3" />
          </ConnectionPointOut>
        </LdObject>
        <LdObject xsi:type="RightPowerRail">
          <RelPosition x="40" y="0" />
          <ConnectionPointIn>
            <RelPosition x="0" y="5" />
            <Connection refConnectionPointOutId="3" />
          </ConnectionPointIn>
        </LdObject>
      </Rung>
    </BodyContent>
  </MainBody>
</FunctionBlock>

Codesys

Codesys uses PLCopenXML for exports, but the structure is different. For example element position values are always 0 which mean that they are probably ignored by the editor.

      <pou name="PLC_PRG" pouType="program">
        <interface>
          <localVars>
            <variable name="S1">
              <type>
                <BOOL />
              </type>
            </variable>
            <variable name="S2">
              <type>
                <BOOL />
              </type>
            </variable>
            <variable name="S1TON">
              <type>
                <derived name="TON" />
              </type>
            </variable>
            <variable name="S2TON">
              <type>
                <derived name="TON" />
              </type>
            </variable>
          </localVars>
          <outputVars>
            <variable name="Output">
              <type>
                <BOOL />
              </type>
            </variable>
          </outputVars>
        </interface>
        <body>
          <LD>
            <leftPowerRail localId="0">
              <position x="0" y="0" />
              <connectionPointOut formalParameter="none" />
            </leftPowerRail>
            <comment localId="1" height="0" width="0">
              <position x="0" y="0" />
              <content>
                <xhtml xmlns="http://www.w3.org/1999/xhtml" />
              </content>
            </comment>
            <vendorElement localId="2">
              <position x="0" y="0" />
              <alternativeText>
                <xhtml xmlns="http://www.w3.org/1999/xhtml" />
              </alternativeText>
              <addData>
                <data name="http://www.3s-software.com/plcopenxml/fbdelementtype" handleUnknown="implementation">
                  <ElementType xmlns="">networktitle</ElementType>
                </data>
              </addData>
            </vendorElement>
            <contact localId="5" negated="false" storage="none" edge="none">
              <position x="0" y="0" />
              <connectionPointIn>
                <connection refLocalId="0" />
              </connectionPointIn>
              <connectionPointOut />
              <variable>S1</variable>
            </contact>
            <inVariable localId="6">
              <position x="0" y="0" />
              <connectionPointOut />
              <expression>T#1S</expression>
            </inVariable>
            <block localId="4" typeName="TON" instanceName="S1TON">
              <position x="0" y="0" />
              <inputVariables>
                <variable formalParameter="IN">
                  <connectionPointIn>
                    <connection refLocalId="5" />
                  </connectionPointIn>
                </variable>
                <variable formalParameter="PT">
                  <connectionPointIn>
                    <connection refLocalId="6" />
                  </connectionPointIn>
                </variable>
              </inputVariables>
              <inOutVariables />
              <outputVariables>
                <variable formalParameter="Q">
                  <connectionPointOut />
                </variable>
                <variable formalParameter="ET">
                  <connectionPointOut>
                    <expression />
                  </connectionPointOut>
                </variable>
              </outputVariables>
              <addData>
                <data name="http://www.3s-software.com/plcopenxml/fbdcalltype" handleUnknown="implementation">
                  <CallType xmlns="">functionblock</CallType>
                </data>
              </addData>
            </block>
            <contact localId="7" negated="false" storage="none" edge="none">
              <position x="0" y="0" />
              <connectionPointIn>
                <connection refLocalId="0" />
              </connectionPointIn>
              <connectionPointOut />
              <variable>S2</variable>
            </contact>
            <vendorElement localId="3">
              <position x="0" y="0" />
              <alternativeText>
                <xhtml xmlns="http://www.w3.org/1999/xhtml">ParallelBranch</xhtml>
              </alternativeText>
              <addData>
                <data name="http://www.3s-software.com/plcopenxml/ldparallelbranch" handleUnknown="implementation">
                  <ParallelBranch mode="seq" xmlns="">
                    <BranchInput>
                      <connectionPointIn>
                        <connection refLocalId="0" />
                      </connectionPointIn>
                    </BranchInput>
                    <BranchTrees>
                      <Tree>
                        <connectionPointIn>
                          <connection refLocalId="4" formalParameter="Q" />
                        </connectionPointIn>
                      </Tree>
                      <Tree>
                        <connectionPointIn>
                          <connection refLocalId="7" />
                        </connectionPointIn>
                      </Tree>
                    </BranchTrees>
                  </ParallelBranch>
                </data>
              </addData>
            </vendorElement>
            <coil localId="8" negated="false" storage="none">
              <position x="0" y="0" />
              <connectionPointIn>
                <connection refLocalId="4" />
                <connection refLocalId="7" />
              </connectionPointIn>
              <connectionPointOut />
              <variable>S2</variable>
            </coil>
            <comment localId="9" height="0" width="0">
              <position x="0" y="0" />
              <content>
                <xhtml xmlns="http://www.w3.org/1999/xhtml" />
              </content>
            </comment>
            <vendorElement localId="10">
              <position x="0" y="0" />
              <alternativeText>
                <xhtml xmlns="http://www.w3.org/1999/xhtml" />
              </alternativeText>
              <addData>
                <data name="http://www.3s-software.com/plcopenxml/fbdelementtype" handleUnknown="implementation">
                  <ElementType xmlns="">networktitle</ElementType>
                </data>
              </addData>
            </vendorElement>
            <contact localId="11" negated="true" storage="none" edge="none">
              <position x="0" y="0" />
              <connectionPointIn>
                <connection refLocalId="0" />
              </connectionPointIn>
              <connectionPointOut />
              <variable>S1TON.Q</variable>
            </contact>
            <contact localId="12" negated="false" storage="none" edge="none">
              <position x="0" y="0" />
              <connectionPointIn>
                <connection refLocalId="11" />
              </connectionPointIn>
              <connectionPointOut />
              <variable>S1</variable>
            </contact>
            <coil localId="13" negated="false" storage="none">
              <position x="0" y="0" />
              <connectionPointIn>
                <connection refLocalId="12" />
              </connectionPointIn>
              <connectionPointOut />
              <variable>S1</variable>
            </coil>
            <comment localId="14" height="0" width="0">
              <position x="0" y="0" />
              <content>
                <xhtml xmlns="http://www.w3.org/1999/xhtml" />
              </content>
            </comment>
            <vendorElement localId="15">
              <position x="0" y="0" />
              <alternativeText>
                <xhtml xmlns="http://www.w3.org/1999/xhtml" />
              </alternativeText>
              <addData>
                <data name="http://www.3s-software.com/plcopenxml/fbdelementtype" handleUnknown="implementation">
                  <ElementType xmlns="">networktitle</ElementType>
                </data>
              </addData>
            </vendorElement>
            <contact localId="17" negated="false" storage="none" edge="none">
              <position x="0" y="0" />
              <connectionPointIn>
                <connection refLocalId="0" />
              </connectionPointIn>
              <connectionPointOut />
              <variable>S2</variable>
            </contact>
            <inVariable localId="18">
              <position x="0" y="0" />
              <connectionPointOut />
              <expression>T#1S</expression>
            </inVariable>
            <block localId="16" typeName="TON" instanceName="S2TON">
              <position x="0" y="0" />
              <inputVariables>
                <variable formalParameter="IN">
                  <connectionPointIn>
                    <connection refLocalId="17" />
                  </connectionPointIn>
                </variable>
                <variable formalParameter="PT">
                  <connectionPointIn>
                    <connection refLocalId="18" />
                  </connectionPointIn>
                </variable>
              </inputVariables>
              <inOutVariables />
              <outputVariables>
                <variable formalParameter="Q">
                  <connectionPointOut />
                </variable>
                <variable formalParameter="ET">
                  <connectionPointOut>
                    <expression />
                  </connectionPointOut>
                </variable>
              </outputVariables>
              <addData>
                <data name="http://www.3s-software.com/plcopenxml/fbdcalltype" handleUnknown="implementation">
                  <CallType xmlns="">functionblock</CallType>
                </data>
              </addData>
            </block>
            <contact localId="19" negated="false" storage="none" edge="none">
              <position x="0" y="0" />
              <connectionPointIn>
                <connection refLocalId="0" />
              </connectionPointIn>
              <connectionPointOut />
              <variable>S1</variable>
            </contact>
            <coil localId="20" negated="false" storage="none">
              <position x="0" y="0" />
              <connectionPointIn>
                <connection refLocalId="16" />
                <connection refLocalId="19" />
              </connectionPointIn>
              <connectionPointOut />
              <variable>S1</variable>
            </coil>
            <comment localId="21" height="0" width="0">
              <position x="0" y="0" />
              <content>
                <xhtml xmlns="http://www.w3.org/1999/xhtml" />
              </content>
            </comment>
            <vendorElement localId="22">
              <position x="0" y="0" />
              <alternativeText>
                <xhtml xmlns="http://www.w3.org/1999/xhtml" />
              </alternativeText>
              <addData>
                <data name="http://www.3s-software.com/plcopenxml/fbdelementtype" handleUnknown="implementation">
                  <ElementType xmlns="">networktitle</ElementType>
                </data>
              </addData>
            </vendorElement>
            <contact localId="23" negated="true" storage="none" edge="none">
              <position x="0" y="0" />
              <connectionPointIn>
                <connection refLocalId="0" />
              </connectionPointIn>
              <connectionPointOut />
              <variable>S2TON.Q</variable>
            </contact>
            <contact localId="24" negated="false" storage="none" edge="none">
              <position x="0" y="0" />
              <connectionPointIn>
                <connection refLocalId="23" />
              </connectionPointIn>
              <connectionPointOut />
              <variable>S2</variable>
            </contact>
            <coil localId="25" negated="false" storage="none">
              <position x="0" y="0" />
              <connectionPointIn>
                <connection refLocalId="24" />
              </connectionPointIn>
              <connectionPointOut />
              <variable>S2</variable>
            </coil>
            <comment localId="26" height="0" width="0">
              <position x="0" y="0" />
              <content>
                <xhtml xmlns="http://www.w3.org/1999/xhtml" />
              </content>
            </comment>
            <vendorElement localId="27">
              <position x="0" y="0" />
              <alternativeText>
                <xhtml xmlns="http://www.w3.org/1999/xhtml" />
              </alternativeText>
              <addData>
                <data name="http://www.3s-software.com/plcopenxml/fbdelementtype" handleUnknown="implementation">
                  <ElementType xmlns="">networktitle</ElementType>
                </data>
              </addData>
            </vendorElement>
            <contact localId="28" negated="false" storage="none" edge="none">
              <position x="0" y="0" />
              <connectionPointIn>
                <connection refLocalId="0" />
              </connectionPointIn>
              <connectionPointOut />
              <variable>S1</variable>
            </contact>
            <coil localId="29" negated="false" storage="none">
              <position x="0" y="0" />
              <connectionPointIn>
                <connection refLocalId="28" />
              </connectionPointIn>
              <connectionPointOut />
              <variable>Output</variable>
            </coil>
            <rightPowerRail localId="2147483646">
              <position x="0" y="0" />
              <connectionPointIn />
            </rightPowerRail>
          </LD>
        </body>
        <addData>
          <data name="http://www.3s-software.com/plcopenxml/objectid" handleUnknown="discard">
            <ObjectId>6b7e38b6-d20c-49d8-8996-c2bab4f21546</ObjectId>
          </data>
        </addData>
      </pou>

Siemens TIA Portal

Siemens TIA Portal has a version control workspace where program files are stored as XML, providing a structured but complex format.

<?xml version="1.0" encoding="utf-8"?>
<Document>
  <Engineering version="V17" />
  <DocumentInfo>
    <Created>2024-06-24T19:29:50.1427684Z</Created>
    <ExportSetting>WithDefaults</ExportSetting>
    <InstalledProducts>
      <Product>
        <DisplayName>Totally Integrated Automation Portal</DisplayName>
        <DisplayVersion>V17 Update 6</DisplayVersion>
      </Product>
      <OptionPackage>
        <DisplayName>TIA Portal Openness</DisplayName>
        <DisplayVersion>V17 Update 6</DisplayVersion>
      </OptionPackage>
      <OptionPackage>
        <DisplayName>TIA Portal Teamcenter Gateway</DisplayName>
        <DisplayVersion>V17 Update 6</DisplayVersion>
      </OptionPackage>
      <OptionPackage>
        <DisplayName>TIA Portal Version Control Interface</DisplayName>
        <DisplayVersion>V17</DisplayVersion>
      </OptionPackage>
      <Product>
        <DisplayName>STEP 7 Professional</DisplayName>
        <DisplayVersion>V17 Update 6</DisplayVersion>
      </Product>
      <OptionPackage>
        <DisplayName>STEP 7 Safety</DisplayName>
        <DisplayVersion>V17 Update 6</DisplayVersion>
      </OptionPackage>
      <Product>
        <DisplayName>WinCC Advanced / Unified PC</DisplayName>
        <DisplayVersion>V17 Update 6</DisplayVersion>
      </Product>
    </InstalledProducts>
  </DocumentInfo>
  <SW.Blocks.FB ID="0">
    <AttributeList>
      <AutoNumber>true</AutoNumber>
      <HeaderAuthor />
      <HeaderFamily />
      <HeaderName />
      <HeaderVersion>0.1</HeaderVersion>
      <Interface><Sections xmlns="http://www.siemens.com/automation/Openness/SW/Interface/v5">
  <Section Name="Input" />
  <Section Name="Output">
    <Member Name="Output" Datatype="Bool" Remanence="NonRetain" Accessibility="Public"><AttributeList><BooleanAttribute Name="ExternalAccessible" SystemDefined="true">true</BooleanAttribute><BooleanAttribute Name="ExternalVisible" SystemDefined="true">true</BooleanAttribute><BooleanAttribute Name="ExternalWritable" SystemDefined="true">true</BooleanAttribute></AttributeList></Member>
  </Section>
  <Section Name="InOut" />
  <Section Name="Static">
    <Member Name="S1TON" Datatype="TON_TIME" Version="1.0" Remanence="NonRetain" Accessibility="Public"><AttributeList><BooleanAttribute Name="ExternalAccessible" SystemDefined="true">true</BooleanAttribute><BooleanAttribute Name="ExternalVisible" SystemDefined="true">true</BooleanAttribute><BooleanAttribute Name="ExternalWritable" SystemDefined="true">true</BooleanAttribute><BooleanAttribute Name="SetPoint" SystemDefined="true">true</BooleanAttribute></AttributeList><Sections><Section Name="None"><Member Name="PT" Datatype="Time" /><Member Name="ET" Datatype="Time" /><Member Name="IN" Datatype="Bool" /><Member Name="Q" Datatype="Bool" /></Section></Sections></Member>
    <Member Name="S2TON" Datatype="TON_TIME" Version="1.0" Remanence="NonRetain" Accessibility="Public"><AttributeList><BooleanAttribute Name="ExternalAccessible" SystemDefined="true">true</BooleanAttribute><BooleanAttribute Name="ExternalVisible" SystemDefined="true">true</BooleanAttribute><BooleanAttribute Name="ExternalWritable" SystemDefined="true">true</BooleanAttribute><BooleanAttribute Name="SetPoint" SystemDefined="true">true</BooleanAttribute></AttributeList><Sections><Section Name="None"><Member Name="PT" Datatype="Time" /><Member Name="ET" Datatype="Time" /><Member Name="IN" Datatype="Bool" /><Member Name="Q" Datatype="Bool" /></Section></Sections></Member>
    <Member Name="S1" Datatype="Bool" Remanence="NonRetain" Accessibility="Public"><AttributeList><BooleanAttribute Name="ExternalAccessible" SystemDefined="true">false</BooleanAttribute><BooleanAttribute Name="ExternalVisible" SystemDefined="true">false</BooleanAttribute><BooleanAttribute Name="ExternalWritable" SystemDefined="true">false</BooleanAttribute><BooleanAttribute Name="SetPoint" SystemDefined="true">false</BooleanAttribute></AttributeList></Member>
    <Member Name="S2" Datatype="Bool" Remanence="NonRetain" Accessibility="Public"><AttributeList><BooleanAttribute Name="ExternalAccessible" SystemDefined="true">false</BooleanAttribute><BooleanAttribute Name="ExternalVisible" SystemDefined="true">false</BooleanAttribute><BooleanAttribute Name="ExternalWritable" SystemDefined="true">false</BooleanAttribute><BooleanAttribute Name="SetPoint" SystemDefined="true">false</BooleanAttribute></AttributeList></Member>
  </Section>
  <Section Name="Temp" />
  <Section Name="Constant" />
</Sections></Interface>
      <IsIECCheckEnabled>false</IsIECCheckEnabled>
      <IsRetainMemResEnabled>false</IsRetainMemResEnabled>
      <MemoryLayout>Optimized</MemoryLayout>
      <MemoryReserve>100</MemoryReserve>
      <Name>PLC_PRG</Name>
      <Number>3</Number>
      <ProgrammingLanguage>LAD</ProgrammingLanguage>
      <SetENOAutomatically>false</SetENOAutomatically>
      <UDABlockProperties />
      <UDAEnableTagReadback>false</UDAEnableTagReadback>
    </AttributeList>
    <ObjectList>
      <MultilingualText ID="1" CompositionName="Comment">
        <ObjectList>
          <MultilingualTextItem ID="2" CompositionName="Items">
            <AttributeList>
              <Culture>en-US</Culture>
              <Text />
            </AttributeList>
          </MultilingualTextItem>
        </ObjectList>
      </MultilingualText>
      <SW.Blocks.CompileUnit ID="3" CompositionName="CompileUnits">
        <AttributeList>
          <NetworkSource><FlgNet xmlns="http://www.siemens.com/automation/Openness/SW/NetworkSource/FlgNet/v4">
  <Parts>
    <Access Scope="LocalVariable" UId="21">
      <Symbol>
        <Component Name="S1" />
      </Symbol>
    </Access>
    <Access Scope="TypedConstant" UId="22">
      <Constant>
        <ConstantValue>T#1s</ConstantValue>
      </Constant>
    </Access>
    <Access Scope="LocalVariable" UId="23">
      <Symbol>
        <Component Name="S2" />
      </Symbol>
    </Access>
    <Access Scope="LocalVariable" UId="24">
      <Symbol>
        <Component Name="S2" />
      </Symbol>
    </Access>
    <Part Name="Contact" UId="25" />
    <Part Name="TON" Version="1.0" UId="26">
      <Instance Scope="LocalVariable" UId="27">
        <Component Name="S1TON" />
      </Instance>
      <TemplateValue Name="time_type" Type="Type">Time</TemplateValue>
    </Part>
    <Part Name="Contact" UId="28" />
    <Part Name="O" UId="29">
      <TemplateValue Name="Card" Type="Cardinality">2</TemplateValue>
    </Part>
    <Part Name="Coil" UId="30" />
  </Parts>
  <Wires>
    <Wire UId="32">
      <Powerrail />
      <NameCon UId="25" Name="in" />
      <NameCon UId="28" Name="in" />
    </Wire>
    <Wire UId="33">
      <IdentCon UId="21" />
      <NameCon UId="25" Name="operand" />
    </Wire>
    <Wire UId="34">
      <NameCon UId="25" Name="out" />
      <NameCon UId="26" Name="IN" />
    </Wire>
    <Wire UId="35">
      <IdentCon UId="22" />
      <NameCon UId="26" Name="PT" />
    </Wire>
    <Wire UId="36">
      <NameCon UId="26" Name="Q" />
      <NameCon UId="29" Name="in1" />
    </Wire>
    <Wire UId="37">
      <NameCon UId="26" Name="ET" />
      <OpenCon UId="31" />
    </Wire>
    <Wire UId="38">
      <IdentCon UId="23" />
      <NameCon UId="28" Name="operand" />
    </Wire>
    <Wire UId="39">
      <NameCon UId="28" Name="out" />
      <NameCon UId="29" Name="in2" />
    </Wire>
    <Wire UId="40">
      <NameCon UId="29" Name="out" />
      <NameCon UId="30" Name="in" />
    </Wire>
    <Wire UId="41">
      <IdentCon UId="24" />
      <NameCon UId="30" Name="operand" />
    </Wire>
  </Wires>
</FlgNet></NetworkSource>
          <ProgrammingLanguage>LAD</ProgrammingLanguage>
        </AttributeList>
        <ObjectList>
          <MultilingualText ID="4" CompositionName="Comment">
            <ObjectList>
              <MultilingualTextItem ID="5" CompositionName="Items">
                <AttributeList>
                  <Culture>en-US</Culture>
                  <Text />
                </AttributeList>
              </MultilingualTextItem>
            </ObjectList>
          </MultilingualText>
          <MultilingualText ID="6" CompositionName="Title">
            <ObjectList>
              <MultilingualTextItem ID="7" CompositionName="Items">
                <AttributeList>
                  <Culture>en-US</Culture>
                  <Text />
                </AttributeList>
              </MultilingualTextItem>
            </ObjectList>
          </MultilingualText>
        </ObjectList>
      </SW.Blocks.CompileUnit>
      <SW.Blocks.CompileUnit ID="8" CompositionName="CompileUnits">
        <AttributeList>
          <NetworkSource><FlgNet xmlns="http://www.siemens.com/automation/Openness/SW/NetworkSource/FlgNet/v4">
  <Parts>
    <Access Scope="LocalVariable" UId="21">
      <Symbol>
        <Component Name="S1TON" />
        <Component Name="Q" />
      </Symbol>
    </Access>
    <Access Scope="LocalVariable" UId="22">
      <Symbol>
        <Component Name="S1" />
      </Symbol>
    </Access>
    <Access Scope="LocalVariable" UId="23">
      <Symbol>
        <Component Name="S1" />
      </Symbol>
    </Access>
    <Part Name="Contact" UId="24">
      <Negated Name="operand" />
    </Part>
    <Part Name="Contact" UId="25" />
    <Part Name="Coil" UId="26" />
  </Parts>
  <Wires>
    <Wire UId="27">
      <Powerrail />
      <NameCon UId="24" Name="in" />
    </Wire>
    <Wire UId="28">
      <IdentCon UId="21" />
      <NameCon UId="24" Name="operand" />
    </Wire>
    <Wire UId="29">
      <NameCon UId="24" Name="out" />
      <NameCon UId="25" Name="in" />
    </Wire>
    <Wire UId="30">
      <IdentCon UId="22" />
      <NameCon UId="25" Name="operand" />
    </Wire>
    <Wire UId="31">
      <NameCon UId="25" Name="out" />
      <NameCon UId="26" Name="in" />
    </Wire>
    <Wire UId="32">
      <IdentCon UId="23" />
      <NameCon UId="26" Name="operand" />
    </Wire>
  </Wires>
</FlgNet></NetworkSource>
          <ProgrammingLanguage>LAD</ProgrammingLanguage>
        </AttributeList>
        <ObjectList>
          <MultilingualText ID="9" CompositionName="Comment">
            <ObjectList>
              <MultilingualTextItem ID="A" CompositionName="Items">
                <AttributeList>
                  <Culture>en-US</Culture>
                  <Text />
                </AttributeList>
              </MultilingualTextItem>
            </ObjectList>
          </MultilingualText>
          <MultilingualText ID="B" CompositionName="Title">
            <ObjectList>
              <MultilingualTextItem ID="C" CompositionName="Items">
                <AttributeList>
                  <Culture>en-US</Culture>
                  <Text />
                </AttributeList>
              </MultilingualTextItem>
            </ObjectList>
          </MultilingualText>
        </ObjectList>
      </SW.Blocks.CompileUnit>
      <SW.Blocks.CompileUnit ID="D" CompositionName="CompileUnits">
        <AttributeList>
          <NetworkSource><FlgNet xmlns="http://www.siemens.com/automation/Openness/SW/NetworkSource/FlgNet/v4">
  <Parts>
    <Access Scope="LocalVariable" UId="21">
      <Symbol>
        <Component Name="S2" />
      </Symbol>
    </Access>
    <Access Scope="TypedConstant" UId="22">
      <Constant>
        <ConstantValue>T#1s</ConstantValue>
      </Constant>
    </Access>
    <Access Scope="LocalVariable" UId="23">
      <Symbol>
        <Component Name="S1" />
      </Symbol>
    </Access>
    <Access Scope="LocalVariable" UId="24">
      <Symbol>
        <Component Name="S1" />
      </Symbol>
    </Access>
    <Part Name="Contact" UId="25" />
    <Part Name="TON" Version="1.0" UId="26">
      <Instance Scope="LocalVariable" UId="27">
        <Component Name="S2TON" />
      </Instance>
      <TemplateValue Name="time_type" Type="Type">Time</TemplateValue>
    </Part>
    <Part Name="Contact" UId="28" />
    <Part Name="O" UId="29">
      <TemplateValue Name="Card" Type="Cardinality">2</TemplateValue>
    </Part>
    <Part Name="Coil" UId="30" />
  </Parts>
  <Wires>
    <Wire UId="32">
      <Powerrail />
      <NameCon UId="25" Name="in" />
      <NameCon UId="28" Name="in" />
    </Wire>
    <Wire UId="33">
      <IdentCon UId="21" />
      <NameCon UId="25" Name="operand" />
    </Wire>
    <Wire UId="34">
      <NameCon UId="25" Name="out" />
      <NameCon UId="26" Name="IN" />
    </Wire>
    <Wire UId="35">
      <IdentCon UId="22" />
      <NameCon UId="26" Name="PT" />
    </Wire>
    <Wire UId="36">
      <NameCon UId="26" Name="Q" />
      <NameCon UId="29" Name="in1" />
    </Wire>
    <Wire UId="37">
      <NameCon UId="26" Name="ET" />
      <OpenCon UId="31" />
    </Wire>
    <Wire UId="38">
      <IdentCon UId="23" />
      <NameCon UId="28" Name="operand" />
    </Wire>
    <Wire UId="39">
      <NameCon UId="28" Name="out" />
      <NameCon UId="29" Name="in2" />
    </Wire>
    <Wire UId="40">
      <NameCon UId="29" Name="out" />
      <NameCon UId="30" Name="in" />
    </Wire>
    <Wire UId="41">
      <IdentCon UId="24" />
      <NameCon UId="30" Name="operand" />
    </Wire>
  </Wires>
</FlgNet></NetworkSource>
          <ProgrammingLanguage>LAD</ProgrammingLanguage>
        </AttributeList>
        <ObjectList>
          <MultilingualText ID="E" CompositionName="Comment">
            <ObjectList>
              <MultilingualTextItem ID="F" CompositionName="Items">
                <AttributeList>
                  <Culture>en-US</Culture>
                  <Text />
                </AttributeList>
              </MultilingualTextItem>
            </ObjectList>
          </MultilingualText>
          <MultilingualText ID="10" CompositionName="Title">
            <ObjectList>
              <MultilingualTextItem ID="11" CompositionName="Items">
                <AttributeList>
                  <Culture>en-US</Culture>
                  <Text />
                </AttributeList>
              </MultilingualTextItem>
            </ObjectList>
          </MultilingualText>
        </ObjectList>
      </SW.Blocks.CompileUnit>
      <SW.Blocks.CompileUnit ID="12" CompositionName="CompileUnits">
        <AttributeList>
          <NetworkSource><FlgNet xmlns="http://www.siemens.com/automation/Openness/SW/NetworkSource/FlgNet/v4">
  <Parts>
    <Access Scope="LocalVariable" UId="21">
      <Symbol>
        <Component Name="S2TON" />
        <Component Name="Q" />
      </Symbol>
    </Access>
    <Access Scope="LocalVariable" UId="22">
      <Symbol>
        <Component Name="S2" />
      </Symbol>
    </Access>
    <Access Scope="LocalVariable" UId="23">
      <Symbol>
        <Component Name="S2" />
      </Symbol>
    </Access>
    <Part Name="Contact" UId="24">
      <Negated Name="operand" />
    </Part>
    <Part Name="Contact" UId="25" />
    <Part Name="Coil" UId="26" />
  </Parts>
  <Wires>
    <Wire UId="27">
      <Powerrail />
      <NameCon UId="24" Name="in" />
    </Wire>
    <Wire UId="28">
      <IdentCon UId="21" />
      <NameCon UId="24" Name="operand" />
    </Wire>
    <Wire UId="29">
      <NameCon UId="24" Name="out" />
      <NameCon UId="25" Name="in" />
    </Wire>
    <Wire UId="30">
      <IdentCon UId="22" />
      <NameCon UId="25" Name="operand" />
    </Wire>
    <Wire UId="31">
      <NameCon UId="25" Name="out" />
      <NameCon UId="26" Name="in" />
    </Wire>
    <Wire UId="32">
      <IdentCon UId="23" />
      <NameCon UId="26" Name="operand" />
    </Wire>
  </Wires>
</FlgNet></NetworkSource>
          <ProgrammingLanguage>LAD</ProgrammingLanguage>
        </AttributeList>
        <ObjectList>
          <MultilingualText ID="13" CompositionName="Comment">
            <ObjectList>
              <MultilingualTextItem ID="14" CompositionName="Items">
                <AttributeList>
                  <Culture>en-US</Culture>
                  <Text />
                </AttributeList>
              </MultilingualTextItem>
            </ObjectList>
          </MultilingualText>
          <MultilingualText ID="15" CompositionName="Title">
            <ObjectList>
              <MultilingualTextItem ID="16" CompositionName="Items">
                <AttributeList>
                  <Culture>en-US</Culture>
                  <Text />
                </AttributeList>
              </MultilingualTextItem>
            </ObjectList>
          </MultilingualText>
        </ObjectList>
      </SW.Blocks.CompileUnit>
      <SW.Blocks.CompileUnit ID="17" CompositionName="CompileUnits">
        <AttributeList>
          <NetworkSource><FlgNet xmlns="http://www.siemens.com/automation/Openness/SW/NetworkSource/FlgNet/v4">
  <Parts>
    <Access Scope="LocalVariable" UId="21">
      <Symbol>
        <Component Name="S1" />
      </Symbol>
    </Access>
    <Access Scope="LocalVariable" UId="22">
      <Symbol>
        <Component Name="Output" />
      </Symbol>
    </Access>
    <Part Name="Contact" UId="23" />
    <Part Name="Coil" UId="24" />
  </Parts>
  <Wires>
    <Wire UId="25">
      <Powerrail />
      <NameCon UId="23" Name="in" />
    </Wire>
    <Wire UId="26">
      <IdentCon UId="21" />
      <NameCon UId="23" Name="operand" />
    </Wire>
    <Wire UId="27">
      <NameCon UId="23" Name="out" />
      <NameCon UId="24" Name="in" />
    </Wire>
    <Wire UId="28">
      <IdentCon UId="22" />
      <NameCon UId="24" Name="operand" />
    </Wire>
  </Wires>
</FlgNet></NetworkSource>
          <ProgrammingLanguage>LAD</ProgrammingLanguage>
        </AttributeList>
        <ObjectList>
          <MultilingualText ID="18" CompositionName="Comment">
            <ObjectList>
              <MultilingualTextItem ID="19" CompositionName="Items">
                <AttributeList>
                  <Culture>en-US</Culture>
                  <Text />
                </AttributeList>
              </MultilingualTextItem>
            </ObjectList>
          </MultilingualText>
          <MultilingualText ID="1A" CompositionName="Title">
            <ObjectList>
              <MultilingualTextItem ID="1B" CompositionName="Items">
                <AttributeList>
                  <Culture>en-US</Culture>
                  <Text />
                </AttributeList>
              </MultilingualTextItem>
            </ObjectList>
          </MultilingualText>
        </ObjectList>
      </SW.Blocks.CompileUnit>
      <SW.Blocks.CompileUnit ID="1C" CompositionName="CompileUnits">
        <AttributeList>
          <NetworkSource />
          <ProgrammingLanguage>LAD</ProgrammingLanguage>
        </AttributeList>
        <ObjectList>
          <MultilingualText ID="1D" CompositionName="Comment">
            <ObjectList>
              <MultilingualTextItem ID="1E" CompositionName="Items">
                <AttributeList>
                  <Culture>en-US</Culture>
                  <Text />
                </AttributeList>
              </MultilingualTextItem>
            </ObjectList>
          </MultilingualText>
          <MultilingualText ID="1F" CompositionName="Title">
            <ObjectList>
              <MultilingualTextItem ID="20" CompositionName="Items">
                <AttributeList>
                  <Culture>en-US</Culture>
                  <Text />
                </AttributeList>
              </MultilingualTextItem>
            </ObjectList>
          </MultilingualText>
        </ObjectList>
      </SW.Blocks.CompileUnit>
      <MultilingualText ID="21" CompositionName="Title">
        <ObjectList>
          <MultilingualTextItem ID="22" CompositionName="Items">
            <AttributeList>
              <Culture>en-US</Culture>
              <Text />
            </AttributeList>
          </MultilingualTextItem>
        </ObjectList>
      </MultilingualText>
    </ObjectList>
  </SW.Blocks.FB>
</Document>

Rockwell Automation Studio 5000

Rockwell Automation Studio 5000 provides the smallest XML file export.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<RSLogix5000Content SchemaRevision="1.0" SoftwareRevision="33.02" TargetName="PLC_PRG" TargetType="Program" ContainsContext="true" Owner="szymon.palczynski@gmail.com" ExportDate="Mon Jun 24 20:50:17 2024" ExportOptions="References NoRawData L5KData DecoratedData Context Dependencies ForceProtectedEncoding AllProjDocTrans">
<Controller Use="Context" Name="emulate">
<DataTypes Use="Context">
</DataTypes>
<Programs Use="Context">
<Program Use="Target" Name="PLC_PRG" TestEdits="false" MainRoutineName="Main" Disabled="false" UseAsFolder="false">
<Tags>
<Tag Name="Output" TagType="Base" DataType="BOOL" Radix="Decimal" Usage="Output" Constant="false" ExternalAccess="Read Only">
<Data Format="L5K">
<![CDATA[0]]>
</Data>
<Data Format="Decorated">
<DataValue DataType="BOOL" Radix="Decimal" Value="0"/>
</Data>
</Tag>
<Tag Name="S1" TagType="Base" DataType="BOOL" Radix="Decimal" Constant="false" ExternalAccess="Read/Write">
<Data Format="L5K">
<![CDATA[0]]>
</Data>
<Data Format="Decorated">
<DataValue DataType="BOOL" Radix="Decimal" Value="0"/>
</Data>
</Tag>
<Tag Name="S1TON" TagType="Base" DataType="TIMER" Constant="false" ExternalAccess="Read/Write">
<Data Format="L5K">
<![CDATA[[0,1000,0]]]>
</Data>
<Data Format="Decorated">
<Structure DataType="TIMER">
<DataValueMember Name="PRE" DataType="DINT" Radix="Decimal" Value="1000"/>
<DataValueMember Name="ACC" DataType="DINT" Radix="Decimal" Value="0"/>
<DataValueMember Name="EN" DataType="BOOL" Value="0"/>
<DataValueMember Name="TT" DataType="BOOL" Value="0"/>
<DataValueMember Name="DN" DataType="BOOL" Value="0"/>
</Structure>
</Data>
</Tag>
<Tag Name="S2" TagType="Base" DataType="BOOL" Radix="Decimal" Constant="false" ExternalAccess="Read/Write">
<Data Format="L5K">
<![CDATA[0]]>
</Data>
<Data Format="Decorated">
<DataValue DataType="BOOL" Radix="Decimal" Value="0"/>
</Data>
</Tag>
<Tag Name="S2TON" TagType="Base" DataType="TIMER" Constant="false" ExternalAccess="Read/Write">
<Data Format="L5K">
<![CDATA[[0,1000,0]]]>
</Data>
<Data Format="Decorated">
<Structure DataType="TIMER">
<DataValueMember Name="PRE" DataType="DINT" Radix="Decimal" Value="1000"/>
<DataValueMember Name="ACC" DataType="DINT" Radix="Decimal" Value="0"/>
<DataValueMember Name="EN" DataType="BOOL" Value="0"/>
<DataValueMember Name="TT" DataType="BOOL" Value="0"/>
<DataValueMember Name="DN" DataType="BOOL" Value="0"/>
</Structure>
</Data>
</Tag>
</Tags>
<Routines>
<Routine Name="Main" Type="RLL">
<RLLContent>
<Rung Number="0" Type="N">
<Text>
<![CDATA[[XIC(S1) TON(S1TON,?,?) XIC(S1TON.DN) ,XIC(S2) ]OTE(S2);]]>
</Text>
</Rung>
<Rung Number="1" Type="N">
<Text>
<![CDATA[XIO(S1TON.DN)XIC(S1)OTE(S1);]]>
</Text>
</Rung>
<Rung Number="2" Type="N">
<Text>
<![CDATA[[XIC(S2) TON(S2TON,?,?) XIC(S2TON.DN) ,XIC(S1) ]OTE(S1);]]>
</Text>
</Rung>
<Rung Number="3" Type="N">
<Text>
<![CDATA[XIO(S2TON.DN)XIC(S2)OTE(S2);]]>
</Text>
</Rung>
<Rung Number="4" Type="N">
<Text>
<![CDATA[XIC(S1)OTE(Output);]]>
</Text>
</Rung>
</RLLContent>
</Routine>
</Routines>
</Program>
</Programs>
</Controller>
</RSLogix5000Content>

What's most important it saves rung's code as plain text which is fairly easy to read and compare

[XIC(S1)TON(S1TON,?,?)XIC(S1TON.DN),XIC(S2)]OTE(S2);
XIO(S1TON.DN)XIC(S1)OTE(S1);
[XIC(S2)TON(S2TON,?,?)XIC(S2TON.DN),XIC(S1)]OTE(S1);
XIO(S2TON.DN)XIC(S2)OTE(S2);
XIC(S1)OTE(Output);

FactoryTalk Design Studio

What's interesting is that the latest Rockwell product, FactoryTalk Design Studio, allows editing ladder logic in plain text format. This represents a significant step forward in the PLC programming world. However, the web-based IDE implementation suffers from lag, which can impede productivity.

routine ld Area.smart_object.program1.main(
    output BOOL ^Output
) {

    [XIC(S1)TON(S1TON)XIC(s1ton.dn),XIC(S2)]OTE(s2);
    XIC(s1ton.dn)XIC(s1)OTE(s1);
    [XIC(S2)TON(S2TON)XIC(S2TON.DN),XIC(s1)]OTE(S1);
    XIC(S2TON.DN)XIC(S2)OTE(S2);
    XIC(s1)OTU(^output);

    tag BOOL S1;
    tag BOOL S2;
    tag TIMER S1TON {
        PRE := 1000;
    };
    tag TIMER S2TON {
        PRE := 1000;
    };
}

Advantages of Text Files

Saving ladder logic as text offers several important advantages. Text files are inherently more readable and editable compared to binary files, allowing programmers to quickly understand and modify the logic. This readability also facilitates the use of version control systems like Git, enabling efficient tracking of changes, collaborative editing, and seamless merging of different code branches. Moreover, text files simplify the debugging process and code reviews, as issues can be more easily identified and resolved. By standardizing ladder logic in a text format, we align PLC programming with best practices in software development, promoting more organized, maintainable, and error-free code.

Conclusion

Each PLC manufacturer has its own way of storing program files, usually in a binary format. While some offer XML exports, these are not standardized and still hard to read. This makes it difficult to use version control systems and slows down collaboration.

LadderScript proposes a single, text-based format for ladder logic that would be easy to read, compare, and use with version control tools like Git. By being open-source, LadderScript can be widely adopted, and tools can be created to convert LadderScript into the XML formats used by different manufacturers. A graphical LadderScript editor could also make it easier to create and manage ladder logic.

If you are interested in contributing to the LadderScript project, please contact me at simon@codingplc.com. Together, we can improve the way we handle ladder logic programming.