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:
- Active dynamic/static monitoring based on a generic DDS Participant.
- Passive (non-intrusive) dynamic monitoring using network sniffing techniques.
- Offline network recording dissection.
Engine's monitor outputs & plugins:
- A generic C++, C# and Python APIs for receiving monitored messages in JSON and Map formats via push/poll methods.
- Customized integration to operational monitoring tools (proprietary and open-source).
- Textual reports generation.
- Integration to databases (relational and non-relational).
Engine's message injection:
- A C++, C# and Python APIs for injecting messages via JSON or Map formats.
- Message injection based on a user-provided textual format (e.g. CSV).
DDS XML/IDL Type Files Introspection:
- A simplified C++, C# and Python APIs for extracting detailed information on a selected DDS type's structure.
- 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
- pip install Omnicon-GenericDDSEngine-Py
- Requires: Visual Studio redistributable (https://aka.ms/vs/17/release/vc_redist.x64.exe)
- An Omnnicon license is required to utilize the API. Please Contact Info@OmniconSystems.com.
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
Built Distributions
Hashes for Omnicon_GenericDDSEngine_Py-4.5.5-5-cp37-cp37m-win_amd64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 2ddc49967e77a42ca2cc4f19f87f1f1fc56cb7ba92ab02d76944595638aaa01c |
|
MD5 | 54ed5cf9b2e03c6d540c0a2782db6650 |
|
BLAKE2b-256 | f434b7f9d6c77e469085ff94affdbf7fa0a36e5174002119fa63b9b599217825 |
Hashes for Omnicon_GenericDDSEngine_Py-4.5.5-4-cp37-cp37m-win_amd64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 9e7b8913a2715458c92fcc3c5800836c81f3883431b38a227b90b822e0587576 |
|
MD5 | 5e43c69027c95dcb22e42935162fd351 |
|
BLAKE2b-256 | 133dec3e5ec6dc5cbd0cd21c174fa47ac814d6b03c7145fc8414f75f8873f74a |
Hashes for Omnicon_GenericDDSEngine_Py-4.5.5-3-cp37-cp37m-win_amd64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | a89ec1c9651a83a971509b3a1174c7813347f9b336bc46d4688e093ef6cb737c |
|
MD5 | a8333fe77648e26c0fd72c87d759c3cb |
|
BLAKE2b-256 | cac874a427bb83ce124cb2764652caa2b289652096d9d94a958342b6563b0f5f |
Hashes for Omnicon_GenericDDSEngine_Py-4.5.5-2-cp37-cp37m-win_amd64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 39ead5d04b9a9a70f9a35128fff18ef4058779545385788efb68c9c18abc0efa |
|
MD5 | fe034484c96667b097cd7dca4e0bc179 |
|
BLAKE2b-256 | a2d0ddd83be39f860b8ecef259e914bba11457117c11c2f8aa509cf8abcd1b4b |
Hashes for Omnicon_GenericDDSEngine_Py-4.5.5-1-cp37-cp37m-win_amd64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | dccf85e692a7eb8bc96301c0c2d0b7d4501c768d8b2b4a27fc9fc49c3f6c6c20 |
|
MD5 | d0262f74e699bfed5748afba4e5b2698 |
|
BLAKE2b-256 | 3edd1eaf3412ad0668567ea20ff4a7a67466a37cb523befbe9a6212903b2eda8 |