Getting Started
This chapter walks you through the anatomy of a TSharkRex program, introduces comments and reserved keywords, and explains how the execution model works. By the end, you will understand enough to read and modify simple recipes.
Program Anatomy
Every TSharkRex program (recipe) is composed of two parts:
- Variable declarations - one or more
VARblocks that define all data the program uses. - Executable code - the logic that runs on every scan cycle.
Here is a complete minimal recipe:
VAR
A : BOOL;
B : BOOL;
END_VAR;
VAR_OUTPUT
MY_OUTPUT : OUTPUT;
END_VAR;
// Output always called every cycle - use (A OR B) directly as value
MY_OUTPUT(VALUE := (A OR B) * 1000, PERIOD := 1000);
Let’s break this down section by section.
The VAR Block
VAR
A : BOOL;
B : BOOL;
END_VAR;
The VAR ... END_VAR block declares local variables. These are private to your program and retain their values between scan cycles (they are not re-initialized on each cycle).
Each variable declaration follows the pattern:
name : TYPE;
name : TYPE := initial_value;
If no initial value is given, the variable is initialized to zero (for numeric types) or FALSE (for BOOL).
The VAR_OUTPUT Block
VAR_OUTPUT
MY_OUTPUT : OUTPUT;
END_VAR;
The VAR_OUTPUT block declares output channels. Each output corresponds to a physical output on the dongle or PowerUnit. The OUTPUT type is a special built-in type that provides methods for controlling brightness, flash patterns, and timing.
Outputs declared here appear in the XBB mobile app, where the user can see their status in real time.
The Executable Code
VAR
A : BOOL;
B : BOOL;
END_VAR;
VAR_OUTPUT
MY_OUTPUT : OUTPUT;
END_VAR;
// Boolean expression directly as value: TRUE (1) * 1000 = on, FALSE (0) * 1000 = off
MY_OUTPUT(VALUE := (A OR B) * 1000, PERIOD := 1000);
Everything after the variable declarations is executable code that runs on every scan cycle. In this example:
(A OR B)- evaluates toTRUE(1) orFALSE(0).* 1000- converts the boolean to a PWM value: 1 × 1000 = full on, 0 × 1000 = off.PERIOD := 1000- sets the PWM period to 1000 microseconds (1 kHz).
VALUE parameter uses a scale of 0–1000, where 1000 = 100.0% and 500 = 50.0%. This gives you 0.1% resolution for PWM dimming. The PERIOD parameter is in milliseconds.
Variable Declaration Blocks
TSharkRex provides several types of declaration blocks, each serving a different purpose:
| Block | Purpose |
|---|---|
VAR |
Local variables (general-purpose storage) |
VAR_SIGNAL |
CAN bus signal inputs (mapped to vehicle data) |
VAR_OUTPUT |
Physical output channels (lights, relays) |
VAR_INPUT |
Input parameters for function blocks |
VAR_CONSTANT |
Compile-time constants |
A more realistic recipe uses multiple block types:
VAR_SIGNAL
SIGNAL_HELLJUS : BOOL; // High-beam from vehicle CAN
SIGNAL_HASTIGHET : INT; // Speed in km/h
END_VAR;
VAR_OUTPUT
EXTRALJUS : OUTPUT; // Auxiliary lights
VARNINGSLJUS : OUTPUT; // Warning indicator
END_VAR;
VAR
aktiv : BOOL := FALSE; // Local state variable
END_VAR;
VAR_CONSTANT
MAX_HASTIGHET : INT := 120; // Speed threshold
END_VAR;
// Determine if aux lights should be active
aktiv := SIGNAL_HELLJUS AND (SIGNAL_HASTIGHET < MAX_HASTIGHET);
// Outputs always called every cycle
EXTRALJUS(VALUE := aktiv * 1000, PERIOD := 1000);
VARNINGSLJUS(VALUE := (SIGNAL_HASTIGHET > MAX_HASTIGHET) * 1000, PERIOD := 1000);
Comments
TSharkRex supports two styles of comments:
Line Comments
Use // for single-line comments. Everything after // on that line is ignored by the compiler:
// This entire line is a comment
VAR
hastighet : INT; // This comment explains the variable
END_VAR;
Block Comments
Use (* ... *) for multi-line block comments:
(*
This is a block comment.
It can span multiple lines.
Useful for longer explanations or temporarily
disabling sections of code.
*)
VAR
(* You can also use block comments inline *)
temp : INT;
END_VAR;
Comments in VAR_SIGNAL
Comments placed on signal declarations have a special behavior: they are displayed in the TSharkRex Platform UI (xbb-code.com) as the signal’s description. This makes your code easier to understand when browsing libraries:
VAR_SIGNAL
SIGNAL_HELLJUS : BOOL; // Helljus (aktiv/inaktiv)
SIGNAL_BLINKERS_V : BOOL; // Vänster blinkers
SIGNAL_BLINKERS_H : BOOL; // Höger blinkers
SIGNAL_HASTIGHET : INT; // Fordonets hastighet (km/h)
END_VAR;
VAR_SIGNAL declarations. End users see these comments in the app when viewing signal values, and they make your recipe much easier to understand.
Case Sensitivity
TSharkRex is case-sensitive, consistent with the IEC 61131-3 standard. This applies to:
- Keywords - must be uppercase:
VAR,IF,THEN,END_IF,TRUE,FALSE, etc. - Type names - must be uppercase:
BOOL,INT,DINT,REAL, etc. - Identifiers -
speed,Speed, andSPEEDare three different variables.
// CORRECT:
IF aktiv THEN
EXTRALJUS(VALUE := 1000);
END_IF;
// WRONG - will NOT compile:
if aktiv then // 'if' and 'then' must be uppercase
EXTRALJUS(value := 1000); // 'value' must be uppercase (VALUE)
end_if; // 'end_if' must be uppercase
Reserved Keywords
The following words are reserved by the TSharkRex language and cannot be used as variable names, function names, or other identifiers:
Control Flow
IF |
THEN |
ELSE |
ELSIF |
END_IF |
CASE |
OF |
END_CASE |
||
WHILE |
DO |
END_WHILE |
||
FOR |
TO |
END_FOR |
||
EXIT |
RETURN |
Declarations
VAR |
VAR_SIGNAL |
VAR_INPUT |
VAR_OUTPUT |
VAR_CONSTANT |
CONSTANT |
GLOBAL |
END_VAR |
Functions, Function Blocks, and Types
FUNCTION |
END_FUNCTION |
FUNCTION_BLOCK |
END_FUNCTION_BLOCK |
TYPE |
END_TYPE |
STRUCT |
END_STRUCT |
Operators and Literals
TRUE |
FALSE |
NOT |
AND |
OR |
MOD |
BAND |
BOR |
BNOT |
XOR |
SHL |
SHR |
Types and Data
ARRAY |
POINTER |
NULL |
nullptr |
CAN Mode Constants
CAN_MODE_CONFIG |
CAN_MODE_NORMAL |
CAN_MODE_SLEEP |
CAN_MODE_DEEP_SLEEP |
CAN_MODE_SILENT |
is_array instead of ARRAY, or exit_flag instead of EXIT).
Program Execution Model
Understanding the execution model is fundamental to writing correct TSharkRex programs. Here are the key rules:
The Scan Cycle
Your code runs in a continuous loop. On each iteration (called a scan):
- Inputs are read - all
VAR_SIGNALvalues are updated with the latest data from the CAN bus. - Your code executes - from the first line after the declarations to the last line, top to bottom.
- Outputs are written - all
VAR_OUTPUTvalues are sent to the physical output hardware. - Repeat - the cycle starts over immediately.
Initialization
Variable declarations (VAR blocks) are processed once when the program starts. Initial values are set at this point. After initialization, the declarations are not re-executed - only the executable code section runs on each scan.
VAR
raknare : INT := 0; // Set to 0 once at startup
END_VAR;
// This runs every scan cycle
raknare := raknare + 1; // Increments on every cycle
State Persistence
Local variables in VAR blocks retain their values between scans. This is different from many programming languages where local variables are re-created each time a function is called. In TSharkRex, think of VAR variables as persistent state:
VAR
har_sett_helljus : BOOL := FALSE; // Remembers across scans
END_VAR;
VAR_SIGNAL
SIGNAL_HELLJUS : BOOL;
END_VAR;
// Once high-beam has been seen, this stays TRUE forever
// (until the device is reset)
IF SIGNAL_HELLJUS THEN
har_sett_helljus := TRUE;
END_IF;
No Main Function
There is no main(), no entry point function, and no explicit loop. You write the body of the scan cycle directly. The runtime provides the loop structure for you.
A Complete Example
Putting it all together, here is a recipe that reads vehicle high-beam and speed signals, then controls auxiliary lights with speed-dependent behavior:
(*
Recipe: Extraljus med hastighetsspärr
Controls auxiliary lights based on high-beam,
with automatic disable above 160 km/h.
*)
VAR_SIGNAL
SIGNAL_HELLJUS : BOOL; // High beam active
SIGNAL_HASTIGHET : INT; // Speed in km/h
END_VAR;
VAR
extraljus_varde : INT; // Intermediate: calculated output value
END_VAR;
VAR_OUTPUT
EXTRALJUS : OUTPUT; // Auxiliary light output
END_VAR;
VAR_CONSTANT
HASTIGHETSGRANS : INT := 160; // Max speed for aux lights
END_VAR;
// Calculate the output value based on conditions
IF SIGNAL_HELLJUS AND (SIGNAL_HASTIGHET < HASTIGHETSGRANS) THEN
extraljus_varde := 1000; // Full brightness
ELSE
extraljus_varde := 0; // Off (no high beam, or speed too high)
END_IF;
// Output is ALWAYS called every scan cycle - never inside IF!
EXTRALJUS(VALUE := extraljus_varde, PERIOD := 1000);
A Note on Semicolons
TSharkRex uses semicolons (;) as statement terminators. Every variable declaration and every executable statement ends with a semicolon. The END_VAR keyword also requires a trailing semicolon:
VAR
x : INT; // Semicolon after declaration
END_VAR; // Semicolon after END_VAR
x := x + 1; // Semicolon after assignment
IF x > 10 THEN // No semicolon after THEN
x := 0; // Semicolon after assignment
END_IF; // Semicolon after END_IF
IF ... THEN, WHILE ... DO, FOR ... TO ... DO) do not take a semicolon. Keywords that end a block (END_IF, END_WHILE, END_FOR, END_VAR) do.