FORUM CTRLX AUTOMATION
ctrlX World Partner Apps for ctrlX AUTOMATION
08-03-2021 09:50 AM - edited 08-03-2021 10:35 AM
I want to use multiple different flatbuffers in my application, but I can't register more than one flatbuffer as a type in the data layer.
I extended the datalayer.register.node example to include a second flatbuffer (called sampleScheme2.fbs). Now when I start the application, I always see that registerType fails with the message "DL_INVALID_VALUE" for the second flatbuffer.
If I call registerType for sampleScheme2.fbs first, than sampleScheme.fbs returns "DL_INVALID_VALUE" when calling registerType.
Registering the nodes works without any problems.
Do I have to create a new data layer provider for each flatbuffer?
Solved! Go to Solution.
09-06-2021 01:53 PM - edited 11-22-2021 09:04 AM
Sorry for the late reply.
Of course it is possible to register several flatbuffers in one app. I adapted the registernode example of the SDK for ctrlx AUTOMATION in version 1.10:
// IDL file for sample schema.
namespace mysample.myschema;
table InertialValue { x:short; y:short; z:short; a:short;}
root_type InertialValue;
...
# Flatbuffers
set (FLATBUFFERS_FLATC_EXECUTABLE ${USER_DEPENDENCY_DIR}/bin/oss.flatbuffers/linux-gcc-x64/release/flatc)
set (FLATBUFFERS_INCLUDE_DIR ${USER_DEPENDENCY_DIR}/include/oss.flatbuffers/oss.flatbuffers)
include (${USER_DEPENDENCY_DIR}/cmake/oss.flatbuffers/FindFlatBuffers.cmake)
set( FLATBUFFERS_FLATC_SCHEMA_EXTRA_ARGS "--gen-object-api")
build_flatbuffers("sampleSchema.fbs" "" "registernodeflatbuffers" "${CMAKE_CURRENT_LIST_DIR}" "${CMAKE_CURRENT_LIST_DIR}" "${CMAKE_CURRENT_LIST_DIR}/bfbs" "")
build_flatbuffers("mysampleSchema.fbs" "" "myregisternodeflatbuffers" "${CMAKE_CURRENT_LIST_DIR}" "${CMAKE_CURRENT_LIST_DIR}" "${CMAKE_CURRENT_LIST_DIR}/bfbs" "")
...
# Define Executables to add from project files and their depending source files
add_executable( ${TARGET_PROJECT_NAME} ${SOURCE_FILES_REGISTERNODE} )
add_dependencies(${TARGET_PROJECT_NAME} registernodeflatbuffers)
add_dependencies(${TARGET_PROJECT_NAME} myregisternodeflatbuffers)
...
#include "sampleSchema_generated.h"
#include "mysampleSchema_generated.h"
...
// Read function of metadata of an object. Function will be called whenever a node should be written.
virtual void onMetadata(const std::string &address, const comm::datalayer::IProviderNode::ResponseCallback &callback) override {
flatbuffers::FlatBufferBuilder builder;
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<comm::datalayer::Reference>>> references;
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<comm::datalayer::Reference>>> references2;
auto emptyString = builder.CreateString("This is a Description");
if (address.compare("myData/myFlatbuffer") == 0) {
flatbuffers::Offset<comm::datalayer::Reference> vecReferences[] = {
comm::datalayer::CreateReferenceDirect(builder, "readType", "types/sampleSchema/inertialValue"), };
references = builder.CreateVectorOfSortedTables(vecReferences, 1); }
else if (address.compare("myData/myFlatbuffer2") == 0) {
flatbuffers::Offset<comm::datalayer::Reference> vecReferences[] = {
comm::datalayer::CreateReferenceDirect(builder, "readType", "types/mysampleSchema/inertialValue"), };
references2 = builder.CreateVectorOfSortedTables(vecReferences, 1); }
// Set allowed operations
comm::datalayer::AllowedOperationsBuilder allowedOperations(builder);
allowedOperations.add_read(true);
allowedOperations.add_write(false);
allowedOperations.add_create(true);
allowedOperations.add_delete_(false);
auto operations = allowedOperations.Finish();
// Create metadata
comm::datalayer::MetadataBuilder metadata(builder);
metadata.add_description(emptyString);
metadata.add_descriptionUrl(emptyString);
metadata.add_operations(operations);
if (address.compare("myData/myFlatbuffer") == 0) {
metadata.add_references(references); }
else if (address.compare("myData/myFlatbuffer2") == 0) {
metadata.add_references(references2); }
auto metaFinished = metadata.Finish();
builder.Finish(metaFinished);
...
// Create dummy flatbuffer data
flatbuffers::FlatBufferBuilder builder2;
auto actInertialValue2 = mysample::myschema::CreateInertialValue(builder2, 33, -427, 911, 42);
builder2.Finish(actInertialValue2);
comm::datalayer::Variant myFlatbuffer2;
myFlatbuffer2.shareFlatbuffers(builder2);
// Register type of flatbuffer value
// If running on SNAP environment, use $SNAP environment variable for register the bfbs
std::string bfbsPath2 = getenv("SNAP") != nullptr ? getenv("SNAP") : "bfbs";
bfbsPath2 += "/sampleSchema.bfbs";
std::cout << bfbsPath2 << std::endl;
result = myProvider->registerType("types/mysampleSchema/inertialValue", bfbsPath2);
if(STATUS_FAILED(result)) {
std::cout << "Register type 'types/mysampleSchema/inertialValue' failed with: " << result.toString() << std::endl; }
else {
std::cout << "Register type 'types/mysampleSchema/inertialValue' was successful!" << std::endl; }
// Register a node as flatbuffer value
result = myProvider->registerNode("myData/myFlatbuffer2", new MyProviderNode(myFlatbuffer2));
if(STATUS_FAILED(result)) {
std::cout << "Register node 'myData/myFlatbuffer2' failed with: " << result.toString() << std::endl; }
else {
std::cout << "Register node 'myData/myFlatbuffer2' was successful!" << std::endl; }
...
// Unregister type and nodes
myProvider->unregisterType("types/sampleSchema/inertialValue");
myProvider->unregisterType("types/mysampleSchema/inertialValue");
...
09-09-2021 12:07 PM
Hello,
I am interested in making a very similar application to be able to send data to the PLC by Rest API in a single JSON file.
I've started to test the ResgisterNode example but VSCode is giving me an error because it can't find the "SampleSchema_generated.h" library.
How can I fix it, I have no experience with VSCode.
I'm using SDK 1.10 in a virtual machine with Ubuntu 18
Thanks in advance.
09-09-2021 01:39 PM
The "xxx_generated.h" file will be generated by Cmake (code: step number 2 in previous post) just by following the build procedure.
10-13-2021 11:04 AM
I still had problems, but I finally found the error!
strcat shouldn't be used with getenv, because the first arguments gets modified. See std::strcat - cppreference.com
Modifying the lines to something like this resolves the issues when running the app in a snap package:
std::string bfbsPath = getenv("SNAP") != nullptr ? getenv("SNAP") : "bfbs";
bfbsPath += "/sampleSchema.bfbs")
...
std::string bfbsPath2 = getenv("SNAP") != nullptr ? getenv("SNAP") : "bfbs";
bfbsPath2 += "/sampleSchema.bfbs";
11-22-2021 07:57 AM
Thanks for mentioning we will check that and improve our example.