Dear Community User! We are updating our platform to a new system.
Read more: Important information on the platform change.

cancel
Showing results for 
Search instead for 
Did you mean: 
SOLVED

Register multiple flatbuffer types in Data Layer

Register multiple flatbuffer types in Data Layer

AlexStepanov
Member

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?

5 REPLIES 5

CodeShepherd
Community Moderator
Community Moderator

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:

  1. Added new schema file "mysampleSchema.fbs:
    // IDL file for sample schema.
    namespace mysample.myschema;
    table InertialValue {    x:short;    y:short;    z:short;    a:short;}
    root_type InertialValue;​
  2. Extended CMakeLists.txt:
    ...
    
    # 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)
  3. Adapted main.cpp:
    ...
    
    #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");  
    
    ...
  4. Run application:
    2021-09-06_13h41_04.png

David08
Long-established Member

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.

CodeShepherd
Community Moderator
Community Moderator

The "xxx_generated.h" file will be generated by Cmake (code: step number 2 in previous post) just by following the build procedure.

  1. Open example in VSC
  2. Choose Cmake build option and wait for configuration to be finished:
    CodeShepherd_0-1631187385015.png
  3. Build your project and the file will appear:
    CodeShepherd_2-1631187535599.png

     


     

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";

 

Thanks for mentioning we will check that and improve our example.

Icon--AD-black-48x48Icon--address-consumer-data-black-48x48Icon--appointment-black-48x48Icon--back-left-black-48x48Icon--calendar-black-48x48Icon--center-alignedIcon--Checkbox-checkIcon--clock-black-48x48Icon--close-black-48x48Icon--compare-black-48x48Icon--confirmation-black-48x48Icon--dealer-details-black-48x48Icon--delete-black-48x48Icon--delivery-black-48x48Icon--down-black-48x48Icon--download-black-48x48Ic-OverlayAlertIcon--externallink-black-48x48Icon-Filledforward-right_adjustedIcon--grid-view-black-48x48IC_gd_Check-Circle170821_Icons_Community170823_Bosch_Icons170823_Bosch_Icons170821_Icons_CommunityIC-logout170821_Icons_Community170825_Bosch_Icons170821_Icons_CommunityIC-shopping-cart2170821_Icons_CommunityIC-upIC_UserIcon--imageIcon--info-i-black-48x48Icon--left-alignedIcon--Less-minimize-black-48x48Icon-FilledIcon--List-Check-grennIcon--List-Check-blackIcon--List-Cross-blackIcon--list-view-mobile-black-48x48Icon--list-view-black-48x48Icon--More-Maximize-black-48x48Icon--my-product-black-48x48Icon--newsletter-black-48x48Icon--payment-black-48x48Icon--print-black-48x48Icon--promotion-black-48x48Icon--registration-black-48x48Icon--Reset-black-48x48Icon--right-alignedshare-circle1Icon--share-black-48x48Icon--shopping-bag-black-48x48Icon-shopping-cartIcon--start-play-black-48x48Icon--store-locator-black-48x48Ic-OverlayAlertIcon--summary-black-48x48tumblrIcon-FilledvineIc-OverlayAlertwhishlist