Features   Offline Analysis → ReviewsShipping


Rewrite ST

 

Optimize the program body that preserves intent while cutting dead code and improving loops.

LD-ST Converter

 

Turn ladder .export files networks into clear ST, even adding edge memory vars when needed, then merges/tidies your declarations. Drag and drop ready.

Anti-patterns

 

Busy waits, deep IF statement nesting, magic numbers, unsafe casts, the assistant flags them and tells you the one-line fix.

Safety & Determinism Checks

Surface the race conditions and non-determinism constructs before they hit the field, devlivered as concise, actionable bullets your team can fix fast.


Example

Original Vars

FUNCTION_BLOCK FB_Motor_FC_01
(*
2018-04-16 BH Error messages changed to "True=Error"!
2019-06-26 BH Created from FB_Motor_FC_01
2019-08-21 BH Bug fix
2019-12-04 BH BMS off/on with overrun changed (version FRA3-F)
2020-09-08 BH PBS only in automatic mode
2020-09-15 BH Actuating signal remains with manual off (version MUC-B)
2021-11-15 BH Manual off is not functional! Enable is removed via the priority function block (version ZRH-B)
2024-05-14 NiFr Recreated in CoDeSys V3
*)
(*
Block for Control of the refrigeration system pumps.
Caution: A fault does not cause a shutdown!
*)
VAR_INPUT
xActive :BOOL; (* Activates the function block *)
xEnable :BOOL; (* Motor is requested *)
rSpeed_SW :REAL; (* Control signal, 0-100% *)
iFrg_GLT_019 :INT :=9; (* Enables the BMS, 0-Off, 1-On, 9-Auto *)
rManual_SW :REAL; (* Setpoint for manual on *)
rManual_SW_Factor :REAL :=1; (* Factor for converting Hertz to %, e.g., 50Hz -> 2; 60Hz -> 1.666; to % -> 1 *)
rOverrun Time :REAL :=0; (* Run-on time in automatic mode, in seconds *)
xRep_Switch :BOOL := TRUE; (* Repair switch, True=ON *)
xMotorProtect :BOOL := TRUE; (* Motor protection contact, True=Error *)
xPTC Thermistor :BOOL := TRUE; (* PTC thermistor contact, True=Error *)
xRunMonitor :BOOL := TRUE; (* Contact for run monitoring, True=Motor running *)
rRunMonitor_Time :REAL :=10; (* Run monitoring switch-on delay, time in seconds *)
rSpeed_RM :REAL :=999; (* Motor speed feedback, 0-100%, 999 = monitoring deactivated *)
xPBS_Enable :BOOL; (* Enables the pump for pump blocking protection, True=On *)
rPBS_Speed ​​:REAL; (* Speed ​​for pump blocking protection, in % *)
xSSM_Ack :BOOL; (* Acknowledges fault message, True=Ack *)
END_VAR
VAR_OUTPUT
xStufe_1 :BOOL; (* Enables the motor *)
rY_Control_Signal :REAL; (* Control signal in percent or Hz with conversion factor *)
wY_Control_Signal :WORD; (* Control signal as word 0-32767 *)
xRep_Switch_On :BOOL; (* Control switch On *)
xError_Laufuebw :BOOL; (* Fault in run monitoring, True=Error *)
xError_Drehzahluebw :BOOL; (* Fault in speed monitoring, True=Error *)
xError :BOOL; (* Fault, does not require acknowledgment, does not shut down!, True=Error *)
xOperation :BOOL; (* Motor running feedback, via xRunMonitor. True=On *)
xOverrun_active :BOOL; (* Overrun is active, True=Overrun *)
rOverrun_Actual :REAL; (* Elapsed overrun time, in s *)
xRev_02_5 :BOOL; (* Revision 02.5; 2021-11-15 BH Manual Off is not functional! Enable is removed via Prio-FB (ZRH-B version) *)
END_VAR
VAR
TON01 : TON;
TOF01 : TOF;
xManualOn : BOOL;
xAutoOperation : BOOL;
xSW_Manual : BOOL; (* Manual setpoint active *)
rPositioning signal : REAL; (* Internal control signal from 0-100% *)
TON02 : TON;
TP01 : TP;
TP02 : TP;
END_VAR

Original program body

//Automatic On-Off Mode
IF iFrg_GLT_019 = 0 THEN
xHandOn := FALSE;
xAutoOperation := FALSE;
xSW_Man := FALSE;
ELSIF iFrg_GLT_019 = 1 THEN
xHandOn := TRUE;
xAutoOperation := FALSE;
xSW_Man := TRUE;
ELSIF iFrg_GLT_019 = 9 THEN
xHandOn := FALSE;
xAutoOperation := TRUE;
xSW_Man := FALSE;
ELSE
xHandOn := FALSE;
xAutoOperation := FALSE;
xSW_Man := FALSE;
END_IF

//Activation of the enable
TOF01();
TOF01.IN := xRelease OR xManualOn;
TOF01.PT := REAL_TO_TIME(rOverrunTime * 1000);
rOverrunActual := TIME_TO_REAL(TOF01.ET) / 1000;
xLevel_1 := xActive AND (TOF01.Q OR (xAutoOperation AND xPBS_Enable));
xOverrunActive := xLevel_1 AND TOF01.Q AND NOT TOF01.IN;

//Output of the control signal
IF NOT xLevel_1 THEN
rControlSignal := 0;
ELSIF xSW_Manual THEN
rControlSignal := rManual_SW * rManual_SW_Factor;
ELSIF xPBS_Enable AND NOT xEnable THEN
rControlSignal := rPBS_Speed;
ELSE
rControl signal := rSpeed_SW;
END_IF

rControl signal := LIMIT(0, rControl signal, 100);

wY_Control signal := REAL_TO_WORD(rControl signal*327.67);
rY_Control signal := rControl signal * rManual_SW_Factor;

//Error message
TP01();
TP01.PT := T#10S;
TP01.IN := xMotorProtect OR xPTC thermistor;
xError := xMotorProtect OR xPTC thermistor OR TP01.Q;

//Running monitoring
xOperation := xRunningmonitor;
xRep_Switch_On := xRep_Switch;

TON01();
TP02();
TON01.PT := REAL_TO_TIME(rRunMonitoringTime * 1000);
TON01.IN := xRep_Switch AND xStage_1 AND NOT xRunMonitoring AND NOT xError;
TP02.PT := T#3S;
TP02.IN := TON01.Q;
xError_RunMonitoring := TON01.Q OR TP02.Q;

//Speed ​​Monitoring
TON02();
TON02.PT := REAL_TO_TIME(rRunMonitoringTime * 2000);
TON02.IN := xOperation AND NOT xError AND (rSpeed_RM = 0 OR ABS((rControlSignal/ MAX(0.1,rSpeed_RM))-1)>0.03);
xError_Drehzahluebw := TON02.Q;

 

Rewrite program

//Automatic On-Off Mode
CASE iFrg_GLT_019 OF
0: xHandOn := FALSE; xAutoOperation := FALSE; xSW_Man := FALSE;
1: xHandOn := TRUE; xAutoOperation := FALSE; xSW_Man := TRUE;
9: xHandOn := FALSE; xAutoOperation := TRUE; xSW_Man := FALSE;
ELSE
xHandOn := FALSE; xAutoOperation := FALSE; xSW_Man := FALSE;
END_CASE

//Activation of the enable
TOF01(IN:=xRelease OR xManualOn, PT:=REAL_TO_TIME(rOverrunTime * 1000));
rOverrunActual := TIME_TO_REAL(TOF01.ET) / 1000;
xLevel_1 := xActive AND (TOF01.Q OR (xAutoOperation AND xPBS_Enable));
xOverrunActive := TOF01.Q AND NOT TOF01.IN;

//Output of the control signal
rControlSignal := 0;
IF xLevel_1 THEN
IF xSW_Manual THEN
rControlSignal := rManual_SW * rManual_SW_Factor;
ELSIF xPBS_Enable AND NOT xEnable THEN
rControlSignal := rPBS_Speed;
ELSE
rControlSignal := rSpeed_SW;
END_IF;
END_IF;

rControlSignal := LIMIT(0, rControlSignal, 100);
wY_ControlSignal := REAL_TO_WORD(rControlSignal * 327.67);
rY_ControlSignal := rControlSignal * rManual_SW_Factor;

//Error message
TP01(IN:=xMotorProtect OR xPTCthermistor, PT:=T#10S);
xError := xMotorProtect OR xPTCthermistor OR TP01.Q;

//Running monitoring
xOperation := xRunningmonitor;
xRep_Switch_On := xRep_Switch;
TON01(IN:=xRep_Switch AND xStage_1 AND NOT xRunMonitoring AND NOT xError, PT:=REAL_TO_TIME(rRunMonitoringTime * 1000));
TP02(IN:=TON01.Q, PT:=T#3S);
xError_RunMonitoring := TON01.Q OR TP02.Q;

//Speed Monitoring
TON02(IN:=xOperation AND NOT xError AND (rSpeed_RM = 0 OR ABS((rControlSignal / MAX(0.1, rSpeed_RM)) - 1) > 0.03), PT:=REAL_TO_TIME(rRunMonitoringTime * 2000));
xError_Drehzahluebw := TON02.Q;

Performance review

- The first IF-ELSIF-ELSE block could be optimized for better performance by using a CASE statement instead.
- The TOF01 function is called but not defined in the provided code, which may lead to errors or unexpected behavior.
- The TP01 and TP02 functions are called but not defined in the provided code, which may lead to errors or unexpected behavior.
- The calculation of rStellsignal could be optimized by using a temporary variable to store the common factor (rHand_SW_Faktor) instead of calculating it twice.
- The TON01 and TP02 functions are called but not defined in the provided code, which may lead to errors or unexpected behavior.
- The calculation of xError_Drehzahluebw could be optimized by using a temporary variable to store the common condition (xBetrieb AND NOT xError) instead of calculating it twice.

Tidy up

FUNCTION_BLOCK FB_Motor_FC_01
(*
2018-04-16 BH Error messages changed to "True=Error"!
2019-06-26 BH Created from FB_Motor_FC_01
2019-08-21 BH Bug fix
2019-12-04 BH BMS off/on with overrun changed (version FRA3-F)
2020-09-08 BH PBS only in automatic mode
2020-09-15 BH Actuating signal remains with manual off (version MUC-B)
2021-11-15 BH Manual off is not functional! Enable is removed via the priority function block (version ZRH-B)
2024-05-14 NiFr Recreated in CoDeSys V3
*)
(*
Block for Control of the refrigeration system pumps.
Caution: A fault does not cause a shutdown!
*)
VAR_INPUT
xActive : BOOL ; (* Activates the function block *)
xEnable : BOOL ; (* Motor is requested *)
rSpeed_SW : REAL ; (* Control signal, 0-100% *)
iFrg_GLT_019 : INT :=9 ; (* Enables the BMS, 0-Off, 1-On, 9-Auto *)
rManual_SW : REAL ; (* Setpoint for manual on *)
rManual_SW_Factor : REAL :=1 ; (* Factor for converting Hertz to %, e.g., 50Hz -> 2; 60Hz -> 1.666; to % -> 1 *)
rOverrun Time :REAL :=0; (* Run-on time in automatic mode, in seconds *)
xRep_Switch : BOOL := TRUE ; (* Repair switch, True=ON *)
xMotorProtect : BOOL := TRUE ; (* Motor protection contact, True=Error *)
xPTC Thermistor :BOOL := TRUE; (* PTC thermistor contact, True=Error *)
// xRunMonitor : BOOL := TRUE ; (* Contact for run monitoring, True=Motor running *) // unused
// rRunMonitor_Time : REAL :=10 ; (* Run monitoring switch-on delay, time in seconds *) // unused
rSpeed_RM : REAL :=999 ; (* Motor speed feedback, 0-100%, 999 = monitoring deactivated *)
xPBS_Enable : BOOL ; (* Enables the pump for pump blocking protection, True=On *)
rPBS_Speed ​​:REAL; (* Speed ​​for pump blocking protection, in % *)
// xSSM_Ack : BOOL ; (* Acknowledges fault message, True=Ack *) // unused
END_VAR
VAR_OUTPUT
// xStufe_1 : BOOL ; (* Enables the motor *) // unused
// rY_Control_Signal : REAL ; (* Control signal in percent or Hz with conversion factor *) // unused
// wY_Control_Signal : WORD ; (* Control signal as word 0-32767 *) // unused
xRep_Switch_On : BOOL ; (* Control switch On *)
// xError_Laufuebw : BOOL ; (* Fault in run monitoring, True=Error *) // unused
xError_Drehzahluebw : BOOL ; (* Fault in speed monitoring, True=Error *)
xError : BOOL ; (* Fault, does not require acknowledgment, does not shut down!, True=Error *)
xOperation : BOOL ; (* Motor running feedback, via xRunMonitor. True=On *)
// xOverrun_active : BOOL ; (* Overrun is active, True=Overrun *) // unused
// rOverrun_Actual : REAL ; (* Elapsed overrun time, in s *) // unused
// xRev_02_5 : BOOL ; (* Revision 02.5; 2021-11-15 BH Manual Off is not functional! Enable is removed via Prio-FB (ZRH-B version) *) // unused
END_VAR
VAR
TON01 : TON ;
TOF01 : TOF ;
xManualOn : BOOL ;
xAutoOperation : BOOL ;
xSW_Manual : BOOL ; (* Manual setpoint active *)
rPositioning signal : REAL; (* Internal control signal from 0-100% *)
TON02 : TON ;
TP01 : TP ;
TP02 : TP ;
END_VAR

Anti-patern sweep

- Deep IF nesting in the first block can be simplified for better readability and maintainability.
Fix: Use a CASE structure or multiple IF statements to handle different conditions separately.
- Magic numbers (e.g., 9, 1000) should be replaced with named constants for clarity and easier maintenance.
Fix: Define constants at the beginning of the code for these values.
- Mixed edge/level logic in the "Aktivierung der Freigabe" section can lead to confusion.
Fix: Use consistent logic (either edge-triggered or level-triggered) throughout this section.
- Duplicated rungs in the "Störmeldung" and "Laufüberwachung" sections are not necessary.
Fix: Remove one of the duplicated rungs to simplify the code.
- Unsafe casts from REAL to TIME and vice versa can lead to unexpected behavior or errors.
Fix: Use appropriate functions for type conversion (e.g., REAL_TO_TIME, TIME_TO_REAL) with proper handling of units.

Safety & Determinism check

- Determinism Risk: The behavior of the system could be non-deterministic if iFrg_GLT_019 changes its value during the execution of the IF-ELSIF-ELSE block, leading to unpredictable results for xHandEin, xAutoBetrieb, and xSW_Hand.
- Race Condition: There is a potential race condition in the assignment of rStellsignal where its value could be changed simultaneously by two different branches of the IF-ELSIF-ELSE block. This could lead to inconsistent or unexpected results.

Recommendations:
- To mitigate determinism risks, consider using a state machine approach or adding additional checks to ensure that iFrg_GLT_019 does not change during the execution of the IF-ELSIF-ELSE block.
- To avoid race conditions in the assignment of rStellsignal, consider restructuring the code to eliminate simultaneous assignments from different branches of the IF-ELSIF-ELSE block or using a temporary variable to hold intermediate results before assigning them to rStellsignal.

Test scaffolding & documenting

Module Docstring:
This module handles the operation mode of a system, including manual and automatic modes with various conditions for activation and deactivation. It also manages the output signal based on different states and conditions. Additionally, it includes error handling for motor protection and cold conductor issues, as well as monitoring for operation and speed.

High-Level Black-Box Test Cases:
1. Verify that the system correctly switches between manual, automatic, and off modes based on input iFrg_GLT_019 values 0, 1, and 9.
2. Ensure that the output signal rStellsignal is calculated correctly under different conditions (manual mode, PBS freigabe, etc.).
3. Confirm that errors are properly flagged when xMotorschutz or xKaltleiter are true, and that TP01 timer functions as expected.
4. Test the operation of the TON01 and TP02 timers in the context of the laufüberwachung section to ensure correct error handling for lack of operation.
5. Validate the functionality of the drehzahlüberwachung section, including the TON02 timer and its role in detecting speed-related errors.

POU generator chat


LD to ST converter

Result

ADD
VAR
_prev_Input3 : BOOL;
END_VAR
Output1 := Input1;
Output2 := (Input1) AND (Input2);
IF ((Input1) AND (Input2)) AND (Input3) THEN
FC_Set_Reset(
    EN := ((Input1) AND (Input2)) AND (Input3),
    I_Reset := Input2,
    I_Set := Input1,
    O_Out => Output3
);
END_IF;
IF ((Input1) AND (Input2)) AND (Input3) THEN
RETURN;
END_IF;
IF Input1 THEN
IF Input1 AND Input2 THEN
 Output1 := FALSE;
end_if;
END_IF;
IF (Input1) AND (Input4) THEN
FC_Latch(
    EN := (Input1) AND (Input4),
    Input := Input3,
    Output => Output4
);
END_IF;
IF (Input1) AND (Input4) THEN
FC_Test(
    EN := (Input1) AND (Input4),
    I_Automatic := Input1,
    I_Manual := Input2,
    I_SemiAuto := Input3,
    FC_Test => Output2
);
END_IF;
Output3 := (Input1) AND ((Input3 AND (NOT _prev_Input3)));
// Edge memory updates
_prev_Input3 := Input3;

Monthly subscription

Rewrite for speed & clarity—instantly. Hit Ctrl + Alt + A and get an optimized program body that preserves intent while cutting dead code and improving loops. No markdown fluff, just clean ST.

 

Turn Ladder into ST in seconds. Paste a CODESYS .export and the Assistant converts networks to clear ST, even adding edge-memory vars when needed, then merges/tidies your declarations. Drag-and-drop ready.

 

Automatic declaration tidy-up. It aligns columns, preserves comments, and comments out unused variables (including a visual highlight), so your VAR blocks finally read like a spec sheet.

 

One-click safety & determinism checks. Surface race conditions and non-deterministic constructs before they hit the field, delivered as concise, actionable bullets your team can fix fast.

 

Kill anti-patterns before they cost you hours. Busy waits, deep IF nesting, magic numbers, unsafe casts, the Assistant flags them and tells you the one-line fix.

 

Built-in lint & metrics when AI can’t respond. Even offline, it detects unused vars, excessive nesting, and unreachable code, then summarizes savings (lines/vars) for your PR notes.

 

POU generator chat. Describe the module you need; get a full POU back (VAR…END_VAR + body) or JSON blocks, perfect for rapid scaffolding.

 

Keyboard-driven flow. Ctrl + Alt + A to analyze, Ctrl + Alt + H to hide inputs for a clean “suggested code only” view in demos and code reviews.

 

Works the way your stack does. Local Ollama support with model pull/probing, temperature control, and language preferences, keep code identifiers in English while localizing comments/UI.