Multi-Trigger Asynchronous Event Handling
An instrument cluster ECU must concurrently respond to diverse asynchronous triggers: vehicle speed broadcast frames arriving every 20ms, driver trip reset button presses, warning chime expiration timers, and CAN bus error frames. CAPL's event-driven architecture handles each trigger cleanly through independent event handlers.
Overview & Key Concepts
In CAPL (CAN Application Programming Language) scripting, events are mechanisms that allow you to react to specific triggers or conditions within the system. Events enable CAPL programs to respond to CAN bus traffic, user inputs, and time-based or condition-based occurrences. These events are crucial in handling asynchronous and real-time communication in embedded systems, such as automotive ECUs (Electronic Control Units), network monitoring, or simulation setups.
Types of Events in CAPL
There are several types of events in CAPL scripting, and each serves a different purpose. They include:
Message Events
Timer Events
User Input Events
State Machine Events
Error Events
Let's go through these events in detail with examples.
Message Events
These events are triggered when a message is received on the CAN bus. In CAPL, you can write functions that respond when certain CAN messages are received or transmitted. These functions are called message event handlers.
Example: Message Event Handler
on message EngineSpeed {
// This event triggers when an "EngineSpeed" message is received on the CAN bus
output("Engine speed message received.");
int speed = EngineSpeed.Speed; // Access the "Speed" signal within the message
if (speed > 3000) {
output("Engine speed is high!");
}
}
Explanation:
The on message keyword defines a handler for a specific message, in this case, EngineSpeed.
Whenever an EngineSpeed message is received, the event triggers the block of code, where we access the signal Speed and check if it is above a certain threshold.
Timer Events
Timers are used to schedule periodic events in CAPL scripts. Timers allow you to execute certain actions after a specified delay or at periodic intervals.
Example: Timer Event
variables
{
msTimer myTimer; // Declare a timer variable
}
on start
{
setTimer(myTimer, 1000); // Set the timer to 1000ms (1 second)
}
on timer myTimer
{
output("1 second has passed!");
setTimer(myTimer, 1000); // Reset the timer to trigger again after 1 second
}
Explanation:
msTimer myTimer; declares a timer variable.
The setTimer() function is used to set the timer to a specific delay (1000ms in this case).
When the timer expires, the on timer event handler triggers, and the specified code is executed. The timer is then reset to continue triggering periodically.
User Input Events
User input events are triggered by actions from the user, such as pressing a button or typing in a control panel. These inputs are often used in simulation environments or testing tools.
Example: User Input Event
on key 'a'
{
output("The 'A' key was pressed.");
}
on key 'b'
{
output("The 'B' key was pressed.");
}
Explanation:
The on key event is triggered when the specified key is pressed on the keyboard.
In this example, pressing the 'A' key will output a message saying "The 'A' key was pressed" and similarly for the 'B' key.
State Machine Events
CAPL also supports state machine events, which are useful for modeling systems that operate in various states. These states can be changed based on certain conditions or events.
Example: State Machine Event
variables
{
state systemState = Idle; // Declare a state variable
}
enum state { Idle, Running, Stopped }
on message StartEngine
{
if (systemState == Idle) {
systemState = Running;
output("Engine is now Running.");
}
}
on message StopEngine
{
if (systemState == Running) {
systemState = Stopped;
output("Engine has Stopped.");
}
}
Explanation:
The enum is used to define states (Idle, Running, Stopped).
The systemState variable holds the current state of the system.
The state changes are triggered by receiving certain messages, such as StartEngine or StopEngine.
The state transitions are controlled within the on message event handlers, and messages are output based on the new state.
Error Events
Error events in CAPL allow you to monitor the status of the CAN bus or specific devices and react accordingly when errors occur.
Example: Error Event Handler
on error
{
output("An error occurred on the CAN bus!");
}
Explanation:
The on error event handler triggers when an error is detected in the CAN bus communication.
The code inside the handler executes whenever the error event is triggered, such as reporting an issue or taking corrective action.
Conclusion
Events in CAPL scripting provide a powerful way to respond to changes or triggers in your embedded systems or simulations. By using message handlers, timers, user inputs, state machines, and error detection, you can create responsive and robust applications that interact with CAN bus systems or other hardware in real time. Each type of event serves a specific role, and understanding how to use them effectively will help you build better scripts and simulations.
| Event Type | Syntax Example |
|---|---|
| Message Event | on message <MessageName> { // Code to execute } |
| Timer Event | on timer <TimerName> { // Code to execute } |
| User Input Event | on key '<key>' { // Code to execute } |
| State Machine Event | on <event> { // Code to execute } |
| Error Event | on error { // Code to handle error } |
- Never assume the arrival order of asynchronous events. Use state flags and timestamps rather than implicit execution ordering.
- Handler execution must be lightweight: long computational routines should be divided into timer chunks to maintain real-time simulation fidelity.
Select your answer for each question below to receive immediate correctness evaluation and in-depth technical rationale.
Create an event-driven CAPL node with two event handlers: 1) 'on key 'r'' which resets a global float `gTripDistanceKm` to 0.0, and 2) 'on message 0x120' (VehicleSpeedMsg) that adds distance to `gTripDistanceKm` based on speed and delta time.
Verified CAPL implementation:
variables {
float gTripDistanceKm = 0.0;
dword gLastTimestamp = 0;
}
on start {
gLastTimestamp = timeNow();
write("Trip Meter initialized.");
}
on key 'r' {
gTripDistanceKm = 0.0;
write("Trip Meter manually reset to 0.0 km.");
}
on message 0x120 {
dword currentTime;
float deltaHours;
float currentSpeedKmh;
currentTime = timeNow();
// CANoe timeNow() returns time in 10 microsecond units (or 100us depending on config)
deltaHours = (currentTime - gLastTimestamp) / 360000000.0;
// Extract speed from payload byte 0 and 1
currentSpeedKmh = (this.byte(0) * 256 + this.byte(1)) * 0.01;
gTripDistanceKm += (currentSpeedKmh * deltaHours);
gLastTimestamp = currentTime;
}