Coding Style¶
This page defines the baseline style for PCS PLC source files. The goal is simple: every block should be easy to find, easy to scan, and hard to misuse.
Golden rule
Names should explain the engineering intent. A reader should understand what the signal means without searching through the implementation.
Quick Rules¶
| Area | Rule |
|---|---|
| Blocks | Use FB_, FC_, OB_, DB_, or UDT_ prefixes. |
| Location | Put sources below tia/exports in the responsible subsystem folder. |
| Header | FB, FC, and OB sources contain the standard description header. |
| Variables | Use type prefixes plus meaningful process names. |
| Booleans | Boolean names must read like true/false statements. |
| Units | Add engineering units to names where units matter. |
| Large files | Use numbered REGION sections. |
Do not bypass the scaffold command
Prefer pcs new block ... for new sources. It creates the correct file extension, naming pattern, and header. Manual files tend to drift.
Block Names¶
Block names must start with one of the approved prefixes:
| Prefix | Object type | File extension | Example |
|---|---|---|---|
FB_ |
Function block | .scl |
FB_AlarmRouting |
FC_ |
Function | .scl |
FC_ClampReal |
OB_ |
Organization block | .scl |
OB1_MAIN_CYCLE |
DB_ |
Data block | .db |
DB_AlarmConfig |
UDT_ |
User data type | .udt |
UDT_AlarmEntry |
Create new blocks with:
pcs new block 06_ALARMS/FB_AlarmRouting
pcs new block 06_ALARMS/UDT_AlarmEntry
pcs new block 00_SYSTEM/DB_SystemConfig
FB_PowerLimiter
FB_CommandArbitration
DB_PowerManagementState
UDT_PropulsionCommand
FB_Logic
FB_NewBlock
DB_Data
UDT_Struct1
Why strict block prefixes matter
The prefix tells every engineer and every tool what kind of TIA object is expected. It also lets pcs new block ... decide whether to create .scl, .db, or .udt.
Source Location¶
Sources live below tia/exports and are grouped by subsystem or responsibility:
tia/exports/
00_SYSTEM/
01_PLATFORM/
02_INTERFACES/
06_ALARMS/
99_LEGACY/
Responsibility beats file type
Keep related FBs, FCs, DBs, and UDTs together. Alarm logic belongs in 06_ALARMS, not split into separate technical folders for blocks and data types.
Description Header¶
FB, FC, and OB sources contain a consistent description header. The header lives inside BEGIN so it is visible in TIA Portal:
FUNCTION_BLOCK "FB_AlarmRouting"
{ S7_Optimized_Access := 'FALSE' }
VERSION : 0.1
BEGIN
REGION S000 - Description
(**************************************************************************************************
Function block: FB_AlarmRouting
---------------------------------------------------------------------------------------------------
Version | Date | Author | Comment
---------------------------------------------------------------------------------------------------
v0.1.0 | 2026-05-09 | Tom Westerling | Initial scaffold
---------------------------------------------------------------------------------------------------
Description:
Routes active alarms to the configured HMI and horn outputs.
**************************************************************************************************)
END_REGION
// Keep the logic boring. Keep the vessel safe.
END_FUNCTION_BLOCK
DB and UDT sources intentionally do not contain description headers or inline comments. TIA source generation does not round-trip these comments reliably, so these files follow TIA's generated source style to avoid false sync differences.
Use the correct object label:
| Object | Header label |
|---|---|
FB_ |
Function block: |
FC_ |
Function: |
OB_ |
Organization block: |
Tip
The pcs new block ... command creates the header automatically for SCL blocks, including date, author, REGION S000 - Description, and a small scaffold comment.
DB And UDT Sources¶
DB and UDT files should be kept close to the source generated by TIA Portal:
DATA_BLOCK "DB_SystemConfig"
{ S7_Optimized_Access := 'FALSE' }
VERSION : 0.1
STRUCT
xboPlaceholder : Bool;
END_STRUCT;
BEGIN
END_DATA_BLOCK
TYPE "UDT_LimitConfig"
VERSION : 0.1
STRUCT
xboPlaceholder : Bool;
END_STRUCT;
END_TYPE
Rules for DB and UDT files:
- Use
STRUCT ... END_STRUCT;, notVAR ... END_VAR. - Do not add description headers, regions, block comments, or inline comments.
- Keep engineering explanations in documentation or in the SCL blocks that use the data.
- After importing to TIA and exporting a snapshot, DB/UDT files should not create comment-only or formatting-only sync differences.
Regions¶
Use REGION ... END_REGION to separate logical sections in larger files. S000 - Description is reserved for the generated header. Start implementation regions at S001.
REGION S001 - Input parameter validation
// Validate configured limits and command source.
END_REGION
REGION S002 - Diagnostics
// Evaluate error states and status flags.
END_REGION
REGION S003 - Output assignment
// Assign final output values.
END_REGION
Keep regions useful
Prefer a few meaningful regions over many tiny ones. A small scaffold block does not need regions until the logic grows.
Variable Names¶
Variable names should explain the role of the value in the process. The type prefix is only a quick hint; the rest of the name carries the meaning.
xboStationCommandActive : Bool;
xboDriveFeedbackHealthy : Bool;
reRequestedShaftSpeedRpm : Real;
reAvailablePowerKw : Real;
timAlarmDelay : Time;
stPropulsionCommand : "UDT_PropulsionCommand";
x1 : Bool;
flag : Bool;
temp : Real;
value1 : Real;
data : "UDT_PropulsionCommand";
What self-explaining means
A good variable name says what the value means in the process: request, feedback, command, state, limit, permission, fault, or configuration. It should not only say that a value exists.
Contextful analog scaling names
VAR_INPUT
inRawAnalogValue : Int;
rePhysicalMinimum : Real;
rePhysicalMaximum : Real;
END_VAR
VAR_OUTPUT
reScaledPhysicalValue : Real;
xboSignalFaultActive : Bool;
END_VAR
VAR_TEMP
_reNormalizedInput : Real;
END_VAR
These names make the scaling intent clear: raw sensor value in, physical engineering value out, fault flag as status.
Prefixes For Variables¶
Use short type prefixes consistently.
| Prefix | Type / purpose | Example |
|---|---|---|
xbo |
Boolean | xboWireBreakDetected |
in |
Int |
inRawAnalogValue |
re |
Real |
reScaledTemperatureDegC |
di |
DInt |
diEncoderCount |
by |
Byte |
byAlarmPriority |
wo |
Word |
woTelegramStatus |
dw |
DWord |
dwDiagnosticMask |
tim |
Time |
timAlarmDelay |
dtl |
DTL |
dtlEventTimestamp |
st |
Struct or UDT instance | stDriveStatus |
arr |
Array | arrGeneratorStatus |
e |
Enumeration-like value | eSystemMode |
_ |
Internal static/temp helper | _reFilteredValue |
Internal helper names
Prefix internal static or temporary helper variables with _ when they should not be confused with the public interface. Example: _reNormalizedInput.
Boolean Names¶
Boolean names should read like true/false statements.
xboPowerLimitActive
xboWireBreakDetected
xboStationHasControl
xboDriveReadyForCommand
xboPowerLimit
xboWire
xboStation
xboReady
Ambiguous booleans create bugs
Weak names force the reader to ask whether the value is a request, a state, a permission, a fault, or a configuration.
Units¶
Put the engineering unit in the variable name when the unit matters.
reRequestedSpeedRpm
reAvailablePowerKw
reBusVoltageV
reTemperatureDegC
timStartDelay
reRequestedSpeed
reAvailablePower
reVoltage
reTemperature
Info
Unit suffixes prevent mistakes when values move between HMI, PLC logic, drive telegrams, and simulation.
Interface Clarity¶
Use clear interface sections and keep inputs, outputs, and in/out variables focused.
VAR_INPUT
xboEnable : Bool;
reRequestedPowerKw : Real;
reAvailablePowerKw : Real;
END_VAR
VAR_OUTPUT
reLimitedPowerCommandKw : Real;
xboPowerLimitActive : Bool;
END_VAR
VAR_INPUT
enable : Bool;
in1 : Real;
in2 : Real;
END_VAR
Comments¶
Comments should explain why the code exists, not repeat what the code already says.
// Keep the previous valid value during wire break to avoid a step change at the drive command.
reScaledPhysicalValue := _reLastValidValue;
// Assign value.
reScaledPhysicalValue := _reLastValidValue;
Use comments for assumptions, limits, diagnostics, and non-obvious decisions.
Practical Checklist¶
Before adding or deploying a block
- The block prefix matches the object type.
- The file is in the correct subsystem folder.
- FB, FC, and OB headers are present and up to date.
- DB and UDT sources follow the generated TIA
STRUCTstyle without comments. - Variable names describe engineering meaning and units.
- Boolean names read like true/false statements.
- Larger blocks use numbered
REGIONsections. - Temporary helper names are not leaked into the public interface.