Skip to main content

Omnicon Generic DDS Engine Python API

Project description

OmniCon GenericDDSEngine PythonAPI

Introduction

OmniCon's Generic DDS Engine is a pluggable software library that provides simple, fully generic monitoring and message injection capabilities for Data Distribution Service (DDS).

Motivation

This project encapsulates DDS-complex API and configuration. It provides a simple, user friendly API to easily incorporate DDS traffic to generic monitoring and visualization tools.

Engine Capabilites

Engine's monitor inputs:

  1. Active dynamic/static monitoring based on a generic DDS Participant.
  2. Passive (non-intrusive) dynamic monitoring using network sniffing techniques.
  3. Offline network recording dissection.

Engine's monitor outputs & plugins:

  1. A generic C++, C# and Python APIs for receiving monitored messages in JSON and Map formats via push/poll methods.
  2. Customized integration to operational monitoring tools (proprietary and open-source).
  3. Textual reports generation.
  4. Integration to databases (relational and non-relational).

Engine's message injection:

  1. A C++, C# and Python APIs for injecting messages via JSON or Map formats.
  2. Message injection based on a user-provided textual format (e.g. CSV).

DDS XML/IDL Type Files Introspection:

  1. A simplified C++, C# and Python APIs for extracting detailed information on a selected DDS type's structure.
  2. Documentation / ICD generator.

DDS Overview

The OMG Data Distribution Service (DDS™) is a middleware protocol and API standard for data-centric connectivity from the Object Management Group® (OMG®). It integrates the components of a system together, providing low-latency data connectivity, extreme reliability, and a scalable architecture that business and mission-critical Internet of Things (IoT) applications need.
For more information refer to https://www.dds-foundation.org/.

Installation

Examples

For full API documentation and examples refer to https://www.OmniconSystems.com

Active Dynamic Monitoring

Demonstrate how to dinamically monitor every topic in a desired DDS domain. The same API applies for Passive monitoring.

from Omnicon_GenericDDSEngine_Py import Omnicon_GenericDDSEngine_Py as omnicon
from time import sleep


class ActiveDynamicMonitorExampleListener(omnicon.EngineListener):

    def OnUserDataJson(self, sampleJson):
        print("OnUserDataJson")
        print(sampleJson)

    def OnDiscoveryDataJson(self, sampleJson):
        print("OnDiscoveryDataJson")
        print(sampleJson)


class ActiveDynamicMonitorExample:
    def __init__(self):
        print(self.run())

    @staticmethod
    def run():
        print("Active Dynamic Monitoring Example")

        # Factory configuration (optional) (can also be performed via an XML configuration)
        factory_configuration = omnicon.FactoryConfiguration()
        factory_configuration.loggerConfiguration.verbosity = omnicon.LogSeverityLevel.trace
        if not omnicon.GenericDDSEngine.SetFactoryConfiguration(factory_configuration):
            print("error setting factory configuration")
            return False

        # Engine configuration (can also be performed via API)
        engine = omnicon.GenericDDSEngine()
        engine_configuration = omnicon.EngineConfiguration()
        engine_configuration.engineOperationMode = omnicon.EngineOperationMode.ACTIVE_DYNAMIC_MONITORING
        engine_configuration.ddsConfigurationFilesPath.append("./EngineConfigurationExamples/ActiveDynamicMonitoring")
        engine_configuration.enableJsonOutput = True

        if not engine.Init(engine_configuration):
            return False

        # Register to engine's callbacks/events
        listener = ActiveDynamicMonitorExampleListener()
        if not engine.BindListener(listener, omnicon.ON_USER_DATA_JSON | omnicon.ON_DISCOVERY_DATA_JSON):
            return False

        if not engine.Run():
           return False

        print("Running Example...")
        input('Press Enter to Exit ')
        sleep(1)
        engine.UnbindListener()
        print("Shutting Down...")

Required Standard DDS configuration files include a basic participant with the DDS types files and DDS domain. For example:

<dds xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <types>
    <enum name="ShapeFillKind">
        <enumerator name="SOLID_FILL"/>
        <enumerator name="TRANSPARENT_FILL"/>
        <enumerator name="HORIZONTAL_HATCH_FILL"/>
        <enumerator name="VERTICAL_HATCH_FILL"/>
    </enum> 
    <struct name= "ShapeType">
        <member name="color" stringMaxLength="128" type="string" key="true"/>
        <member name="x" type="int32"/>
        <member name="y" type="int32"/>
        <member name="shapesize" type="int32"/>
    </struct>
    <struct name= "ShapeTypeExtended" baseType="ShapeType">
        <member name="fillKind" type="nonBasic"  nonBasicTypeName= "ShapeFillKind"/>
        <member name="angle" type="float32"/>
    </struct>
  </types>

  <domain_library name="Domain_Lib">
    <domain name="Domain" domain_id="7"/>
  </domain_library>

  <domain_participant_library name="Participants_Lib">
    <domain_participant name="OmniCon_Engine_Participant" domain_ref="Domain_Lib::Domain">
      <subscriber name="Subscriber"/>
    </domain_participant>
  </domain_participant_library>

</dds>

Message Injection

Demonstrate how to generically inject every DDS Topic using dictionary/json format.

from Omnicon_GenericDDSEngine_Py import Omnicon_GenericDDSEngine_Py as omnicon
from time import sleep


class MessageInjectionExample:
    def __init__(self):
        print(self.run())

    @staticmethod
    def run():
        print("Message Injection Example")

        engine = omnicon.GenericDDSEngine()
        # Engine configuration (can also be performed via xml config file)
        engine_configuration = omnicon.EngineConfiguration()
        engine_configuration.engineOperationMode = omnicon.EngineOperationMode.MESSAGE_INJECTION
        engine_configuration.ddsConfigurationFilesPath.append("./EngineConfigurationExamples/MessageInjection")

        if not engine.Init(engine_configuration):
            return False
        if not engine.Run():
            return False

        # Prevent data races:
        sleep(2)
        print("List of available writers: ")
        for writerInfo in engine.GetWritersInfo():
            print(writerInfo.entityName, "to Topic", writerInfo.topicName)
        print("")

        # Primitive Topic message:
        primitive_topic_input = {
            "SampleData.myLongLong": "-1",
            "SampleData.myUnsignedShort": "0",
            "SampleData.myFloat": "-6789889.3392",
            "SampleData.myDouble": "-6789898989.33999442",
            "SampleData.myBoolean": "0",  # can also use "False"
            "SampleData.myChar": "",
            "SampleData.myWchar": "0",  # wchar is treated as number
            "SampleData.myOctet": "0",
            "SampleData.myShort": "-32768",
            "SampleData.myLong": "-2147483648",
            "SampleData.myUnsignedLong": "0"
        }
        print("Injecting Primitive Topic Message")
        engine.InjectMessage("Publisher::PrimitiveTypeTopic_DW", primitive_topic_input)

        # String Topic Message
        string_topic_input = {
            "SampleData.myBoundedString": "Hello",
            "SampleData.myUnboundedString": "OmniCon",
            "SampleData.myBoundedWString": "!"
        }
        print("Injecting String Topic Message")
        engine.InjectMessage("Publisher::StringsTypeTopic_DW", string_topic_input)

        # Enum Topic Message
        enum_topic_input = {
            "SampleData.mySimpleEnum": "2",
            "SampleData.myDigitsEnum": "-1",
            "SampleData.LetterPrimitiveEnum": "1"
        }
        print("Injecting Enum Topic Message")
        engine.InjectMessage("Publisher::EnumTypeTopic_DW", enum_topic_input)

        # PrimitiveNested Topic Message
        primitive_nested_topic_input = {
            "SampleData.myAliasLongType": "1",
            "SampleData.myFirstType.myChar": "1",
            "SampleData.myFirstType.myWchar": "1",
            "SampleData.myFirstType.myOctet": "1",

            "SampleData.PrimitiveSecondNested.myFloat": "2.5",
            "SampleData.PrimitiveSecondNested.myNestedType.myChar": "z",
            "SampleData.PrimitiveSecondNested.myDouble": "3.14159265359"
        }
        print("Injecting PrimitiveNested Topic Message")
        engine.InjectMessage("Publisher::PrimitiveNestedTypeTopic_DW", primitive_nested_topic_input)

        # Array Topic Message
        array_type_topic_input = {
            "SampleData.myKey": "1",
            "SampleData.AliasCharArray[0]": "1",
            "SampleData.PrimitiveOneDimensionalLiteralSizeArray.boolean_array[0]": "1",
            "SampleData.PrimitiveOneDimensionalLiteralSizeArray.boolean_array[1]": "0",
            "SampleData.PrimitiveOneDimensionalLiteralSizeArray.boolean_array[2]": "1",
            "SampleData.PrimitiveOneDimensionalLiteralSizeArray.short_array[0]": "223",
        }
        print("Injecting ArrayTypeTopic Topic Message")
        engine.InjectMessage("Publisher::ArrayTypeTopic_DW", array_type_topic_input)

        # Sequence Topic Message
        sequence_topic_message = 	{
					  "SampleData": {
						"myKey": "0",
						"myBooleanSeq": [
							"TRUE"
						],
						"myAliasLongUSeq": [],
						"myAliasSeqEnumMember": [
							"(1) - GREEN",
							"(2) - BLUE"
						],
						"myAliasSeqStringMember": [
							"ABC"
						],
						"myPrimitiveSeq": [
							{
								"myChar": "\u0000",
								"myWchar": "0",
								"myOctet": "0",
								"myShort": "2",
								"myUnsignedShort": "0",
								"myLong": "0",
								"myUnsignedLong": "0",
								"myLongLong": "0",
								"myUnsignedLongLong": "0",
								"myFloat": "0",
								"myDouble": "0",
								"myBoolean": "TRUE"
							}
						],
			        }
                }
        print("Injecting SequenceTypeTopic Topic Message")
        engine.InjectMessage("Publisher::SequenceTypeTopic_DW", sequence_topic_message)

        # Union Topic Message
        union_type_topic_input = {
            "SampleData.myKey": "1",
            "SampleData.mySimpleUnion.AliasLong_2_3": "111",
            # "SampleData.PositionError.Error3DMember.sigmaXX": "23",
            "SampleData.PositionError.Error2DMember.sigmaXX": "245"
        }
        print("Injecting UnionTypeTopic Topic Message")
        engine.InjectMessage("Publisher::UnionTypeTopic_DW", union_type_topic_input)

        input("Press Enter to Exit...")
        return True

Required Standard DDS configuration files include a basic participant with the DDS types files and DDS domain. For example:

<dds xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <types>
    <!--User Types-->
    <include file="TypeFiles/ShapeType.xml" />
    <include file="TypeFiles/myIncludedTypesTester.xml" />
    <include file="TypeFiles/myGenericTypesTester.xml" />
  </types>

<!-- Optional -->
  <qos_library name="QOSLibrary">
    <qos_profile name="DefaultProfile" is_default_participant_factory_profile="true" is_default_qos="true" >
      <participant_qos/>
      <datawriter_qos>
        <property>
          <value>
            <!--Required for unbounded types support-->
            <element>
              <name>dds.data_writer.history.memory_manager.fast_pool.pool_buffer_max_size</name>
              <value>4096</value>
            </element>
          </value>
        </property>
      </datawriter_qos>
      <datareader_qos>
        <property>
          <value>
            <!--Required for unbounded types support-->
            <element>
              <name>dds.data_reader.history.memory_manager.fast_pool.pool_buffer_max_size</name>
              <value>4096</value>
            </element>
          </value>
        </property>
      </datareader_qos>
    </qos_profile>
  </qos_library>



  <domain_library name="Domain_Lib">
    <domain name="Domain" domain_id="7">
      <!--Types Definition-->
      <register_type name="ShapeType" type_ref="ShapeType" />
      <register_type name="PrimitiveType" type_ref="PrimitiveType" />
      <register_type name="MyNamespace::StringsType" type_ref="MyNamespace::StringsType" />
      <register_type name="EnumType" type_ref="EnumType" />
      <register_type name="PrimitiveNestedType" type_ref="PrimitiveNestedType" />
      <register_type name="SequenceType" type_ref="SequenceType" />
      <register_type name="UnionType" type_ref="UnionType" />
      <register_type name="ArrayType" type_ref="ArrayType" />

      <!--Topics Definition-->
      <topic name="Square" register_type_ref="ShapeType"/>
      <topic name="PrimitiveTypeTopic" register_type_ref="PrimitiveType" />
      <topic name="StringsTypeTopic" register_type_ref="MyNamespace::StringsType" />
      <topic name="EnumTypeTopic" register_type_ref="EnumType" />
      <topic name="PrimitiveNestedTypeTopic" register_type_ref="PrimitiveNestedType" />
      <topic name="SequenceTypeTopic" register_type_ref="SequenceType" />
      <topic name="UnionTypeTopic" register_type_ref="UnionType" />
      <topic name="ArrayTypeTopic" register_type_ref="ArrayType" />

    </domain>
  </domain_library>
  <domain_participant_library name="Participants_Lib">
    <domain_participant name="OmniCon_Engine_Participant" domain_ref="Domain_Lib::Domain">
      <publisher name="Publisher">
        <data_writer name="PrimitiveTypeTopic_DW" topic_ref="PrimitiveTypeTopic">
          <datawriter_qos base_name="QOSLibrary::DefaultProfile"/>
        </data_writer>
        <data_writer name="StringsTypeTopic_DW" topic_ref="StringsTypeTopic">
          <datawriter_qos base_name="QOSLibrary::DefaultProfile"/>
        </data_writer>
        <data_writer name="EnumTypeTopic_DW" topic_ref="EnumTypeTopic">
          <datawriter_qos base_name="QOSLibrary::DefaultProfile"/>
        </data_writer>
        <data_writer name="PrimitiveNestedTypeTopic_DW" topic_ref="PrimitiveNestedTypeTopic">
          <datawriter_qos base_name="QOSLibrary::DefaultProfile"/>
        </data_writer>
        <data_writer name="ArrayTypeTopic_DW" topic_ref="ArrayTypeTopic">
          <datawriter_qos base_name="QOSLibrary::DefaultProfile"/>
        </data_writer>
        <data_writer name="SequenceTypeTopic_DW" topic_ref="SequenceTypeTopic">
          <datawriter_qos base_name="QOSLibrary::DefaultProfile"/>
        </data_writer>
        <data_writer name="UnionTypeTopic_DW" topic_ref="UnionTypeTopic">
          <datawriter_qos base_name="QOSLibrary::DefaultProfile"/>
        </data_writer>
      </publisher>
    </domain_participant>
  </domain_participant_library>
</dds>

Type Introspection Example

Demonstrate how to extract DDS type infromation for analysis purposes.

from Omnicon_GenericDDSEngine_Py import Omnicon_GenericDDSEngine_Py as omnicon

class TypeIntrospectionExample:
    def __init__(self):
        print(self.run())

    @staticmethod
    def run():
        print("Type Introspection Example")
        factory_configuration = omnicon.FactoryConfiguration()
        factory_configuration.loggerConfiguration.verbosity = omnicon.LogSeverityLevel.trace
        omnicon.GenericDDSEngine.SetFactoryConfiguration(factory_configuration)

        engine = omnicon.GenericDDSEngine()
        # Engine configuration (can also be performed via xml config file)
        engine_configuration = omnicon.EngineConfiguration()
        engine_configuration.engineOperationMode = omnicon.EngineOperationMode.TYPE_INTROSPECTION
        engine_configuration.ddsConfigurationFilesPath.append("./EngineConfigurationExamples/TypeIntrospection/TopicNamesToTypesDefMap.xml")

        if not engine.Init(engine_configuration):
            return False
        if not engine.Run():
            return False

        DDSTopicToTypeXMLMapping = omnicon.GenericDDSEngine.GetTopicNameToTypeNameMap(
            "./EngineConfigurationExamples/TypeIntrospection/TopicNamesToTypesDefMap.xml")
        for topic, type in DDSTopicToTypeXMLMapping.items():
            print(topic + " - " + type)

            dds_type = engine.IntrospectType(type)
            if dds_type is None:
                print(type + " is None")
            for element in dds_type.structure:
                print(element.name)

                if element.typeKindName == "STRUCTURE":
                    print("\tdataTypeName - " + (element).dataTypeName)
                if element.typeKindName == "STRING":
                    print("\tlen - " + str((element).length))
                if element.typeKindName == "ENUMERATION":
                    print("\tENUMERATION")
                if element.typeKindName == "SEQUENCE":
                    print("\tlen - " + str((element).length))

Required Standard DDS configuration files include a basic DDS types/topic XML definition. For example:

<dds xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:noNamespaceSchemaLocation="http://community.rti.com/schema/6.1.0/rti_dds_profiles.xsd"
     version="6.1.0">
  <types>
    <include file="TypeFiles//myIncludedTypesTester.xml"/>
    <include file="TypeFiles//myGenericTypesTester.xml"/>
    <include file="TypeFiles//ShapeType.xml"/>
  </types>

  <domain_library name="Domain_Lib">
    <domain name="Domain">
      <!--Types Definition-->
      <register_type name="ShapeType" type_ref="ShapeTypeExtended" />
      <register_type name="PrimitiveType" type_ref="PrimitiveType" />
      <register_type name="MyNamespace::StringsType" type_ref="MyNamespace::StringsType" />
      <register_type name="EnumType" type_ref="EnumType" />
      <register_type name="PrimitiveNestedType" type_ref="PrimitiveNestedType" />
      <register_type name="SequenceType" type_ref="SequenceType" />
      <register_type name="UnionType" type_ref="UnionType" />
      <register_type name="ArrayType" type_ref="ArrayType" />

      <!--Topics Definition-->
      <topic name="Square" register_type_ref="ShapeType"/>
      <topic name="PrimitiveTypeTopic" register_type_ref="PrimitiveType" />
      <topic name="StringsTypeTopic" register_type_ref="MyNamespace::StringsType" />
      <topic name="EnumTypeTopic" register_type_ref="EnumType" />
      <topic name="PrimitiveNestedTypeTopic" register_type_ref="PrimitiveNestedType" />
      <topic name="SequenceTypeTopic" register_type_ref="SequenceType" />
      <topic name="UnionTypeTopic" register_type_ref="UnionType" />
      <topic name="ArrayTypeTopic" register_type_ref="ArrayType" />
    </domain>
  </domain_library>

</dds>

OmniCon Distributed System LTD All Rights Reserved ©2019-2023

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

Omnicon_GenericDDSEngine_Py-4.5.5-5-cp37-cp37m-win_amd64.whl (4.0 MB view details)

Uploaded CPython 3.7mWindows x86-64

Omnicon_GenericDDSEngine_Py-4.5.5-4-cp37-cp37m-win_amd64.whl (4.0 MB view details)

Uploaded CPython 3.7mWindows x86-64

Omnicon_GenericDDSEngine_Py-4.5.5-3-cp37-cp37m-win_amd64.whl (4.0 MB view details)

Uploaded CPython 3.7mWindows x86-64

Omnicon_GenericDDSEngine_Py-4.5.5-2-cp37-cp37m-win_amd64.whl (4.0 MB view details)

Uploaded CPython 3.7mWindows x86-64

Omnicon_GenericDDSEngine_Py-4.5.5-1-cp37-cp37m-win_amd64.whl (4.0 MB view details)

Uploaded CPython 3.7mWindows x86-64

File details

Details for the file Omnicon_GenericDDSEngine_Py-4.5.5-5-cp37-cp37m-win_amd64.whl.

File metadata

File hashes

Hashes for Omnicon_GenericDDSEngine_Py-4.5.5-5-cp37-cp37m-win_amd64.whl
Algorithm Hash digest
SHA256 2ddc49967e77a42ca2cc4f19f87f1f1fc56cb7ba92ab02d76944595638aaa01c
MD5 54ed5cf9b2e03c6d540c0a2782db6650
BLAKE2b-256 f434b7f9d6c77e469085ff94affdbf7fa0a36e5174002119fa63b9b599217825

See more details on using hashes here.

File details

Details for the file Omnicon_GenericDDSEngine_Py-4.5.5-4-cp37-cp37m-win_amd64.whl.

File metadata

File hashes

Hashes for Omnicon_GenericDDSEngine_Py-4.5.5-4-cp37-cp37m-win_amd64.whl
Algorithm Hash digest
SHA256 9e7b8913a2715458c92fcc3c5800836c81f3883431b38a227b90b822e0587576
MD5 5e43c69027c95dcb22e42935162fd351
BLAKE2b-256 133dec3e5ec6dc5cbd0cd21c174fa47ac814d6b03c7145fc8414f75f8873f74a

See more details on using hashes here.

File details

Details for the file Omnicon_GenericDDSEngine_Py-4.5.5-3-cp37-cp37m-win_amd64.whl.

File metadata

File hashes

Hashes for Omnicon_GenericDDSEngine_Py-4.5.5-3-cp37-cp37m-win_amd64.whl
Algorithm Hash digest
SHA256 a89ec1c9651a83a971509b3a1174c7813347f9b336bc46d4688e093ef6cb737c
MD5 a8333fe77648e26c0fd72c87d759c3cb
BLAKE2b-256 cac874a427bb83ce124cb2764652caa2b289652096d9d94a958342b6563b0f5f

See more details on using hashes here.

File details

Details for the file Omnicon_GenericDDSEngine_Py-4.5.5-2-cp37-cp37m-win_amd64.whl.

File metadata

File hashes

Hashes for Omnicon_GenericDDSEngine_Py-4.5.5-2-cp37-cp37m-win_amd64.whl
Algorithm Hash digest
SHA256 39ead5d04b9a9a70f9a35128fff18ef4058779545385788efb68c9c18abc0efa
MD5 fe034484c96667b097cd7dca4e0bc179
BLAKE2b-256 a2d0ddd83be39f860b8ecef259e914bba11457117c11c2f8aa509cf8abcd1b4b

See more details on using hashes here.

File details

Details for the file Omnicon_GenericDDSEngine_Py-4.5.5-1-cp37-cp37m-win_amd64.whl.

File metadata

File hashes

Hashes for Omnicon_GenericDDSEngine_Py-4.5.5-1-cp37-cp37m-win_amd64.whl
Algorithm Hash digest
SHA256 dccf85e692a7eb8bc96301c0c2d0b7d4501c768d8b2b4a27fc9fc49c3f6c6c20
MD5 d0262f74e699bfed5748afba4e5b2698
BLAKE2b-256 3edd1eaf3412ad0668567ea20ff4a7a67466a37cb523befbe9a6212903b2eda8

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page