Standard Library
The standard library (NEW_FB_STANDARD_LIB_V3) provides helper functions
and function blocks used across all XBB recipes. It includes things like value clamping,
dimming control, battery monitoring, and wake-up logic.
Standard libraries are not added automatically to new recipes. You must manually add them to your recipe’s library list in the correct order. The standard libraries are available as shared libraries in the system - you do not need to create them, but you do need to link them to your recipe.
The correct library order is:
NEW_FB_STANDARD_LIB_V3- core function blocksNEW_UDS_DID_WAKE_UP_V2(UDS) orNEW_PP_CAN_FD_WAKE_UP_V1(PP-CAN) - wake-up- Your DID module / CAN reading library
NEW_STANDARD_FUNCTIONS_V1- settings, flashers, worklights- Your main recipe (last)
Once the standard library is linked, all its functions and function blocks become
available in your code. For example, HW : HARDWARE is declared and
initialized by the standard library, so you can use HW.SUPPLY_VOLTAGE
directly without declaring it yourself.
Helper Functions
VAL_CLAMP
Clamps a value to a min/max range. Returns MIN if below, MAX if above, otherwise unchanged.
// Definition (in standard library):
FUNCTION VAL_CLAMP : DINT
VAR_INPUT
INVAL : DINT; // Value to clamp
MIN : DINT; // Lower bound
MAX : DINT; // Upper bound
END_VAR;
// Usage in your recipe:
result := VAL_CLAMP(brightness, 0, 1000); // Clamp to PWM range
temp := VAL_CLAMP(rawTemp, 0, 250); // Clamp to sensor range
speed := VAL_CLAMP(rawSpeed, 0, 300); // Clamp to max speed
VAL_CLAMP is used extensively in production recipes, especially for
the HIGHBEAM output: HIGHBEAM(VALUE := VAL_CLAMP(signal, 0, 1000), PERIOD := 1000);
PLC_INPUT
Converts the analog input voltage to a clean BOOL by comparing it against
the supply voltage. Returns TRUE when analog input is above 70% of supply,
FALSE when below 30%. Holds previous state between 30–70% (hysteresis).
// Definition:
FUNCTION PLC_INPUT : BOOL
VAR_INPUT
REF : DINT; // Reference voltage (mV) - use HW.SUPPLY_VOLTAGE
IN : DINT; // Input voltage (mV) - use HW.ANALOG_IN0
END_VAR;
// Usage (read ignition from analog input on Dongle-2):
VAR_SIGNAL
HW : HARDWARE;
SIGNAL_IN_TANDNING : BOOL;
END_VAR;
HW();
SIGNAL_IN_TANDNING := PLC_INPUT(HW.SUPPLY_VOLTAGE, HW.ANALOG_IN0);
Recommended for VAG vehicles (VW, Audi, Skoda, Seat, Cupra, Porsche) with +12V on OBD-II pin 1. See Example 6.
GET_PLC_TIME
Returns time in milliseconds since program start as UDINT.
This is the PLC’s internal clock, similar to GET_SYSTEM_TIME().
VAR
start : UDINT;
elapsed : UDINT;
END_VAR;
start := GET_PLC_TIME();
// ... do work ...
elapsed := GET_PLC_TIME() - start; // Elapsed time in milliseconds
RND
Pseudo-random number generator using a Linear Congruential Generator (LCG) algorithm. Returns a value from 0 to MAX−1.
// Definition:
FUNCTION RND : UDINT
VAR_INPUT
MAX : UDINT; // Upper bound (exclusive)
END_VAR;
// Usage:
random_value := RND(100); // Returns 0-99
random_delay := 500 + RND(1500); // Returns 500-1999
About the Algorithm
LCG is a simple, fast, and deterministic algorithm commonly used in embedded systems.
It uses the formula: seed = (a * seed + c) mod m, where a,
c, and m are fixed constants. The output is then mapped to
the range 0..MAX-1 using modulo.
What this means for you:
- Fast - single multiplication + addition per call, negligible CPU cost
- Deterministic - same seed produces the same sequence every time. The seed is initialized from system time at startup, so the sequence varies between power cycles
- Not cryptographically secure - the sequence is predictable. This is fine for visual effects (flicker, random delays, pattern variation) but should not be used for security-critical applications
- Uniform distribution - values are roughly evenly distributed across the range, though LCG can have correlation between consecutive values
Good for: random flash patterns, variable delays, visual effects,
staggering CAN request timing.
Not suitable for: cryptography, encryption keys, security tokens.
BYTE_TO_BOOL
Converts a BYTE to BOOL. Returns TRUE if value > 0, FALSE if value = 0.
FUNCTION BYTE_TO_BOOL : BOOL
VAR_INPUT
MYBYTE : BYTE;
END_VAR;
// Usage:
flag := BYTE_TO_BOOL(canData[3]); // TRUE if byte is non-zero
Function Blocks
These function blocks are instantiated automatically by the standard library. You interact with them by setting their input variables and reading their outputs.
DIM_MATRIX
Smooth dimming controller for lights. Creates fade-in/fade-out effects by ramping the output value gradually instead of switching instantly.
| Variable | Type | Direction | Description |
|---|---|---|---|
DIM | BOOL | Input | Enable gradual dimming (ramp up when TRUE, ramp down when FALSE) |
ON | BOOL | Input | Instant on/off (bypasses dimming, jumps to MAX/MIN) |
UP | INT | Input | Increment step per scan cycle when ramping up |
DOWN | INT | Input | Decrement step per scan cycle when ramping down |
MIN | INT | Input | Minimum output value |
MAX | INT | Input | Maximum output value |
OUT | INT | Output | Current output level (ramps between MIN and MAX) |
OUT_STATIC | INT | Output | Target level (MIN or MAX) |
VAR
DIMMER : DIM_MATRIX;
END_VAR;
VAR_OUTPUT
LIGHT : OUTPUT;
END_VAR;
// Configure dimming parameters
DIMMER(
DIM := SIGNAL_HELLJUS, // Ramp up when high beam on, ramp down when off
ON := FALSE, // Not using instant on
UP := 50, // Ramp up speed (higher = faster)
DOWN := 30, // Ramp down speed (lower = smoother fade-out)
MIN := 0,
MAX := 1000
);
// Use the dimmer output for smooth light control
LIGHT(VALUE := DIMMER.OUT, PERIOD := 1000);
Adjust UP and DOWN to control transition speed.
Typical values: UP=50, DOWN=30 (slightly slower fade-out than fade-in).
Higher values = faster transition, lower = smoother.
GYRO_DETECT
Gyroscope-based movement detection. Detects vehicle movement by monitoring the dongle’s built-in gyroscope. Key component of the wake-up system.
| Variable | Type | Direction | Description |
|---|---|---|---|
X | INT | Input | Gyro X axis (from HW.GYRO_X) |
Y | INT | Input | Gyro Y axis (from HW.GYRO_Y) |
Z | INT | Input | Gyro Z axis (from HW.GYRO_Z) |
THRESHOLD | INT | Input | Movement threshold (higher = less sensitive) |
INIT_DELAY | TIME | Input | Ignore readings during startup |
MOVEMENT | BOOL | Output | TRUE when movement detected |
READY | BOOL | Output | TRUE when init delay has passed |
GYRO_DETECT is used internally by the wake-up library
to detect vehicle movement. The wake-up library creates the instance, feeds it gyro
data from HW, and uses it to trigger system wake-up. You configure it
indirectly through your recipe’s wake-up settings:
// In your main recipe - this is all you need:
GYRO_WAKE_UP := TRUE; // Enable gyro-based wake-up
GYRO_VALUE := 60; // Sensitivity threshold (higher = less sensitive)
// The wake-up library internally does:
// GYRO.X := HW.GYRO_X;
// GYRO.Y := HW.GYRO_Y;
// GYRO.THRESHOLD := GYRO_VALUE; (your setting)
// GYRO();
// IF GYRO.MOVEMENT THEN ... wake up ...
For electric vehicles with heat pumps or other vibration sources, increase
GYRO_VALUE to 100–150 to prevent false wake-ups. Default is 60.
BATT_MONITOR
Battery voltage monitor with hysteresis and delay. Detects low-battery conditions to prevent draining the vehicle battery. Managed internally by the wake-up library.
| Variable | Type | Direction | Description |
|---|---|---|---|
VOLTAGE | INT | Input | Current voltage (mV) |
OFF_MV | INT | Input | Low battery threshold (mV) |
ON_MV | INT | Input | Recovery threshold (mV) |
DELAY | TIME | Input | Delay before state change |
LOW_BATT | BOOL | Output | TRUE when battery is low |
Like GYRO_DETECT, you configure battery monitoring through your
recipe’s wake-up settings - the wake-up library does the rest:
// In your main recipe - this is all you need:
BATTOFF := 11500; // 11.5V - shut down threshold
BATTON := 11900; // 11.9V - recovery threshold (hysteresis)
LOW_BATT_DELAY := T#30s; // Wait 30s before declaring low battery
// The wake-up library internally does:
// BATT.VOLTAGE := HW.SUPPLY_VOLTAGE;
// BATT.OFF_MV := BATTOFF; (your setting)
// BATT.ON_MV := BATTON; (your setting)
// BATT.DELAY := LOW_BATT_DELAY; (your setting)
// BATT();
// IF BATT.LOW_BATT THEN SIGNAL_SYSTEM_ON := FALSE;
BLINKER
Simple blink generator with configurable period. Toggles output on/off at a fixed rate.
Unlike the wake-up blocks above, BLINKER can be used directly in your code.
| Variable | Type | Direction | Description |
|---|---|---|---|
PERIOD | TIME | Input | Half-period (full cycle = 2x PERIOD) |
Q | BOOL | Output | Toggling output (TRUE/FALSE) |
VAR
BLINK : BLINKER;
blink_value : INT;
END_VAR;
VAR_OUTPUT
WARNING_LED : OUTPUT;
END_VAR;
// Configure and call the blinker
BLINK.PERIOD := T#300ms; // 300ms on, 300ms off = ~1.7 Hz
BLINK();
// Use BLINK.Q to drive output (via intermediate variable)
IF BLINK.Q THEN
blink_value := 1000;
ELSE
blink_value := 0;
END_IF;
// Output always called every cycle
WARNING_LED(VALUE := blink_value, PERIOD := 1000);
WAKE_TIMER
Off-delay timer for system wake-up. Unlike TOF, WAKE_TIMER
starts with Q = FALSE (safe at startup - system stays off until triggered).
Managed internally by the wake-up library.
| Variable | Type | Direction | Description |
|---|---|---|---|
IN | BOOL | Input | Trigger (movement, ignition, etc.) |
PT | TIME | Input | Hold time after trigger goes FALSE |
Q | BOOL | Output | System-on output |
You configure the hold time via your recipe:
// In your main recipe - this is all you need:
SYSTEM_ON_TIME := T#30s; // Stay awake 30s after last movement/ignition
// The wake-up library internally does:
// TMR_SYSTEM_ON.IN := GYRO.MOVEMENT OR SIGNAL_TANDNING;
// TMR_SYSTEM_ON.PT := SYSTEM_ON_TIME; (your setting)
// TMR_SYSTEM_ON();
// SIGNAL_SYSTEM_ON := TMR_SYSTEM_ON.Q;
Behavior: When IN is TRUE, Q is TRUE.
When IN goes FALSE, Q stays TRUE for PT
milliseconds, then goes FALSE. This keeps the system awake for a configurable period
after the last movement or ignition signal.
BMW_WAKE_SPECIAL
BMW-specific wake-up handler. BMW vehicles trigger alarms if the CAN bus is not periodically acknowledged. This block toggles between SILENT and NORMAL CAN mode every few seconds to empty the CAN buffer without triggering the alarm. Managed internally by the wake-up library.
| Variable | Type | Direction | Description |
|---|---|---|---|
ENABLE | BOOL | Input | Master enable |
ACK_INTERVAL | TIME | Input | How often to cycle CAN mode |
ACTIVE | BOOL | Output | BMW special mode is active |
CAN_MODE_OUT | BYTE | Output | 1=SILENT, 2=NORMAL |
You enable it via your recipe’s wake-up settings:
// In your main recipe - this is all you need for BMW:
CAN_WAKE_UP := TRUE; // Must be TRUE for BMW
GYRO_WAKE_UP := FALSE; // Must be FALSE when CAN_WAKE_UP is TRUE
BMW_WAKE_UP := TRUE; // Enable BMW alarm handling
// The wake-up library internally does:
// BMW.ENABLE := BMW_WAKE_UP AND CAN_WAKE_UP;
// BMW.ACK_INTERVAL := T#3s;
// BMW();
// IF BMW.ACTIVE THEN
// toggle CANMODE between SILENT and NORMAL every 3s
// END_IF;
BMW_WAKE_SPECIAL is only for BMW vehicles.
Setting BMW_WAKE_UP := TRUE on non-BMW vehicles will cause
the CAN controller to switch between SILENT and NORMAL mode repeatedly,
which prevents normal communication.
Global Hardware Instance
The standard library declares a global HARDWARE instance named HW:
// Declared by the standard library (do NOT redeclare):
VAR_SIGNAL
HW : HARDWARE;
END_VAR;
HW();
HW.GYRO_Z := 0; // Workaround for faulty Z axis on some hardware
This HW instance is available in all recipe files. You do not need to
declare it yourself - just use HW.SUPPLY_VOLTAGE,
HW.GYRO_X, HW.BUTTON, etc. directly.
Standard Libraries Reference
These are the standard libraries you should add to your recipe. They are shared libraries available in the system - you link them to your recipe, you do not create them yourself.
| Library | Reference Recipe | Purpose |
|---|---|---|
NEW_FB_STANDARD_LIB_V3 |
1332 / 1568 | Core function blocks, helper functions, HW instance (this chapter) |
NEW_UDS_DID_WAKE_UP_V2 |
1332 | UDS wake-up: gyro detection, CAN init, sleep management |
NEW_PP_CAN_FD_WAKE_UP_V1 |
1568 | PP-CAN wake-up: voltage detection, CAN mode management |
NEW_STANDARD_FUNCTIONS_V1 |
1332 / 1568 | Settings UI, flasher patterns, worklights, common utilities |
These libraries already exist in the system. Do not create your own copies - just link the existing ones to your recipe. Duplicating them causes compilation errors from duplicate variable declarations.
You can find these libraries by searching in the library list. If you are starting from a template or copying an existing recipe, the libraries are usually already linked. If you are creating a recipe from scratch, add them manually in the order shown above.