Engee documentation

Masks in Engee

Mask — This is a customizable user interface for creating custom blocks. Blocks can be created based on any blocks. Engee libraries and subsystems.

Mask simplifies the use and reuse of blocks. The masked block (with the mask applied) has its own settings window where you can change the block parameters. Masks allow you to transfer parameters not only to the block or subsystem, but also to the source code of the blocks. Engee Function and C Function.

The mask allows you to:

  • Create your own parameters dialog box for quick configuration of the unit/subsystem;

  • Change the appearance of the block/subsystem;

  • Hide the contents of the block/subsystem.

Mask Editor is a tool for customizing masks. To open the editor, right-click on the block and select MaskAdd mask:

masks 1 en

The editor opens in a new browser window:

mask editor 1 en

After saving the mask, the mask parameters are displayed in the block settings. To see the parameters of the block itself, click Look Under Mask. To return, click Look Mask:

masks switching 1 en

For subsystems, the option Look Under Mask it transfers it inside the subsystem, rather than showing the block parameters. Use Navigation panel for models to exit the subsystem.

To edit or delete a mask, right-click on the icon of the block with the mask you have already created and select Edit mask or Remove mask:

masks main 1 en

The mask can be easily adjusted so that when the values of its parameters change, the values of the block parameters automatically change. However, the opposite effect is impossible: the values of the block parameters cannot change the values of the mask parameters. This restriction provides control over the block settings through the mask and prevents accidental changes to the mask itself.

Interface of the mask editor

The mask editor contains two sets of tabs:

  • Interface Editor

  • Code Editor

Interface Editor

Interface Editor — the section for adding masks of controls, structural elements and tabs to the settings window.

mask editor 1 2 en

  1. Actions — controls that are used to perform actions according to specified conditions.

    1. 1.1 Button mask button — a control that performs the specified actions when clicked.

  2. Structure — containers for placing and hiding controls:

    1. 2.1. Hidden section hidden section masks — a container that can be hidden or opened by clicking, allowing you to control the display of several elements simultaneously.

      Hidden section without the added controls, it will not be shown in the mask. The default section can be renamed.
  3. Controls elements — the main components of the interface from which the block mask is formed. Each control has three parameters:

    • Parameter label — must match the name of the variable in the mask that needs to be configured;

    • Label — will be displayed in the settings window;

    • Value or list item — defines the default value.

    In addition to the parameters, you can configure the attributes:

    • Hidden — hides the control;

    • Evaluate — analyzes the entered value, interprets it, and stores the appropriate data type (for example, a number, string, or array). If you enter an incorrect data type, the system will return an error.

  1. 3.1. Text input text input masks — adds a mask parameter with an input text or numeric value. Data type: Any;

  2. 3.2. Checkbox checkbox masks — the area for placing the flag. Data type: Bool;

  3. 3.3. Select dropdown masks — displays a list of available options, from which one is selected. To add items to the drop-down list, enter them one at a time in the List Items field and press Enter after each value. Data type: String;

    The drop-down list without parameters returns an error and does not allow you to save the mask.
  1. Mask space is an area for creating masks using controls and structural elements. All the elements added to the area will be exactly transferred to the mask after saving. To add items, drag them with the mouse.:

    masks drag and drop en

    To delete an item, select it and press Delete.

    To add a new tab, click + in the right corner of the mask space.:

    new tab mask

  2. Save button — saves the mask. Alternatively, you can use keyboard shortcuts. Ctrl+S (Win/Linux) and +S (macOS).

  3. The callback editor button opens the section Code editor.

  4. Hide the left panel/show the left panel.

  5. Hide the right panel/show the right panel.

The code editor

Code editor — control settings section using callback functions (callbacks). Each control element has its own unique callbacks.

mask editor 1 3 en

  1. The names of the mask parameters (you can change them in the interface editor).

  2. Field name — indicates the label or type of the parameter field (you can change it in the interface editor). It provides a more detailed description of the parameter’s purpose or function.

  3. Callback Code space is an area for configuring callbacks for a specific mask parameter.

  4. Save button — saves the mask. Alternatively, you can use keyboard shortcuts. Ctrl+S (Win/Linux) and +S (macOS).

  5. Hide the left panel/show the left panel.

  6. Hide the right panel/show the right panel.

Callbacks

Callbacks are functions that are called automatically in response to certain actions. Callbacks in Engee are written in Julia, are not executed during the simulation and are used to control both individual parameters and the entire mask as a whole. Local callbacks are used to control individual parameters, and global calls are used for the entire mask.:

  • Global callbacks are associated with the entire mask and are performed independently of specific parameters. The global callbacks are iconDrawCallback and blockChangedCallback. Global calls have access to all local calls and can manage them. For example, you can transfer data from a local call to a global one. blockChangedCallback. This will allow you to use a global call to configure the actions of a local one.

  • Local callbacks are linked to specific mask parameters and are triggered only when these parameters are changed. All callbacks except iconDrawCallback and blockChangedCallback, are local. Local callbacks can only work with the parameters they are bound to in the interface editor, and cannot directly change the parameters of other callbacks (Checkbox can’t manage the drop-down list, global callbacks are used for this).

To work with the mask parameter, you first need to get it. For this purpose, a special parameter object is used, which is stored in the 'mask` variable. For example, to get the parameter Text input text input masks with the name `text_input_1', you can use the following code:

mask.parameters.text_input_1

The parameter object has three main properties:

  • name::String — field name (read-only);

  • value::Any — parameter value (available for reading and writing);

  • hidden::Bool — visibility of the parameter (available for reading and writing).

To change a parameter, always assign a new value to the value attribute. You cannot change an existing value directly, as this will not be considered a change. For example:

  • Correct:

    mask.parameters.text_input_1.value = [1, 2, 3]
  • Incorrect:

    append!(mask.parameters.text_input_1.value, 4)

To get the path to the block with the mask, use the function engee.gcb(). The path is returned as a string. This allows you to control the block and its internal components using code. Let’s say you need to pass a value from a parameter Dropdown list dropdown masks (dropdown_1) to the indoor unit LDL Factorization:

LDLPath = engee.gcb() * "/LDL Factorization"
engee.set_param!(LDLPath, "NonPositive" => mask.parameters.dropdown_1.value)

Here engee.gcb() gets the path to the current block. The path is used to find the LDL Factorization block, after which the value from dropdown_1 is passed to the NonPositive parameter of the block. Thus, the engee.gcb() function helps to link the mask parameters to other parts of the model.

Besides engee.gcb() to get the current block, engee.gcm() to get the current model and engee.gcs() to get the current system are also used.

Overview of callbacks

The order of launching mask callbacks:

  1. For each changed parameter, it is called validateCallback. Occurs first to ensure that the parameters have valid values before performing any further operations.;

  2. For each changed parameter, it is called valueChangedCallback. After each callback, it is called validateCallback for each newly changed parameter, as changing the value may affect other parameters.;

  3. It’s starting blockChangedCallback. For each newly changed parameter, it is called validateCallback.

  4. It’s starting iconDrawCallback.

Knowing the order in which callbacks are run is important for the block mask to work correctly, as changing one parameter may affect others. Incorrect order can lead to errors in checking the values or incorrect updating of the icon. Following the correct order ensures that all dependencies are taken into account and the block is working correctly.


iconDrawCallback — formation of the block appearance

Details

To work with iconDrawCallback the `engee.show()' function must be used. The icon with the wrong iconDrawCallback it looks like this:

display callback 5

iconDrawCallback It can display text, a number, a graph, an image, or a formula (LaTeX). For example:

  • Number output (similar for text):

    engee.show(text_input_1)

    display callback 1 endisplay callback 2

  • SVG output:

    engee.show(
        svg"""
        <svg xmlns:ns0="http://www.w3.org/2000/svg" width="78%" height="80%" viewBox="0 0 26 27" fill="none">
            <path vector-effect="non-scaling-stroke" d="M13 0.5L13 25.7282" stroke="#DDDDDD" stroke-linecap="round" />
            <path vector-effect="non-scaling-stroke" d="M0.5 13H25.5" stroke="#DDDDDD" stroke-linecap="round" />
            <path vector-effect="non-scaling-stroke" d="M24.1894 8.46273L13 8.46273L13 17.4628L2.18942 17.4627" stroke="#212121" stroke-linecap="round" />
        </svg>
        """
    )

    custom block 1

    It is recommended to use SVG icons for blocks, as they take up less space and automatically adjust to the block size without loss of quality.
  • The output of the LaTeX formula. To do this, use a capital letter and the quotation marks "". The formula is written in quotation marks according to the classic LaTeX syntax.:

    engee.show(L"\lvert u \rvert")

    custom block 2

  • Graph output:

    x = range(0, 2*pi, 1000);
    y = sin.(x);
    engee.show(plot(x, y))

    display callback 3

  • Image output:

    img = "...base64-text..."
    engee.show(Images.load(IOBuffer(base64decode(img))))

There are different ways to get base64 representations of an image:

  • Via the Julia script:

    image_data = read("path_to_file")
    base64_encoded = base64encode(image_data)
    println(base64_encoded)
  • Through command prompt img 41 1 2 (first, switch to shell mode by pressing ;):

    base64 --wrap 0 "path_to_file"
  • Through external services, for example base64decode.org.

You can change the block’s port signature using the `engee.port_label()' function.`through the callback mechanism. The example below shows how to display text on the block icon and set signatures for different ports.:

engee.show("Some text")                 # Text output on the block icon
engee.port_label("input", 1, "foo_1")    # Signature 'foo_1' for the first input port
engee.port_label("input", 2, "foo_2")    # Signature 'foo_2' for the second input port
engee.port_label("output", 1, "bar")    # The 'bar' signature for the output port

sum mask 1

Signatures can also be set for non-directional ports. You can enter an empty name.:

engee.port_label("acausal", 1, "")      # An empty name for an undirected port

SVG files and LaTeX formulas can be output in the port signatures.:

engee.port_label("input", 1, svg="...")
engee.port_label("input", 1, L="...")

The port numbering is the same as the program control. If you specify an incorrect port number or type, the function will be ignored.

blockChangedCallback — performed after changing any mask parameter

Details

It starts when any mask parameter is changed, but after all other callbacks are executed. Being a global callback, it has access to both variables and the mask object. Examples:

  • Changing a parameter in a subsystem:

    LDLPath = engee.gcb() * "/LDL Factorization"
    
    mode = dropdown_1
    if mode == "Ignore"
        engee.set_param!(LDLPath, "NonPositive" => "Ignore")
    elseif mode == "Warning"
        engee.set_param!(LDLPath, "NonPositive" => "Warning")
    elseif mode == "Error"
        engee.set_param!(LDLPath, "NonPositive" => "Error")
    end

    here, the value of the mask parameter is synchronized with the parameter of the LDL Factorization block. mode' is a variable that stores the current value of the `dropdown_1 parameter. For example, if you change the value of a parameter in the drop-down list from Warning to Error, then the same parameter will similarly change in the LDL Factorization block in the subsystem.

valueChangedCallback — performed when the parameter value is changed

Details

valueChangedCallback it is needed to hide parameters or to change subsystem states using the engee.gcb() function. The callback is triggered when the value of the associated parameter is changed. The parameters are linked if the parameter name of the corresponding control matches the callback code, for example:

valuechangedfcn callback 1 envaluechangedfcn callback 2 Examples:

  • Hiding parameters:

    mask.parameters.text_input_1.hidden = checkbox_1

    here the parameter is hidden when pressed Checkbox and it is visible when Checkbox pressed.

  • Changing the subsystem state (using software control functions):

    if checkbox
        mask.parameters.checkbox.hidden = false
        engee.add_block("/Basic/Ports & Subsystems/Model", engee.gcb() * "/Model")
    else
        mask.parameters.checkbox.hidden = true
        engee.delete_block(engee.gcb() * "/Model")
    end

    the connection is set here with Checkbox (checkbox_1), when enabled (the checkbox is active) which adds the Model block to the subsystem and is deleted when turned off (the checkbox is unchecked).

validateCallback — checks the correctness of the parameter value (validation)

Details

The callback verifies the validity of the value validateCallback and, in case of an incorrect value, it shows an error. All error messages except AssertionError will be considered an error of the callback itself, and not an error of the entered data.:

validatorcallback 1 1 en

The correctness of the parameter value is checked using the value variable. validateCallback it always starts with a macro @assert.

validateCallback available only for the control Text input text input masks and it is attached to his callback. valueChangedCallback. Examples:

  • Checking the correctness of the value:

    @assert value > 0 "The value must be greater than zero"
  • Checking the entered type:

    @assert value isa Number "The value must be a number."

Examples

When using masked blocks (for example, a block 3DOF (Body Axes)) it is important to take into account the interaction of mask parameters and workspace variables:

  1. Some names of mask parameters may overlap with workspace variables. In this case, the value from the mask will take precedence over the variable with the same name from the workspace.

  2. If the model is opened before the parameter variables are defined in the workspace, the mask parameter values can be reset to their default values. However, the subsequent declaration of variables will not automatically update the values in the mask.

  3. The parameters of masked blocks are validated not at the initialization stage of the model, but during manual parameter changes. For example:

    validateCallback
      @assert value isa Number "The value must be a scalar"
      @assert value isa Float64 "The value must be of the Float64 type."

If an unknown variable is used or the parameter contains an invalid value (for example, an undeclared variable or an unsuitable data type), the interface reports an error — the parameter is highlighted in a red box and accompanied by an explanation:

mask debugger 1

example of passing the mask parameter to the source code of the C Function block
  1. Put the C Function block in the Engee workspace. Right-click on the block and select MaskAdd mask.

  2. In the Mask interface editor, add the Input field text input masks.

  3. Go to the mask code editor and select the option in the left options menu Text input (by default, this is text_input_1) and move it to the mask space. Do this twice so that each parameter of the C Function block has its own input field.:

    blockchanged c function 4 en

  4. In the callback blockChangedCallback use the following code:

    # Setting the path to the current block
    CFunctionPath = engee.gcb()
    
    # Getting mask parameter values
    param1 = text_input_1
    param2 = text_input_2
    
    # Generating the C code depending on the parameter values
    c_code = """
    int add_numbers(int param1, int param2) {
        return param1 + param2;
    }
    int result = add_numbers($param1, $param2);
    """
    
    # Setting the "OutputCode" parameter in the C Function block
    engee.set_param!(CFunctionPath, "OutputCode" => c_code)

    blockchanged c function en

    In this code, the path to the current C Function block is set using the engee.gcb() function, after which the values from text_input_1 and text_input_2 are read, which correspond to the parameters of the param1 and param2 blocks. Then a line of C code is created that defines the 'add_numbers` function, which adds two integers, and uses the entered values to calculate the result. Using `engee.set_param! the "OutputCode" parameter of the C Function block is updated, setting the generated code.

  5. Now, when editing the mask parameters, the parameters of the C Function block also change, and their changed values end up in the source code in the OutputCode tab.:

blockchanged c function 1 en

blockchanged c function 3 en

A similar approach is implemented for other tabs of the source code of the C Function block - StartCode and TerminalCode, as well as for the tabs of the Engee Function block — ExeCode and `InhMethodsCode'.

You can use more than just numeric values, for example:

engee.set_param!(engee.gcb(), "OutputCode"=>"print($text_input_1)")

To do this, in the mask interface editor, when creating or editing a parameter, you must specify a value, the data type of which will subsequently change. If the data type does not match, the system will display an error.:

error mask 1 en

It is important to make sure that the "Calculate" checkbox is checked, as this will allow the mask to save the parameter data type after saving.:

mask param save en

example of passing the mask parameter to the source code of the Engee Function block
  1. Assemble the model from blocks Sine Wave, Engee Function and Terminator and turn on recording signal logging 1 The signal is as shown in the figure:

    engee function mask model 1

  2. In the source code of the Engee Function block, add the following code:

    engee function mask model 2 en

    struct Block <: AbstractCausalComponent end
    
    function (c::Block)(t::Real, x)
        return gain .* x
    end
  3. Open the mask editor for the Engee Function block, to do this, click on the block, select MaskAdd mask. In the mask editor, add Text input text input masks, name the Gain parameter and set its value, for example 3:

    engee function mask model 3 en

  4. In the parameters of the Engee Function block, set the value of the gain parameter as shown in the figure:

    engee function mask model 4 en

    This approach allows you to use the value of the mask parameter from the block settings, adding it to the source code and applying the parameter name to get the specified value.:

    engee function mask model 5 en

  5. Let’s test this approach using a graph by running a simulation of the model.:

    engee function mask model 6 en

  6. The value of the gain parameter is indeed 3, which means that the mask works perfectly with the source code of the Engee Function block.

example of a configurable subsystem (the Subsystem block)

Masks can be applied on top of blocks. Subsystem. Let’s consider a case in which it is required to control the parameters of subsystem blocks. For example, the block parameters Sine Wave:

  • By default, the subsystem has no parameters other than Treat as atomic unit:

    without mask 1

    Go to the subsystem and add the Sine Wave block to it.

  • Right-click on the subsystem icon and select MaskAdd mask.

  • In the mask interface editor, add Dropdown list dropdown masks. Add the Sample based and Time based parameters to the list.:

    sine wave mask example 2 en

  • In the Mask code editor, go to the Global tab and in the callback iconDrawCallback add the following code:

    engee.show(dropdown_1)

    This code will display the current value of the dropdown_1 parameter (dropdown list parameter) on the subsystem icon.

  • In the callback blockChangedCallback use the following code:

    SinePath = engee.gcb() * "/Sine Wave"
    
    mode = dropdown_1
    if mode == "Time based"
    engee.set_param!(SinePath, "SineType" => "Time based")
    elseif mode == "Sample based"
    engee.set_param!(SinePath, "SineType" => "Sample based")
    end

    This code changes the SineType parameter of the Sine Wave block in the subsystem depending on the value of the dropdown_1 mask parameter: if Time based is selected, SineType is set ⇒ "Time based", if "Sample based", then "SineType""Sample based".

By changing the value of the Sine type parameter in the masked subsystem, this parameter is automatically changed in the Sine Wave block.

Time based is selected

Sample based is selected

sine wave mask example 1

sine wave mask example 3 1

sine wave mask example 3

sine wave mask example 1 1

example of passing the mask parameter to the Chart block

The mask parameters can be passed to the block Chart. For example, create a model from blocks Constant, Subsystem and To CSV as shown in the picture:

chart mask model 1

Add the Chart block to the subsystem. To connect it to the input (In1) and exit (Out1) subsystems, open the Chart block and create input) and (output ports via settings window debug article icon 1. Also add two local variables:

  • local_input with the value input;

  • local_c with the value c.

These variables will receive values from the subsystem mask.

After that, create condition stateflow state. give it a name and write an expression using local variables, inputs and outputs. Make sure that the names of the variables in the state match those specified in the settings of the Chart block. The result is a finite state machine model with configured inputs, outputs, and variables.:

chart mask model 6 en

Now the model inside the subsystem will look like this:

chart mask model 4

Using masks, create the following Text input text input masks for the Chart block:

chart mask model 5 en

Navigate to the top level of the model using navigation bars and for the Subsystem block, create a mask with the following Text input text input masks:

chart mask model 2 en

Run the model start button. At the end of the simulation in file browser file browser 7 A CSV file will be created showing the results of the time simulation.:

time,1
0.0,22.0
0.01,22.0
0.02,22.0
0.03,22.0
0.04,22.0
0.05,22.0
0.06,22.0
0.07,22.0
0.08,22.0
...
9.96,22.0
9.97,22.0
9.98,22.0
9.99,22.0
10.0,22.0

The result is 22, which confirms the correctness of calculating the expression in the state of the Chart block: local_c = c = 6 (from the Subsystem mask), local_input = input = 15 (from the Chart block mask), their sum is 21, and the Constant block adds another 1, getting the total value of `22'.