Registered Function Node

The Registered Function Node allows for invoking a registered function defined on your Embedded Device from within an execution of an Embedded Workflow.

Registered Function Node

Configuration

The configuration for the Registered Function Node is split into three sections.

Function Name

The only required field within the node configuration is the Function Name – that is, the name of the function to invoke. This function must match the name as it is declared on your device.

The function being invoked must follow these rules:

  • The function must be provided as a WASM import.
  • To avoid naming conflicts, the function is imported with a prefix of eea_fn_, followed by your unique identifier. For example, if you define the function name as my_great_function within the Registered Function Node, the function will be imported as eea_fn_my_great_function). Do not include the eea_fn_ prefix in the node configuration’s function name.
  • The function name is a maximum of 64 characters.
  • The name must contain only uppercase and lowercase letters; numbers; and underscores (_).
  • In the node configuration, the function name is not templatable.

Inputs

Optionally, you may provide up to 10 input values to pass to the function. For each input, you must declare:

Registered Function Node Inputs

  • Argument Type: The data type for the input (Boolean, Int32, array of Int16 values, etc.).
  • Argument Value Template: The value to pass to the registered function. The field is templatable, but the template must resolve to a value matching the Argument Type.

The resolved values of these inputs are then passed to your registered function in the order the arguments are defined within the node.

  • For string input data types, the node will calculate the length of the string in bytes, and pass both a pointer to the string and its byte length as arguments to the registered function.
  • For array input data types, the node will calculate the number of items in the array, and pass both a pointer to the array and its length as arguments to the registered function.

Outputs

You may also optionally define up to 10 outputs that will be populated by your function invocation. Each is passed to your function as a pre-allocated pointer, which must be populated by the code within the registered function. For each output, you must define:

Registered Function Node Outputs

  • Argument Type: The data type for the output (Boolean, Int32, array of Int16 values, etc.).
  • Max Length: If a data type of “String”, “JSON”, or any of the array types is selected, you must also enter the maximum length of the output for proper memory allocation. For array data types, this is the number of items in the array. For “String” and “JSON” types, this is the number of bytes to allocate. The value is not templatable.
  • Destination Payload Path: Where on the payload to place the output value after the function executes.

For JSON, string, and array output data types, each output will also include:

  • A length argument, which is the value provided in the output’s “Max Length” property.
  • A result_length pointer, which the registered function must write the actual length of the value to. For array data types, this is the number of items in the array; for “String” and “JSON” data types, this is the length of the value in bytes.

For JSON output types, the agent will attempt to parse the stringified JSON output into a full JSON object and will place the parsed object at the output’s payload path. If parsing the JSON fails, the node will throw an error and execution will cease.

Return Code

Optionally, you may place the function’s Int32 return code at a path on your payload, which can be used to determine the success or failure of the execution.

Note: If you do not set a payload path for the return code, and the function’s return code is not 0, the workflow will throw an error and execution will stop.

Node Example

Declaring the function on your device varies depending on the language used to compile the WASM bundle. However, the interface does provide an example signature based on the provided function name, inputs, and outputs. For more information, check out the Registered Function API.

Registered Function Node Signature

In the above example, and in all the screenshots provided on this page, the Registered Function Node is configured with:

  • A Function Name of my_great_function
  • Two inputs …

    1. A 32-bit signed integer (Int32).
    2. An array of unsigned 8-bit integers (uInt8 Array).
  • Two outputs …

    1. A 16-bit signed integer (Int16) whose value is placed at the payload path working.numberOut.
    2. A String with a max length of 128 bytes whose value is placed at the payload path working.stringOut.

This results in a function signature of:

fn eea_fn_my_great_function(input0: i32, input1: *const u8, input1_length: u32, output0: *const i16, output1: *const u8, output1_length: u32, output1_result_length: *const u32) -> i32

Breaking this down piece by piece …

  • fn eea_fn_my_great_function(...): This declares a function (fn) with a name of eea_fn_my_great_function. Note that the name matches the “Function Name” provided in the configuration with the eea_fn_ prefix. Inside the parentheses are the arguments provided to the function, each of which is described below.
  • input0: i32: The first declared input is a 32-bit signed integer.
  • input1: *const u8: The second input is a pointer to an array of 8-bit unsigned integers.
  • input1_length: u32: The third argument to the function is the length of the second input, represented as an unsigned 32-bit integer representing, in this case, the number of items in the array that is passed as the second input.
  • output0: *const i16: This argument represents the first output as a pointer to a 16-bit signed integer. Your function must populate this value.
  • output1: *const u8: The second output is represented here as a pointer to an unsigned 8-bit integer, which your function must populate with the string value declared in the Registered Function Node configuration. (Strings are treated here as unsigned 8-bit integers; in other languages, this may be represented as *char.)
  • output1_length: u32: This is the “Max Length” argument provided in the node configuration (128 in this case).
  • output1_result_length: *const u32: This argument is a pointer to the actual length of the value set in the output1 pointer. Your function must set this value as an unsigned 32-bit integer.
  • -> i32: The registered function must return a status code as a signed 32-bit integer, though it is optional as to whether you place that code on your payload. Note the behavior differences around whether a Return Code Path is set (described above) when the registered function returns a non-zero status code.

Node Errors

The most common error arising from the Registered Function Node occurs when the function being invoked by the node is not declared as a WASM import. However, instead of causing the node to error, the entire WASM bundle that includes the workflow utilizing the node – along with any other Embedded Workflows deployed to the device – will fail to load.

Another common error is if a JSON-type output fails to parse the stringified object passed through the output’s pointer into a JSON object. In that case, the node will throw an error and execution will cease.

Was this page helpful?


Still looking for help? You can also search the Losant Forums or submit your question there.