Union data structure and Python data

7 posts / 0 new
Last post
Offline
Last seen: 6 years 7 months ago
Joined: 02/07/2017
Posts: 14
Union data structure and Python data

Hi, I would like to send and receive data which consists of a union data structure (.xml file).. Could anyone tell me how this would be done in Python using the RticonnextDDS-Connector.. 

using the parameter:......

<member name="parameterValue" nonBasicTypeName="ParameterModule::DATA_T" type="nonBasic"/>

 

here it is here...................................

 

 

-<union name="DATA_T" topLevel="false">

<discriminator nonBasicTypeName="ParameterModule::DDS_UNION_E" type="nonBasic"/>


-<case>

<caseDiscriminator value="(ParameterModule::UNION_BOOL)"/>

<member name="valueBool" type="boolean"/>

</case>

-<case>

<caseDiscriminator value="(ParameterModule::UNION_TEXT)"/>

<member name="valueStr" type="string" stringMaxLength="S3DDSDefaults::NAME_LENGTH"/>

</case>


-<case>

<caseDiscriminator value="(ParameterModule::UNION_UNUSED)"/>

<member name="unused" type="boolean"/>

</case>


-<case>

<caseDiscriminator value="(ParameterModule::UNION_LONG)"/>

<member name="valueLong" type="long"/>

</case>


-<case>

<caseDiscriminator value="(ParameterModule::UNION_DOUBLE)"/>

<member name="valueDbl" type="double"/>

</case>

</union>

 

 

 

-<enum name="DDS_UNION_E">

<enumerator name="UNION_BOOL" value="0"/>

<enumerator name="UNION_TEXT" value="1"/>

<enumerator name="UNION_UNUSED" value="2"/>

<enumerator name="UNION_LONG" value="3"/>

<enumerator name="UNION_DOUBLE" value="4"/>

</enum>

 

 

 

Organization:
gianpiero's picture
Offline
Last seen: 2 months 1 week ago
Joined: 06/02/2010
Posts: 177

Hello,

Let look at this type as an example:

<types>
<union name="AUnion">
<discriminator type="long"/>
<case>
<caseDiscriminator value="1"/>
<member name="sData" id="1" type="short"/>
</case>
<case>
<caseDiscriminator value="2"/>
<member name="lData" id="2" type="long"/>
</case>
</union>
<struct name= "BType">
<member name="y" id="0" type="float"/>
<member name="z" id="1" type="double"/>
<member name="aunion" id="2" type="nonBasic" nonBasicTypeName= "AUnion"/>
</struct>
<struct name= "AType">
<member name="x" id="0" type="long"/>
<member name="color" id="1" type="string"/>
<member name="complex" id="2" type="nonBasic" nonBasicTypeName= "BType"/>
</struct>
</types>

you can just call the api setNumber passing 'complex.aunion.lData'  and the value that you want to assing:

output.instance.setNumber("complex.aunion.lData", 30);

The discriminator will be set automatically for you.

You can access the discriminator (for example, after a read or a take) by using the getString API using as a name complex.aunion#

disc = input.samples.getString(j, "complex.aunion#") 

 

In this example you will get the string 'lData'. Once you know the discriminator you can do the right call to get the value:

lData = input.samples.getNumber(j, "complex.aunion.lData");

 

Best,
   Gianpiero

Offline
Last seen: 6 years 7 months ago
Joined: 02/07/2017
Posts: 14

Hi Gianpiero, many thanks for your reply... I still cannot get the solution to work.. when I use the getString with (#) i get an error 

 

edwards@edwards-VirtualBox /media/sf_shared_drive_VM/Test/examples/python/Monitor $ python monitor_reader.py
DDS_DynamicData_bind_typeI:type not supported (primitive or string not allowed as a top-level type)
DDS_DynamicData_autoBindAndExecuteOperation:invalid operation, bound to member id 3
DDS_DynamicData_autoBindAndExecuteOperation:field valueLong# (id=3) not found
DDS_DynamicData_unbind_complex_member:internal error 1 trying to to stream
DDS_DynamicData_autoBindAndExecuteOperation:internal error trying to DDS_DynamicData_unbind_complex_member
DDS_DynamicData_finalize:WARNING: destructing object bound to a member, automatically unbinding now
DDS_DynamicData_unbind_complex_member:internal error 1 trying to to stream
RTILuaDynamicData_get:!get kind failed for 'parameterValue.valueLong#'
DDS_DynamicData_bind_complex_member:invalid operation, bound to member id 7
DDS_DynamicData_autoBindAndExecuteOperation:invalid operation, bound to member id 4

 

also my xml is slightly different in that when i use the api setNumber i only pass in 

vBool  = output.instance.setBoolean("parameterValue.valueBool", False);

disc = input.samples.getString(j, "parameterValue.valueLong#");

lData= input.samples.getNumber(j, "parameterValue.valueLong");

 

this is the xml here:

 

<module name="ParameterModule">
<enum name="DDS_UNION_E">
<enumerator name="UNION_BOOL" value="0"/>
<enumerator name="UNION_TEXT" value="1"/>
<enumerator name="UNION_UNUSED" value="2"/>
<enumerator name="UNION_LONG" value="3"/>
<enumerator name="UNION_DOUBLE" value="4"/>
</enum>
<enum name="TYPE_E">
<enumerator name="TEMPERATURE" value="0"/>
<enumerator name="FLOW" value="1"/>
<enumerator name="POSITIVE_PRESSURE" value="2"/>
<enumerator name="NEGATIVE_PRESSURE" value="3"/>
<enumerator name="CURRENT" value="4"/>
<enumerator name="VOLTAGE" value="5"/>
<enumerator name="SPEED" value="6"/>
<enumerator name="EDW_BOOL" value="7"/>
<enumerator name="DISTANCE" value="8"/>
<enumerator name="PERCENT" value="9"/>
<enumerator name="NUMBER" value="10"/>
<enumerator name="TEXT" value="11"/>
<enumerator name="DURATION" value="12"/>
<enumerator name="PARAM_UNUSED" value="13"/>
<enumerator name="COUNTER" value="14"/>
</enum>
<union name="DATA_T" topLevel="false">
<discriminator type="nonBasic" nonBasicTypeName="ParameterModule::DDS_UNION_E"/>
<case>
<caseDiscriminator value="(ParameterModule::UNION_BOOL)"/>
<member name="valueBool" id="1" type="boolean"/>
</case>
<case>
<caseDiscriminator value="(ParameterModule::UNION_TEXT)"/>
<member name="valueStr" id="2" stringMaxLength="S3DDSDefaults::NAME_LENGTH" type="string"/>
</case>
<case>
<caseDiscriminator value="(ParameterModule::UNION_UNUSED)"/>
<member name="unused" id="3" type="boolean"/>
</case>
<case>
<caseDiscriminator value="(ParameterModule::UNION_LONG)"/>
<member name="valueLong" id="4" type="long"/>
</case>
<case>
<caseDiscriminator value="(ParameterModule::UNION_DOUBLE)"/>
<member name="valueDbl" id="5" type="double"/>
</case>
</union>
<struct name= "AttributeData" topLevel="false">
<member name="attributeName" stringMaxLength="S3DDSDefaults::SHORT_NAME_LENGTH" type="string"/>
<member name="attributeNameResourceId" type="unsignedLong"/>
<member name="attrType" type="nonBasic" nonBasicTypeName= "ParameterModule::TYPE_E"/>
<member name="value" type="nonBasic" nonBasicTypeName= "ParameterModule::DATA_T"/>
<member name="changed" type="boolean"/>
</struct>
<typedef name="attributeList" sequenceMaxLength="S3DDSDefaults::SEQUENCE_LENGTH" type="nonBasic" nonBasicTypeName= "ParameterModule::AttributeData"/>
<struct name= "DataType">
<member name="time_sec" type="long"/>
<member name="time_usec" type="unsignedLong"/>
<member name="objectId" stringMaxLength="S3DDSDefaults::NAME_LENGTH" type="string" key="true"/>
<member name="parameterName" stringMaxLength="S3DDSDefaults::SHORT_NAME_LENGTH" type="string"/>
<member name="parameterNameResourceId" type="unsignedLong"/>
<member name="parameterType" type="nonBasic" nonBasicTypeName= "ParameterModule::TYPE_E"/>
<member name="parameterValue" type="nonBasic" nonBasicTypeName= "ParameterModule::DATA_T"/>
<member name="attributes" type="nonBasic" nonBasicTypeName= "ParameterModule::attributeList"/>
</struct>

 

best regards,

Nick

 

 

 

 

Offline
Last seen: 6 years 7 months ago
Joined: 02/07/2017
Posts: 14

Hi Gianpiero, 

I've found out the best solution to this which works for me is to use dictionarys.  

to write i set a dictionary then write the dictionary with the values in it i want to set..

dic = dict(parameterType=0, objectId= "testID",
changed=False,
time_sec=10,
time_usec=20,
parameterName="gasflowrate",
parameterNameResourceId=10,
parameterValue=dict(unused=True))

output.instance.setDictionary(dic);
output.write();

then I read the dictionary in its entirity

sample = input.samples.getDictionary(j)

print(sample);

or if i want to access a particular value in the dictionary to do an assert on it i will convert to JSON first

dic = rtiInputFixture.samples.getDictionary(1)
json_dic = json.dumps(dic)
loaded_dic=json.loads(json_dic)

parameterValue=loaded_dic['parameterValue']

 

then do assert parameterValue== testMsg['parameterValue'] 

this gets the result I want.. 

I tried to use the method you suggest but with no luck.. has anyone used this method with success?? 

very best regards,

Nick

gianpiero's picture
Offline
Last seen: 2 months 1 week ago
Joined: 06/02/2010
Posts: 177

Nick,

The method i suggested should work.. i am not sure why is not working with you BUT I am glad you were able to find a solution. 

Thanks,
  Gianpiero

Offline
Last seen: 6 years 7 months ago
Joined: 02/07/2017
Posts: 14

Hi Gianpiero,  thank you very much for your help so far.. we are having some consultation time with your colleague Juanjo.  he was explaining the request reply api to me.. and gave me the C++ code for request reply.  I would like to repeat this in Python now.. I think the part of code I am missing in Python would be this section in C++.. 

 

/* Important: We create a CFT with a filter on the
metadata. In this case, we expect to receive
samples that contain the writer_guid of our writer
in the related_sample_identity. The replier is in
charge of setting that field correctly when
receiving the request. */
DDS_DataWriterQos qos;
Request_writer->get_qos(qos);
std::ostringstream filter_str(std::ostringstream::out);
filter_str << "@related_sample_identity.writer_guid.value" << " = &hex(";
for (int i = 0; i < 16; i++) {
if (qos.protocol.virtual_guid.value[i] < 0x10) {
filter_str << "0";
}
filter_str << std::hex << (int)qos.protocol.virtual_guid.value[i];
}
filter_str << ")";
printf("Using filter: '%s'\n", filter_str.str().c_str());
DDSContentFilteredTopic * reply_cft =
participant->create_contentfilteredtopic(
"Reply CFT Topic", reply_topic,
filter_str.str().c_str(), DDS_StringSeq());
if (reply_cft == NULL) {
printf("create_contentfilteredtopic error\n");
method_shutdown(participant);
return -1;

Have you an idea how I could covert this into Python so that I can use this in my Python request reply app.. ?

would it be easier if I e-mailed you directly possibly? if you supplied your e-mail address.. 

 

many thanks,

Nick

 

 

gianpiero's picture
Offline
Last seen: 2 months 1 week ago
Joined: 06/02/2010
Posts: 177

Hello Nick,

we do not support the Request/Reply API in the Connector right now. Connector is a simplified API, we do not expose api such as get writer qos... you can set content filter in the xml but that's about it. 

We are talking to customers to find out how to best improve connector. I would suggest you write to support or talk to your local rapresentative to bring this need up. 

 

You can always email me directly gianpiero [at] rti.com

Best,
  Gianpiero