🔍
v1.3.8

Introduction

Welcome to the TSharkRex programming language reference. This guide will take you from your first program to advanced vehicle integration, covering everything you need to build real-world automotive automation recipes.

What is TSharkRex?

TSharkRex is a PLC-style programming language based on the IEC 61131-3 Structured Text standard. It is purpose-built for XBB automotive diagnostic dongles - small devices that plug into (or are permanently mounted on) a vehicle’s CAN bus and can read signals, make diagnostic requests, and control external outputs such as lights or accessories.

If you have ever worked with industrial automation or PLC programming, TSharkRex will feel familiar. If your background is in general-purpose languages like C, Python, or JavaScript, think of TSharkRex as a real-time control language where your code runs in a continuous loop, reading inputs and writing outputs on every cycle.

IEC 61131-3 is the international standard for programmable logic controller (PLC) languages. TSharkRex adopts its Structured Text syntax - variable declarations, typed data, and control flow - while adding automotive-specific extensions for CAN bus communication and output control.

What Does It Do?

A TSharkRex program - called a recipe - typically performs two jobs:

  1. Read vehicle data - listen to CAN bus frames or send UDS (Unified Diagnostic Services) requests to ECUs to obtain signal values such as speed, gear position, high-beam status, ambient light level, and more.
  2. Control outputs - based on the signal values, drive physical outputs (LEDs, relays, accessories) connected through the dongle or an external PowerUnit module.

Here is a minimal example that turns on an output whenever the vehicle’s high-beam signal is active:

VAR
    CANRECV : CAN_RX;
    DATA : ARRAY[0..7] OF BYTE;
END_VAR;

VAR_SIGNAL
    SIGNAL_HELLJUS : BOOL;
END_VAR;

VAR_OUTPUT
    EXTRALJUS : OUTPUT;
END_VAR;

// Read CAN message from vehicle
CANRECV(ENABLE := TRUE, ID := 0x381, EXT := FALSE, DATA := DATA);

// Extract high-beam signal from byte 1, bit 3
SIGNAL_HELLJUS := DATA[1].3;

// Drive auxiliary light output based on high-beam
EXTRALJUS(VALUE := SIGNAL_HELLJUS * 1000, PERIOD := 1000);

Don’t worry about the syntax details yet - we will cover every construct in the chapters ahead. The key takeaway is that TSharkRex lets you express “read a vehicle signal, then control an output” in a compact, readable way.

Target Hardware

TSharkRex programs compile to native machine code for the ARM Cortex-M4 processor found inside all XBB hardware products:

The compiler takes care of targeting the correct hardware. You write the same TSharkRex code regardless of device; hardware-specific differences (CAN mode, wake-up method) are handled by the platform and standard libraries.

See the next chapter, Hardware Overview, for a detailed comparison of each product’s capabilities.

Language Characteristics

Case Sensitivity

TSharkRex is case-sensitive. Keywords must be written in their canonical form (usually uppercase), and identifiers are distinguished by case:

// These are three DIFFERENT variables:
VAR
    speed : INT;
    Speed : INT;
    SPEED : INT;
END_VAR;
Unlike some PLC environments that treat identifiers as case-insensitive, TSharkRex follows the IEC 61131-3 recommendation for case sensitivity. Always use the exact casing shown in the documentation for keywords (VAR, IF, END_IF, etc.).

Strongly Typed

Every variable must be declared with an explicit type before use. There is no dynamic typing or implicit type coercion. This catches many bugs at compile time rather than at runtime on the vehicle.

No Dynamic Memory

TSharkRex does not have heap allocation, garbage collection, or dynamic data structures. All memory is statically allocated at compile time. This is a deliberate design choice for safety and determinism - in an automotive environment, you need predictable timing and zero risk of memory leaks.

Development Workflow

TSharkRex programs are created and compiled on the TSharkRex Platform at xbb-code.com. The typical workflow looks like this:

  1. Write your recipe in the online code editor.
  2. Compile the recipe using the built-in compiler. The compiler runs server-side and produces an ARM binary.
  3. Install the compiled recipe onto your XBB device via the XBB mobile app over Bluetooth LE.
  4. Test the recipe on the vehicle. Monitor signals and outputs in real time using the app.
  5. Iterate - go back to step 1 and refine your logic.

You do not need to install any local toolchain. Everything from editing to compilation happens in the browser or through the platform API.

Execution Model

TSharkRex programs run in a continuous scan cycle, just like a traditional PLC:

// Conceptual execution model (you do NOT write this loop yourself):
//
//   1. Read all inputs (CAN signals, button state, etc.)
//   2. Execute your program code from top to bottom
//   3. Write all outputs (LEDs, relays, etc.)
//   4. Go back to step 1
//
// This cycle repeats as long as the device is powered.

Your code is the body of this loop. You never write an explicit while(true) or main() function - the runtime does that for you. Variable declarations in VAR blocks are initialized once when the program starts; the rest of the code executes on every scan.

This means you should think about your program as a set of rules that are continuously evaluated, rather than a sequence of steps that runs once. For example:

VAR_SIGNAL
    SIGNAL_HASTIGHET : INT;       // Vehicle speed (km/h)
END_VAR;

VAR
    varning_aktiv : INT;          // Intermediate variable for output value
END_VAR;

VAR_OUTPUT
    VARNINGSLAMPA : OUTPUT;       // Warning light
END_VAR;

// Logic: set intermediate variable based on condition
IF SIGNAL_HASTIGHET > 120 THEN
    varning_aktiv := 1000;        // Full brightness
ELSE
    varning_aktiv := 0;           // Off
END_IF;

// IMPORTANT: Output must be called EVERY scan cycle!
// Never put the output call inside an IF - it must always run.
VARNINGSLAMPA(VALUE := varning_aktiv, PERIOD := 1000);
Important: Always call outputs every cycle

A common mistake is to call OUTPUT() only inside an IF block. This means the output is not updated when the condition is false, which can cause the output to get stuck in its last state. Always calculate the value first (using an intermediate variable or an inline expression), then call the output unconditionally at the end of your code.

The XBB system runs at a fixed 10ms scan cycle (100 Hz). Your entire program executes once every 10ms. Within a single cycle, operations like WHILE loops for draining CAN_RX.AVAILABLE run at sub-millisecond speed on the ARM Cortex-M4, so you can process multiple CAN messages per cycle without any issue.

Recipes and Libraries

In TSharkRex terminology:

A set of standard libraries are provided by XBB for common tasks (wake-up, settings, flashers). You add these manually to your recipe’s library list - they are not added automatically. You can also create your own libraries to share code between recipes. See Chapter 24 for the full library structure.

What You Will Learn

This reference guide is organized as a progressive tutorial. Here is what the upcoming chapters cover:

Later chapters will cover variables, operators, control flow, functions, function blocks, CAN communication, UDS requests, output control, and advanced topics. By the end, you will be able to write production-quality recipes for any XBB-supported vehicle.