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.
The configuration for the Registered Function Node is split into three sections.
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_functionwithin 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.
Optionally, you may provide up to 10 input values to pass to the function. For each input, you must declare:
- Argument Type: The data type for the input (
Int32, array of
- 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.
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:
- Argument Type: The data type for the output (
Int32, array of
- 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:
lengthargument, which is the value provided in the output’s “Max Length” property.
result_lengthpointer, 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.
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.
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.
In the above example, and in all the screenshots provided on this page, the Registered Function Node is configured with:
- A Function Name of
Two inputs …
- A 32-bit signed integer (
- An array of unsigned 8-bit integers (
- A 32-bit signed integer (
Two outputs …
- A 16-bit signed integer (
Int16) whose value is placed at the payload path
Stringwith a max length of
128bytes whose value is placed at the payload path
- A 16-bit signed integer (
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
output1_length: u32: This is the “Max Length” argument provided in the node configuration (
128in this case).
output1_result_length: *const u32: This argument is a pointer to the actual length of the value set in the
output1pointer. 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.
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.