User Tools

Site Tools


aircraft:tmd:events

Events Inside The TMD

Introduction

A very powerful tool in Aerofly FS 2 aircraft programming in the TMD file are events. Though not needed for any conventional aircraft with basic on/off switches, actuators and instruments, the events open the door for more complex avionics. Be it a multi-function display controller, where each button serves a different purpose on each page or a detecting changes in the system, e.g. the disconnection of the autopilot.

Events are usually only triggered every once in a while and are certainly not intended for constant state logic. Inherently the event logic is state-less. Events cannot replace an underlying logic circuit and shouldn't be allowed to continue to run for more than one execution. Their purpose is to execute a one time function, reset a timer to zero, play a sound once, change a digital state, etc.

None of the event objects have an Output, except event_pulse, event_timeout (in DynamicObjects) and event_sound (output to sound section).

So what are events then?

An event in the tmd is a function execution, a function that has one input value that is passed on from one element to the next and that returns nothing. The function that is executed and weather or not additional events can be fired depend on the specific element. Such a function is typically called Trigger, Set, Step or Reset.

void Trigger( double a )
{
  // do sth.
}

How are they triggered

The events are triggered by one of three means:

  • input_event - A button press triggers an event.
  • event_edge - A system change is detected, e.g. in the q400 the system senses that the power levers are advanced for takeoff and then sets the spoiler switch to flight mode automatically. This is also used for many lever sounds.
  • Events can trigger other events

Event Generation

input_event

The input_event receives messages from the controls or key and button inputs just like any other TMD input.

Depending on the qualifier of the message (event, step,toggle) either the Events, StepEvents or ToggleEvents list of functions is executed.

Adding the line <[float64][InputValue][1.0]> can filter the incoming messages by exact value.

            <[input_event][Button_Pressed][]
                <[string8][Message][Controls.Button]>
                <[string8][Events][ DEV0.Trigger ]>
            >
            <[input_event][Knob_Stepped][]
                <[string8][Message][Controls.Button]>
                <[string8][StepEvents][ DEV0.Trigger ]>
            >
            <[input_event][Button_Toggled][]
                <[string8][Message][Controls.Button]>
                <[string8][ToggleEvents][ DEV0.Trigger ]>
            >
            <[input_event][Button_Clicked][]
                <[string8][Message][Controls.Button]>
                <[string8][Events]      [ DEV0.Trigger ]>
                <[string8][StepEvents]  [ DEV0.Trigger ]>
                <[string8][ToggleEvents][ DEV0.Trigger ]>
            >
            <[input_event][Button1_Pressed][]
                <[string8][Message][Controls.Button]>
                <[float64][InputValue][1.0]>
                <[string8][Events][ DEV0.Trigger ]>
            >

event_edge

The event_edge, event_edge_rising and event_edge_falling objects constantly monitor the input. When the input passes through the Threshold it triggers all of the functions listed in the Events list.

  • event_edge_rising - The input is increasing and passes from below the threshold above the threshold then the Events are fired.
  • event_edge_falling - The input is moving from above the threshold below it then the Events are fired.
  • event_edge - When the input passes through the threshold it triggers the events.
            <[event_edge][State_Changed][]
                <[string8][Input][State.Output]>
                <[string8][Events][ DEV0.Trigger ]>
                <[float64][Value][0.0]>
                <[float64][Threshold][0.5]>
            >
            <[event_edge_rising][State_Increased][]
                <[string8][Input][State.Output]>
                <[string8][Events][ DEV0.Trigger ]>
                <[float64][Value][0.0]>
                <[float64][Threshold][0.5]>
            >
            <[event_edge_falling][State_Decreased][]
                <[string8][Input][State.Output]>
                <[string8][Events][ DEV0.Trigger ]>
                <[float64][Value][0.0]>
                <[float64][Threshold][0.5]>
            >

Event Value Manipulation

When a button, key command or joystick button are pressed they all generate messages and these messages carry a certain value. Most of them are 1.0, some are -1.0 (e.g. when rotated in the other direction) but other values can also exist. In the controls the value of the message can be set as needed.

When the message is received by an input_event the message value is passed on to any subsequently triggered events. And the event objects that are triggered in turn hand the value over to the next objects. The only exceptions are the event_linear, which scales the value and adds an offset, and the event_value which overwrites the value with its' own input.

The value is therefor carried from one event object to the next most of the time and we still have access to the original value way down the event chain.

When a Variable.Set function is called the variable then uses the value carried by the event call.

event_linear

The event_linear changes the value carried by the event and then triggers a list of Events with the new value. The new value is simply: NewValue = OldValue * Scaling + Offset.

            <[event_linear][StepSomething][]
                <[string8][Events][ DEV0.Trigger ]>
                <[float64][Scaling][1.0]>
                <[float64][Offset][0.0]>
            >

event_value

The event_value overwrites the value carried by the event chain and uses the value from the Input instead.

This is used to set a variable to a specific value with Variable.Set or Variable.Reset.

            <[event_value][SetSomethingToSomeValue][]
                <[string8][Input][SomeValue.Output]>
                <[string8][Events][ Something.Set ]>
            >

Event Logic

Depending on the value carried by the event or other values read in decisions can be made and whole decision trees can be set-up.

event_sequence

Creates a chain of events that are executed one after another. This allows objects like the autopilot, that only trigger a single Event and not multiple Events (note the s at the end!). It also allows events to be reused or multiple things to happen after a decision is made with an event_select or event_demultiplexer.

            <[event_sequence][Sequence][]
                <[string8][Events][ DEV0.Trigger DEV0.Trigger ]>
            >

event_demultiplexer

This is like a switch case with discrete input taken from the tmd.

The InputSelect value is taken in from the tmd and becomes a discrete integer. That value is then used as an index in the list, starting from 0 (zero based index). If the InputSelect value is outside of the range 0 to (n-1) no event is triggered.

If InputSelect == 0.0 → trigger event at index 0 (first in the list), if InputSelect == 1.0 → trigger event at index 1 (triggers second in the list), etc.
            <[event_demultiplexer][TriggerIf][]
                <[string8][InputSelect][Condition.Output]>
                <[string8][Events][ DEV0.Trigger DoSomething.Trigger ]>
            >

event_select

This is like a switch case with discrete input taken from the value of the event itself.

When triggered the event_select checks the value of the event call and casts it into an integer. Depending on the integer it selects one of the events from the Events list based on the calculated index. The list starts at index 0 (zero based index). When the value is below zero or higher than the number of events that can be triggered then no event is fired.

This is useful to have when there is a row of buttons, e.g. like a bezel select on an multifunction display and there is only one message name to be used. With an input_event you can receive that message and then call this event_select to do something specific based on the value of the original button message.

Similar logic can be achieved with the InputValue property of the input_event class.
When you are not interested in the value carried with the event then use the event_demultiplexer class.
            <[event_select][EventValueSelect][]
                <[string8][Events][ DoSomethingIfValueIs0.Trigger
                                    DoSomethingIfValueIs1.Trigger
                                    DoSomethingIfValueIs2.Trigger ]>
            >

event_range

When the event_range is triggered it checks the value of the event call against the range and triggers either the list of events when inside (EventsIn) or outside (EventsOut) of the range. E.g. a button could generate a message with value 1.0 which is received by an input_event and then the input_event triggers this event_range. Depending on what the button value was the event_range does one thing within a set range but does something different when the value is outside that range.

            <[event_range][StepWhenValueInRange][]
                <[tmvector2d][Range][ -5.0 5.0 ]>
                <[string8][EventsIn][ StepSomething.Trigger ]>
                <[string8][EventsOut][ DEV0.Trigger ]>
            >

Event Functions

The following objects allow for different outcomes of a triggered event. After the execution of a chain of events usually either nothing happens, one or more value are changed or a pulse or timer is triggerd.

DEV0

The do-nothing placeholder is triggered with DEV0.Trigger whenever no action is desired.

            <[event_sound][DEV0][]
            >

Variables

The variable class isn't an event class as such, it cannot trigger any further events. But events can manipulate the value of a variable.

Available functions are:

  • Variable.Set - Changes the value of the variable to the value carried by the event (Value = event_value)
  • Variable.Step - The value is increased or decreased by the value carried by the event (Value += event_value)
  • Variable.Reset - The value is set to 0.0 (Value = 0.0)
Events are not limited to the variable class. Many, in fact almost all of the TMD Inputs can be manipulated in the same way as the variable. E.g. an input_binary can be Set, Reset or Toggled, an input_discrete can be Stepped, Toggled, Set or Reset as well.
            <[variable][Variable][]
                <[string8][Value][0.0]>
            >

The value of the variable is available to other tmd objects as Variable.Output and behaves similar to a constant or input_discrete value.

event_sound

Normally an event_sound object is used to generate a switch or button sound. Using the trigger function (in this case SwitchSound.Trigger) causes the event_sound to briefly output 1.0 to the sound section of the TMD. Then a short sound can be played.

            <[event_sound][SwitchSound][]
            >

event_pulse

When the pulse is triggered (function Pulse.Trigger is called) the pulse outputs (Output) 1.0 for the given Duration in seconds. Re-triggering it just resets the timer back to the duration value. When the time has run out the Output drops back to 0.0.

            <[event_pulse][Pulse][]
                <[float64][Duration][0.5]>
            >

event_timeout

The timeout is an object like a countdown, several things can be fired here: Trigger, Set, Reset, Pause, Unpause to start/stop/reset (like a chronometer), to start (let it run), reset (stop and reset) or pause and unpause the internal timer.

Duration is the count down time.

When the timer has reached zero the list of Events are fired.

The event delay could theoretically restart itself causing a periodic check, but this should be avoided if possible as there are better ways to catch changes in a system state, e.g. the event_edge or to constantly monitor a value, e.g. logic_greater, logic_or, etc. (see TMD Logic).
            <[event_timeout][EventDelay][]
                <[float64][Duration][10.0]>
                <[string8][Events][ DEV0.Trigger ]>
            >

event_repeat

Constantly fires an event as long as the input condition is non-zero. When the input is above zero the EventsUp list is fired and if it is below zero EventsDown is triggered.

Scaling adjusts the value that is carried over to the next events. Lower values reduce the step size for example.

It is not intended to trigger a long chain of events, just to fluidly move an input back and forth like the directional gyro adjustment for example.
            <[event_repeat][DirectionalGyroCorrectionSwitchFunction][]
                <[string8][Input]      [DirectionalGyroCorrectionSwitch.Output]>
                <[string8][InputEnable][DirectionalGyroSlaveModeSwitch.Output]>
                <[string8][EventsUp]   [ DirectionalGyroCorrection.Step ]>
                <[string8][EventsDown] [ DirectionalGyroCorrection.Step ]>
                <[float64][Scaling][0.1]>
            >

event_swap

This can swap two values within the tmd, e.g. two variables or a variable and an input_binary, input_discrete, etc.

The input_pair is optimized for frequency inputs that you can swap back and forth. Use this when you can instead of the event_swap.
            <[event_swap][NAV1ManualFrequencySwap][]
                <[string8][Input0][NAV1ManualFrequency.Output]>
                <[string8][Input1][NAV1FrequencyStandby.Output]>
                <[string8][Event0][NAV1ManualFrequency.Set]>
                <[string8][Event1][NAV1FrequencyStandby.Set]>
            >
aircraft/tmd/events.txt · Last modified: 2022/07/19 21:07 by jh