Configure Function Block

openDAQ™ provides processing features through Function Blocks. They can process Signals either on a Device or on a host PC where the SDK is running.

The SDK is bundled with a few Function Blocks:

  • Renderer (displays Signal on a desktop window)

  • Statistics (calculates average and RMS from an input Signal)

  • Power (calculates DC power from the input voltage and current Signal)

These Function Blocks serve as an example of what is possible to achieve with openDAQ™ SDK. They are not meant to be used in production code.

The following examples use the Statistics Function Block to show how to configure a Function Block. It is possible to use any other bundled or custom function block. However, Input Ports, output Signals, and properties in code snippets are specific to the Statistics Function Block. Other Function Blocks may have different Input Ports, output Signals, and properties.

Listing properties

Most of the Function Blocks contain some properties which configure the behavior of the Function Block. Since the Function Block inherits from a property object it is possible to get a list of visible properties. Visible properties are those that are expected to be configured from the client code.

  • Cpp

  • Python

  • C#

// List properties of the Function Block
ListPtr<IProperty> functionBlockProperties = functionBlock.getVisibleProperties();
for (const auto& prop : functionBlockProperties)
    std::cout << prop.getName() << std::endl;
# List properties of the Function Block
function_block_properties = function_block.visible_properties
for prop in function_block_properties:
    print(prop.name)
// List properties of the Function Block
IListObject<Property> functionBlockProperties = functionBlock.VisibleProperties;
foreach (var prop in functionBlockProperties)
    Console.WriteLine(prop.Name);

Reading and configuring properties

The Function Block will provide default values for the properties, but they can be set to other values. In the example snippet for the Statistics Function Block we print the current block size and then set it to 100 samples.

  • Cpp

  • Python

  • C#

// Print current block size
Int currentBlockSize = functionBlock.getPropertyValue("BlockSize");
std::cout << "Current block size is " << currentBlockSize << std::endl;
// Configure the properties of the Function Block
functionBlock.setPropertyValue("BlockSize", 100);
# Print current block size
currentBlockSize = function_block.get_property_value("BlockSize")
print("Current block size is %d" % (currentBlockSize))
# Configure the properties of the Function Block
function_block.set_property_value("BlockSize", 100)
// Print current block size
long currentBlockSize = functionBlock.GetPropertyValue("BlockSize");
Console.WriteLine($"Current block size is {currentBlockSize}");
// Configure the properties of the Function Block
functionBlock.SetPropertyValue("BlockSize", 100);

What happens when a property is changed on a function while processing data depends on the implementation of the Function Block. In the case of the Statistics Function Block when the BlockSize property is changed it will reconfigure the domain Signal (new sample rate) of the output Signal and it will continue to produce the Packets.

Connecting Function Block Input Ports

Function Blocks that process data require that their Input Ports connect to Signals. Function Blocks can have a variable number of Input Ports. The Statistics Function Block provides one Input Port that is required to calculate the average value. Once the Input Port is connected, the output Signal will start to produce the data.

  • Cpp

  • Python

  • C#

// Connect the first Signal of the first Channel from the Device to the first Input Port on the Function Block
functionBlock.getInputPorts()[0].connect(device.getChannels()[0].getSignals()[0]);
// Read data from the first Signal of the Function Block
// ...
# Connect the first Signal of the first Channel from the Device to the first Input Port on the Function Block
function_block.input_ports[0].connect(device.channels[0].signals[0])
# Read data from the first Signal of the Function Block
# ...
// Connect the first Signal of the first Channel from the Device to the first Input Port on the Function Block
functionBlock.GetInputPorts()[0].Connect(device.GetChannels()[0].GetSignals()[0]);
// Read data from the first Signal of the Function Block
// ...

Some function blocks may have a variable number of Input Ports. Input Ports can be created or destroyed on a function block when its property is changed or its Input Port is connected or disconnected. The behavior depends on the implementation of the Function Block.

Full listing

The following is a fully working example of configuring and connecting Function Blocks.

The full example code listing
  • Cpp

  • Python

  • C#

#include <opendaq/opendaq.h>
#include <iostream>

using namespace daq;

int main()
{
    // Create an openDAQ(TM) Instance, loading modules from the current directory
    InstancePtr instance = Instance();

    // Add simulated device
    DevicePtr device = instance.addDevice("daqref://device0");

    // Add function block on the host computer
    FunctionBlockPtr functionBlock = instance.addFunctionBlock("RefFBModuleStatistics");

    // List properties of the Function Block
    ListPtr<IProperty> functionBlockProperties = functionBlock.getVisibleProperties();
    for (const auto& prop : functionBlockProperties)
        std::cout << prop.getName() << std::endl;

    // Print current block size
    Int currentBlockSize = functionBlock.getPropertyValue("BlockSize");
    std::cout << "Current block size is " << currentBlockSize << std::endl;
    // Configure the properties of the Function Block
    functionBlock.setPropertyValue("BlockSize", 100);

    // Connect the first Signal of the first Channel from the Device to the first Input Port on the Function Block
    functionBlock.getInputPorts()[0].connect(device.getChannels()[0].getSignals()[0]);
    // Read data from the first Signal of the Function Block
    // ...

    // Get the output Signal of the Function Block
    SignalPtr outputSignal = functionBlock.getSignals()[0];

    std::cout << outputSignal.getDescriptor().getName() << std::endl;

    return 0;
}
import opendaq

# Create an openDAQ(TM) Instance, loading modules from the current directory
instance = opendaq.Instance()

# Add simulated device
device = instance.add_device('daqref://device0')

# Add Function Block on the host computer
function_block = instance.add_function_block("RefFBModuleStatistics")

# List properties of the Function Block
function_block_properties = function_block.visible_properties
for prop in function_block_properties:
    print(prop.name)

# Print current block size
currentBlockSize = function_block.get_property_value("BlockSize")
print("Current block size is %d" % (currentBlockSize))
# Configure the properties of the Function Block
function_block.set_property_value("BlockSize", 100)

# Connect the first Signal of the first Channel from the Device to the first Input Port on the Function Block
function_block.input_ports[0].connect(device.channels[0].signals[0])
# Read data from the first Signal of the Function Block
# ...

# Get the output Signal of the Function Block
output_signal = function_block.signals[0]

print(output_signal.descriptor.name)
using Daq.Core.Types;
using Daq.Core.Objects;
using Daq.Core.OpenDAQ;

// Create an openDAQ(TM) Instance, loading modules from the current directory
Instance instance = OpenDAQFactory.Instance(MODULE_PATH);

// Add simulated device
Device device = instance.AddDevice("daqref://device0");

// Add Function Block on the host computer
FunctionBlock functionBlock = instance.AddFunctionBlock("RefFBModuleStatistics");

// List properties of the Function Block
IListObject<Property> functionBlockProperties = functionBlock.VisibleProperties;
foreach (var prop in functionBlockProperties)
    Console.WriteLine(prop.Name);

// Print current block size
long currentBlockSize = functionBlock.GetPropertyValue("BlockSize");
Console.WriteLine($"Current block size is {currentBlockSize}");
// Configure the properties of the Function Block
functionBlock.SetPropertyValue("BlockSize", 100);

// Connect the first Signal of the first Channel from the Device to the first Input Port on the Function Block
functionBlock.GetInputPorts()[0].Connect(device.GetChannels()[0].GetSignals()[0]);
// Read data from the first Signal of the Function Block
// ...

// Get the output Signal of the Function Block
Signal outputSignal = functionBlock.GetSignals()[0];

Console.WriteLine(outputSignal.Descriptor.Name);