Skip to content

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;, not VAR ... 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 STRUCT style without comments.
  • Variable names describe engineering meaning and units.
  • Boolean names read like true/false statements.
  • Larger blocks use numbered REGION sections.
  • Temporary helper names are not leaked into the public interface.