PLCProject XML Schema Reference - Version 3.0¶
Document Version: 1.0 Schema Version: 3.0 Last Updated: 2026-01-25 Status: Active
Overview¶
The PLCProject XML format is the native file format for PiPLC ladder logic projects. Files use the .plcproj extension and contain complete project data including metadata, symbol tables, and ladder logic programs.
Version 3.0 introduces support for parallel branches in ladder logic, enabling OR logic representation directly in the data model.
What's New in 3.0¶
- Branch Element: Represents parallel paths in ladder logic (OR logic)
- Path Element: Represents a single path within a branch (AND logic within path)
- Nested Branches: Full support for arbitrarily nested branch structures
- Backward Compatibility: Loader accepts both v2.0 and v3.0 files
File Format Basics¶
- Encoding: UTF-8 (with XML declaration)
- Extension:
.plcproj - MIME Type:
application/x-plcproject+xml - XML Version: 1.0
Schema Version History¶
| Version | Date | Changes |
|---|---|---|
| 3.2 | 2026-01-29 | Added optional address attribute to Decorator elements for T:/C: memory integration |
| 3.0 | 2026-01-25 | Added Branch and Path elements for parallel logic |
| 2.0 | 2026-01-25 | Initial documented schema with streaming XML support |
| 1.0 | (Legacy) | Reserved for future backwards compatibility |
Root Element¶
<?xml version="1.0" encoding="UTF-8"?>
<PLCProject version="3.0">
<!-- Child elements -->
</PLCProject>
Attributes¶
| Attribute | Type | Required | Description |
|---|---|---|---|
version | string | Yes | Schema version (e.g., "3.0"). Required for compatibility checking. |
Child Elements (in order)¶
Metadata- Project metadata (required)SymbolTable- Variable definitions (required, may be empty)Programs- Ladder logic programs (required)
Metadata Element¶
Contains project identification and descriptive information.
<Metadata>
<Name>Motor Control</Name>
<Description>Optional description of the project</Description>
</Metadata>
Child Elements¶
| Element | Type | Required | Description |
|---|---|---|---|
Name | string | No | Project name. Empty string if not specified. |
Description | string | No | Project description. Omitted if empty. |
Notes¶
- Special XML characters (
<,>,&,",') are automatically escaped - Unicode content is fully supported
SymbolTable Element¶
Contains variable/symbol definitions used in the ladder logic.
<SymbolTable>
<Symbol name="StartButton" type="BOOL" address="I:0/0" description="Main start pushbutton" />
<Symbol name="MotorRunning" type="BOOL" address="O:0/0" />
<Symbol name="CycleCount" type="INT" address="N:10" description="Production counter" />
</SymbolTable>
Symbol Element Attributes¶
| Attribute | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Unique variable name. Must follow naming rules (alphanumeric + underscore, no leading digits). |
address | string | Yes | PLC memory address. See Address Formats below. |
type | string | No | Data type: BOOL, INT, DINT, REAL, TIMER, COUNTER. Defaults to BOOL. |
description | string | No | Human-readable description. Omitted if empty. |
Validation Rules¶
- Variable names must be unique within the symbol table
- Duplicate names will cause a load error
- Address must be valid per the Address Formats specification
Programs Element¶
Contains one or more ladder logic programs.
<Programs>
<Program name="MainProgram" type="Main">
<Rungs>
<!-- Rung elements -->
</Rungs>
</Program>
</Programs>
Program Element Attributes¶
| Attribute | Type | Required | Description |
|---|---|---|---|
name | string | No | Program name (informational, may differ from Metadata name) |
type | string | No | Program type: Main, Subroutine, Interrupt. Default: Main |
Notes¶
- Currently only single-program projects are supported
- The authoritative program name comes from
Metadata/Name, not the Program element'snameattribute
Rungs Element¶
Contains the ladder rungs within a program.
<Rungs>
<Rung id="0" comment="Start/stop circuit with seal-in">
<!-- Instruction and Branch elements -->
</Rung>
<Rung id="1">
<!-- Instruction and Branch elements -->
</Rung>
</Rungs>
Rung Element Attributes¶
| Attribute | Type | Required | Description |
|---|---|---|---|
id | integer | No | Rung identifier (0-based). Used for reference only. |
comment | string | No | Rung comment/description. Omitted if empty. |
Rung Child Elements¶
A rung can contain any combination of: - Instruction - Individual ladder instruction - Branch - Parallel branch structure (NEW in v3.0)
Instruction Element¶
Represents a single ladder logic instruction.
<Instruction type="XIC" address="I:0/0" column="0" />
<Instruction type="OTE" address="O:0/0" column="10" />
Attributes¶
| Attribute | Type | Required | Description |
|---|---|---|---|
type | string | Yes | Instruction type. See Instruction Types below. |
address | string | Yes | Target memory address. See Address Formats below. |
column | integer | No | Visual column position in ladder editor. Default: 0 |
preset | integer | No | Preset value for timers (ms) and counters (count). Used by TON, TOF, RTO, CTU, CTD. |
sourceA | string | No | Source A address. Used by math, compare, and bitwise instructions. |
sourceB | string | No | Source B address. Used by binary math, compare, and bitwise instructions. |
source | string | No | Source address. Used by SCL (scale) instruction. |
dest | string | No | Destination address. Used by math, bitwise, and scale instructions. |
ctrl | string | No | Control address (B:x word). Used by BSL and BSR for IN/OV bits. |
inMin | integer | No | Input range minimum. Used by SCL. |
inMax | integer | No | Input range maximum. Used by SCL. |
outMin | integer | No | Output range minimum. Used by SCL. |
outMax | integer | No | Output range maximum. Used by SCL. |
Instruction Types¶
Contact Instructions (Input)¶
| Type | Name | Description |
|---|---|---|
XIC | Examine If Closed | TRUE when addressed bit is 1 |
XIO | Examine If Open | TRUE when addressed bit is 0 |
Coil Instructions (Output)¶
| Type | Name | Description |
|---|---|---|
OTE | Output Energize | Sets bit to match rung continuity |
OTL | Output Latch | Sets bit TRUE on rung TRUE, retains on FALSE |
OTU | Output Unlatch | Sets bit FALSE on rung TRUE, retains on FALSE |
Additional Instruction Types¶
| Type | Name | Description |
|---|---|---|
TON | Timer On-Delay | Output after input TRUE for preset time |
TOF | Timer Off-Delay | Output remains TRUE after input goes FALSE |
RTO | Retentive Timer | Like TON but retains accumulated time |
CTU | Count Up | Increments on rising edge |
CTD | Count Down | Decrements on rising edge |
RES | Reset | Resets timer/counter at target address |
ADD, SUB, MUL, DIV, MOD, NEG, ABS | Math | Arithmetic operations |
SCL | Scale | Linear scaling |
EQU, NEQ, GRT, GEQ, LES, LEQ | Compare | Comparison operations |
BAND, BOR, BXOR, BNOT | Bitwise | Bitwise logic operations |
N2B | Integer to Bit | Dest = (1 << A) |
BSL | Bit Shift Left | Dest = (A << B) | IN |
BSR | Bit Shift Right | Dest = (A >> B) | (IN << 31) |
Decorator Child Elements¶
Contact instructions (XIC/XIO) may contain a <Decorators> child element with one or more <Decorator> entries:
<Instruction type="XIC" address="B:0/0">
<Decorators>
<Decorator type="TON" preset="2000" address="T:0"/>
<Decorator type="OSR"/>
</Decorators>
</Instruction>
Decorator Attributes¶
| Attribute | Type | Required | Description |
|---|---|---|---|
type | string | Yes | Decorator type: TON, TOF, OSR, OSF, Debounce, Counter |
preset | integer | No | Preset value (ms for timers, count for counters) |
debounceTime | integer | No | Debounce time in ms (Debounce type only) |
address | string | No | Assigned T:/C: memory address (auto-created if absent) |
The address attribute enables timer/counter decorators to sync state with PLC memory, allowing RES instructions to reset decorator state. Addresses are auto-assigned on project load if not present (migration from pre-3.2 projects).
Branch Element (NEW in v3.0)¶
Represents parallel paths in ladder logic. Multiple paths are evaluated with OR logic - if any path has power, the branch has power.
<Branch>
<Path>
<!-- Elements in series (AND logic) -->
<Instruction type="XIC" address="I:0/0" column="1" />
</Path>
<Path>
<!-- Alternative path (OR logic with first path) -->
<Instruction type="XIC" address="I:0/1" column="1" />
</Path>
</Branch>
Child Elements¶
| Element | Required | Description |
|---|---|---|
Path | At least one | A single path within the branch. Multiple paths represent OR logic. |
Execution Semantics¶
- If input power is FALSE, branch outputs FALSE (no paths evaluated)
- If branch is empty (no paths), outputs FALSE
- Each path is evaluated with the same input power
- If ANY path outputs TRUE, branch outputs TRUE (OR logic)
- All paths are evaluated regardless of earlier path results (for output execution)
Visual Representation¶
Serialized as:
<Branch>
<Path>
<Instruction type="XIC" address="I:0/0" column="1" />
</Path>
<Path>
<Instruction type="XIC" address="I:0/1" column="1" />
</Path>
</Branch>
<Instruction type="OTE" address="O:0/0" column="10" />
Path Element (NEW in v3.0)¶
Represents a single path within a branch. Elements within a path are evaluated in series (AND logic).
<Path>
<Instruction type="XIC" address="I:0/0" column="1" />
<Instruction type="XIC" address="I:0/1" column="2" />
<Instruction type="OTE" address="O:0/0" column="10" />
</Path>
Child Elements¶
A path can contain any combination of: - Instruction - Individual ladder instruction - Branch - Nested parallel branch (enables complex logic)
Execution Semantics¶
- If path is empty, passes input power unchanged (acts as wire)
- Elements are evaluated left-to-right in series (AND logic)
- Contact instructions affect power flow
- Output instructions are executed with current power but don't affect power flow
- Nested branches are evaluated recursively
Empty Path Behavior¶
An empty path acts as a direct wire, passing power through unchanged:
<Branch>
<Path /> <!-- Always passes power -->
<Path>
<Instruction type="XIC" address="I:0/0" column="1" />
</Path>
</Branch>
Nested Branches¶
Branches can be nested to arbitrary depth to represent complex logic.
Example: Nested OR within OR¶
Logic: (I:0/0) OR ((I:0/1) OR (I:0/2))
<Branch>
<Path>
<Instruction type="XIC" address="I:0/0" column="1" />
</Path>
<Path>
<Branch>
<Path>
<Instruction type="XIC" address="I:0/1" column="1" />
</Path>
<Path>
<Instruction type="XIC" address="I:0/2" column="1" />
</Path>
</Branch>
</Path>
</Branch>
<Instruction type="OTE" address="O:0/0" column="10" />
Example: Series AND within OR paths¶
Logic: ((I:0/0) AND (I:0/1)) OR (I:0/2)
<Branch>
<Path>
<Instruction type="XIC" address="I:0/0" column="1" />
<Instruction type="XIC" address="I:0/1" column="2" />
</Path>
<Path>
<Instruction type="XIC" address="I:0/2" column="1" />
</Path>
</Branch>
<Instruction type="OTE" address="O:0/0" column="10" />
Address Formats¶
PiPLC uses Allen-Bradley/Rockwell-style PLC addressing.
Bit Addresses¶
Format: R:W/B where: - R = Region prefix - W = Word number (0-based) - B = Bit number (0-15)
| Region | Prefix | Description | Example |
|---|---|---|---|
| Input | I | Digital inputs | I:0/0, I:1/15 |
| Output | O | Digital outputs | O:0/0, O:0/7 |
| Bit | B | Internal relays | B:3/0, B:10/8 |
Word Addresses¶
Format: R:W where: - R = Region prefix - W = Word/element number
| Region | Prefix | Description | Example |
|---|---|---|---|
| Integer | N | 16-bit signed integers | N:0, N:100 |
| Timer | T | Timer structures | T:0, T:10 |
| Counter | C | Counter structures | C:0, C:5 |
Timer/Counter Sub-Elements¶
Format: R:W.S where S is:
| Sub-element | Description | Type |
|---|---|---|
.DN | Done bit | BOOL |
.TT | Timer timing / Counter counting | BOOL |
.EN | Enabled | BOOL |
.ACC | Accumulated value | INT |
.PRE | Preset value | INT |
Examples: T:0.DN, C:5.ACC, T:2.PRE
Complete Example with Branches¶
<?xml version="1.0" encoding="UTF-8"?>
<PLCProject version="3.0">
<Metadata>
<Name>Motor Control with Dual Start</Name>
<Description>Motor start/stop circuit with two start buttons (OR logic)</Description>
</Metadata>
<SymbolTable>
<Symbol name="StartPB1" type="BOOL" address="I:0/0" description="Start pushbutton 1" />
<Symbol name="StartPB2" type="BOOL" address="I:0/1" description="Start pushbutton 2" />
<Symbol name="StopPB" type="BOOL" address="I:0/2" description="Stop pushbutton (NC)" />
<Symbol name="MotorOut" type="BOOL" address="O:0/0" description="Motor contactor output" />
<Symbol name="SealIn" type="BOOL" address="B:0/0" description="Motor seal-in relay" />
</SymbolTable>
<Programs>
<Program name="Motor Control with Dual Start" type="Main">
<Rungs>
<Rung id="0" comment="Motor start circuit - (Start1 OR Start2 OR Seal-in) AND NOT Stop">
<Branch>
<Path>
<Instruction type="XIC" address="I:0/0" column="0" />
</Path>
<Path>
<Instruction type="XIC" address="I:0/1" column="0" />
</Path>
<Path>
<Instruction type="XIC" address="B:0/0" column="0" />
</Path>
</Branch>
<Instruction type="XIO" address="I:0/2" column="5" />
<Instruction type="OTE" address="B:0/0" column="10" />
</Rung>
<Rung id="1" comment="Motor output from seal-in">
<Instruction type="XIC" address="B:0/0" column="0" />
<Instruction type="OTE" address="O:0/0" column="10" />
</Rung>
</Rungs>
</Program>
</Programs>
</PLCProject>
Backward Compatibility¶
Reading v2.0 Files¶
The v3.0 loader fully supports v2.0 files: - v2.0 files are loaded without modification - All v2.0 elements are interpreted identically - v2.0 files without branches work exactly as before
Version Detection¶
Writing v3.0 Files¶
- All new projects are saved as v3.0
- Rungs without branches produce identical XML to v2.0 (just different version number)
- Branch elements only appear when parallel logic exists
Error Handling¶
Load Errors¶
The loader reports errors with line and column numbers when possible:
| Error | Description |
|---|---|
No PLCProject element found | Root element missing or malformed XML |
Missing version attribute | Required version attribute not present |
Symbol missing name attribute | Symbol element lacks required name |
Symbol missing address attribute | Symbol element lacks required address |
Invalid address: X:Y/Z | Address format not recognized |
Duplicate variable name: Name | Symbol table contains duplicate names |
Unknown instruction type: TYPE | Instruction type not recognized |
Instruction missing type attribute | Instruction element lacks required type |
Forward Compatibility¶
- Unknown elements are silently skipped
- Unknown attributes are ignored
- This allows newer schema versions to be partially read by older software
Implementation Notes¶
Writing Projects¶
Use QXmlStreamWriter for generating XML: - Auto-formatting enabled with 2-space indentation - UTF-8 encoding with XML declaration - Empty elements written as <Element /> (self-closing)
Reading Projects¶
Use QXmlStreamReader for parsing: - Streaming parser for memory efficiency - Element-by-element processing - Error recovery via skipCurrentElement()
API Reference¶
// Save to file
bool ProjectSerializer::save(const Program *program, const QString &filePath, QString *error);
// Save to device (for testing)
bool ProjectSerializer::save(const Program *program, QIODevice *device, QString *error);
// Load from file
Program* ProjectSerializer::load(const QString &filePath, QString *error);
// Load from device (for testing)
Program* ProjectSerializer::load(QIODevice *device, QString *error);
Data Model Classes¶
// Abstract base for rung elements
class RungElement : public QObject {
enum class ElementType { Instruction, Branch };
virtual ElementType elementType() const = 0;
virtual RungElement* clone(QObject *parent = nullptr) const = 0;
};
// Parallel paths container (OR logic)
class Branch : public RungElement {
int pathCount() const;
RungPath* path(int index) const;
RungPath* addPath();
void addPath(RungPath *path);
};
// Series element container (AND logic)
class RungPath : public QObject {
int elementCount() const;
RungElement* element(int index) const;
void addElement(RungElement *element);
};
// Individual instruction (inherits from RungElement)
class Instruction : public RungElement {
InstructionType type() const;
Address address() const;
};
See Also¶
- PLCProject-v2.0.md - Previous schema version
- VERSIONING.md - Version compatibility guidelines
- SPECIFICATION.md Section 3 - File format requirements
- ProjectSerializer.h - Implementation header
- Branch.h - Branch class reference
- RungPath.h - RungPath class reference
- examples/ - Example project files