Closed vibnwis closed 3 years ago
For full source code, see attached. Thank you
// Copyright 2017 Proyectos y Sistemas de Mantenimiento SL (eProsima).
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
How to know which kind of Topic has been received?
To know which kind of Topic has been received, we can use the object_id parameter or
the request_id. The id of the object_id corresponds to the DataReader that has read
the Topic, so it can be useful to discretize among different topics.
*/
#include "HelloWorld.h"
#include "msbot_master.h"
#include <uxr/client/client.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <inttypes.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <stdbool.h>
#include <time.h>
#define STREAM_HISTORY 8
#define BUFFER_SIZE UXR_CONFIG_UDP_TRANSPORT_MTU* STREAM_HISTORY
char partname[] = "ABCD";
char localpartname[] = "ABCD-local";
char specifications[] = "5V";
void on_mas_topic(
uxrSession* session,
uxrObjectId object_id,
uint16_t request_id,
uxrStreamId stream_id,
struct ucdrBuffer* ub,
uint16_t length,
void* args)
{
(void) session; (void) object_id; (void) request_id; (void) stream_id; (void) length;
msbot_master topic;
msbot_master_deserialize_topic(ub, &topic);
printf("Received master topic: %s, id: %i\n", topic.message, topic.index);
uint32_t* count_ptr = (uint32_t*) args;
(*count_ptr)++;
}
void on_topic(
uxrSession* session,
uxrObjectId object_id,
uint16_t request_id,
uxrStreamId stream_id,
struct ucdrBuffer* ub,
uint16_t length,
void* args)
{
(void) session; (void) object_id; (void) request_id; (void) stream_id; (void) length;
HelloWorld topic;
HelloWorld_deserialize_topic(ub, &topic);
char key[20];
snprintf(key, 20, "0x%X%X%X%X", session->info.key[0], session->info.key[1], session->info.key[2],
session->info.key[3]);
printf("Session %s: %s (%i)\n", key, topic.message, topic.index);
}
void on_reply(
uxrSession* session,
uxrObjectId object_id,
uint16_t request_id,
uint16_t reply_id,
ucdrBuffer* ub,
uint16_t length,
void* args)
{
(void) object_id;
(void) request_id;
(void) length;
//uint64_t result;
char result[3*32];
ucdr_deserialize_string(ub, result, sizeof(result));
#ifdef WIN32
printf("Reply received: %I64u [id: %d]\n", result, reply_id);
#else
//printf("Reply received: %" PRIu64 " [id: %d]\n", result, reply_id);
printf("Reply received: %s [id: %d]\n", result, reply_id);
#endif /* ifdef WIN32 */
}
int main(
int args,
char** argv)
{
if (3 > args || 0 == atoi(argv[2]))
{
printf("usage: program [-h | --help] | ip port [key]\n");
return 0;
}
char* ip = argv[1];
char* port = argv[2];
uint32_t key = (args == 4) ? (uint32_t)atoi(argv[3]) : 0xAAAABBBB;
// State -- master topic
uint32_t count = 0;
// Transport
uxrUDPTransport transport;
if (!uxr_init_udp_transport(&transport, UXR_IPv4, ip, port))
{
printf("Error at init transport.\n");
return 1;
}
// Session
uxrSession session;
uxr_init_session(&session, &transport.comm, key);
uxr_set_reply_callback(&session, on_reply, false);
uxr_set_topic_callback(&session, on_topic, NULL);
uxr_set_topic_callback(&session, on_mas_topic, &count);
if (!uxr_create_session(&session))
{
printf("Error at init session.\n");
return 1;
}
// Streams
uint8_t output_reliable_stream_buffer[BUFFER_SIZE];
uxrStreamId reliable_out = uxr_create_output_reliable_stream(&session, output_reliable_stream_buffer, BUFFER_SIZE,
STREAM_HISTORY);
uint8_t input_reliable_stream_buffer[BUFFER_SIZE];
uxrStreamId reliable_in = uxr_create_input_reliable_stream(&session, input_reliable_stream_buffer, BUFFER_SIZE,
STREAM_HISTORY);
// Create entities
uxrObjectId participant_id = uxr_object_id(0x01, UXR_PARTICIPANT_ID);
const char* participant_xml = "<dds>"
"<participant>"
"<rtps>"
"<name>default_xrce_participant</name>"
"</rtps>"
"</participant>"
"</dds>";
uint16_t participant_req = uxr_buffer_create_participant_xml(&session, reliable_out, participant_id, 0,
participant_xml, UXR_REPLACE);
uxrObjectId requester_id = uxr_object_id(0x01, UXR_REQUESTER_ID);
const char* requester_xml = "<dds>"
"<requester profile_name=\"my_requester\""
"service_name=\"service_name\""
"request_type=\"request_type\""
"reply_type=\"reply_type\">"
"</requester>"
"</dds>";
uint16_t requester_req = uxr_buffer_create_requester_xml(&session, reliable_out, requester_id, participant_id,
requester_xml, UXR_REPLACE);
//-------- publisher and subscriber --------
//---master topic---
uxrObjectId mas_topic_id = uxr_object_id(0x01, UXR_TOPIC_ID); //master topic
const char* mas_topic_xml = "<dds>"
"<topic>"
"<name>msbot_masterTopic</name>"
"<dataType>msbot_master</dataType>"
"</topic>"
"</dds>";
uint16_t mas_topic_req = uxr_buffer_create_topic_xml(&session, reliable_out, mas_topic_id, participant_id, mas_topic_xml,
UXR_REPLACE);
uxrObjectId mas_subscriber_id = uxr_object_id(0x01, UXR_SUBSCRIBER_ID);
const char* mas_subscriber_xml = "";
uint16_t mas_subscriber_req = uxr_buffer_create_subscriber_xml(&session, reliable_out, mas_subscriber_id, participant_id,
mas_topic_xml, UXR_REPLACE);
uxrObjectId mas_datareader_id = uxr_object_id(0x01, UXR_DATAREADER_ID);
const char* mas_datareader_xml = "<dds>"
"<data_reader>"
"<topic>"
"<kind>NO_KEY</kind>"
"<name>msbot_masterTopic</name>"
"<dataType>msbot_master</dataType>"
"</topic>"
"</data_reader>"
"</dds>";
uint16_t mas_datareader_req = uxr_buffer_create_datareader_xml(&session, reliable_out, mas_datareader_id, mas_subscriber_id,
mas_datareader_xml, UXR_REPLACE);
//---master-topic ---
uxrObjectId topic_id_1_1 = uxr_object_id(0x01, UXR_TOPIC_ID);
const char* topic_xml_1_1 = "<dds>"
"<topic>"
"<name>HelloWorldTopic_1_to_2</name>"
"<dataType>HelloWorld</dataType>"
"</topic>"
"</dds>";
uint16_t topic_req_1_1 = uxr_buffer_create_topic_xml(&session, reliable_out, topic_id_1_1, participant_id,
topic_xml_1_1, UXR_REPLACE);
uxrObjectId topic_id_1_2 = uxr_object_id(0x02, UXR_TOPIC_ID);
const char* topic_xml_1_2 = "<dds>"
"<topic>"
"<name>HelloWorldTopic_3_to_1</name>"
"<dataType>HelloWorld</dataType>"
"</topic>"
"</dds>";
uint16_t topic_req_1_2 = uxr_buffer_create_topic_xml(&session, reliable_out, topic_id_1_2, participant_id,
topic_xml_1_2, UXR_REPLACE);
uxrObjectId publisher_id = uxr_object_id(0x01, UXR_PUBLISHER_ID);
const char* publisher_xml = "";
uint16_t publisher_req = uxr_buffer_create_publisher_xml(&session, reliable_out, publisher_id,
participant_id, publisher_xml, UXR_REPLACE);
uxrObjectId datawriter_id = uxr_object_id(0x01, UXR_DATAWRITER_ID);
const char* datawriter_xml = "<dds>"
"<data_writer>"
"<topic>"
"<kind>NO_KEY</kind>"
"<name>HelloWorldTopic_1_to_2</name>"
"<dataType>HelloWorld</dataType>"
"</topic>"
"</data_writer>"
"</dds>";
uint16_t datawriter_req = uxr_buffer_create_datawriter_xml(&session, reliable_out, datawriter_id,
publisher_id, datawriter_xml, UXR_REPLACE);
uxrObjectId subscriber_id = uxr_object_id(0x01, UXR_SUBSCRIBER_ID);
const char* subscriber_xml = "";
uint16_t subscriber_req = uxr_buffer_create_subscriber_xml(&session, reliable_out, subscriber_id,
participant_id, subscriber_xml, UXR_REPLACE);
uxrObjectId datareader_id = uxr_object_id(0x01, UXR_DATAREADER_ID);
const char* datareader_xml = "<dds>"
"<data_reader>"
"<topic>"
"<kind>NO_KEY</kind>"
"<name>HelloWorldTopic_3_to_1</name>"
"<dataType>HelloWorld</dataType>"
"</topic>"
"</data_reader>"
"</dds>";
uint16_t datareader_req = uxr_buffer_create_datareader_xml(&session, reliable_out, datareader_id,
subscriber_id, datareader_xml, UXR_REPLACE);
//---------- end PnS -------------------
// Send create entities message and wait its status
uint16_t requests[] = {
participant_req, mas_topic_req, mas_subscriber_req, mas_datareader_req, requester_req, topic_req_1_1, topic_req_1_2, publisher_req, datawriter_req, subscriber_req,
datareader_req
};
uint8_t req_status[sizeof(requests) / 2];
if (!uxr_run_session_until_all_status(&session, 1000, requests, req_status, 2))
{
printf("Error at create entities: participant: %i requester: %i\n", req_status[0], req_status[1]);
return 1;
}
// Request replies
uxrDeliveryControl delivery_control = {
0
};
delivery_control.max_samples = UXR_MAX_SAMPLES_UNLIMITED;
uint16_t read_data_req = uxr_buffer_request_data(&session, reliable_out, requester_id, reliable_in,
&delivery_control);
uint16_t read_data_req_topic = uxr_buffer_request_data(&session, reliable_out, datareader_id, reliable_in,
&delivery_control);
uint16_t read_data_req_mas_topic_ = uxr_buffer_request_data(&session, reliable_out, mas_datareader_id, reliable_in,
&delivery_control);
time_t t;
/* Intializes random number generator */
srand((unsigned) time(&t));
// Write requests
bool connected = true;
uint32_t requester_count = 0;
HelloWorld topic;
while (connected)
{
//Update publishing message
sprintf(topic.message, "Publisher A(1) turn-on %d", rand() % 8);
printf("Updated messsage is \"%s\"\n", topic.message);
topic.index = requester_count;
//uint8_t request[32 * 3] = {
char request[32 * 3] = { /* 3 strings of 32 chars long */
0
};
ucdrBuffer ub;
// ucdrBuffer ub_1;
uint32_t topic_size = HelloWorld_size_of_topic(&topic, 0);
uxr_prepare_output_stream(&session, reliable_out, datawriter_id, &ub, topic_size);
HelloWorld_serialize_topic(&ub, &topic);
ucdr_init_buffer(&ub, request, sizeof(request));
// ucdr_serialize_uint32_t(&ub, count);
// ucdr_serialize_uint32_t(&ub, count);
// ucdr_serialize_uint32_t(&ub, &partname);
// ucdr_serialize_uint32_t(&ub, &localpartname);
ucdr_serialize_string(&ub, partname);
ucdr_serialize_string(&ub, localpartname);
uint16_t request_id = uxr_buffer_request(&session, reliable_out, requester_id, request, sizeof(request));
//printf("Request sent: (%d + %d) [id: %d]\n", count, count, request_id);
printf("Request sent: (%s + %s) [id: %d]\n", partname, localpartname, request_id);
connected = uxr_run_session_time(&session, 1000);
++requester_count;
}
return 0;
}
I re-code combining the sample HelloWorld_ and my edited msbotmaster_main.c. The result is somewhat similar, the first code, at higher line works. But as soon as the second publisher begins, the first publisher stops running. Restart the first publisher stops the second publisher. It only allows one publisher at a timer. Please comment. Here is the code.
// Copyright 2017 Proyectos y Sistemas de Mantenimiento SL (eProsima).
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "msbot_master.h"
#include "HelloWorld.h"
#include <uxr/client/client.h>
#include <stdio.h> //printf
#include <string.h> //strcmp
#include <stdlib.h> //atoi
#define STREAM_HISTORY 8
#define BUFFER_SIZE UXR_CONFIG_UDP_TRANSPORT_MTU* STREAM_HISTORY
void on_topic(
uxrSession* session,
uxrObjectId object_id,
uint16_t request_id,
uxrStreamId stream_id,
struct ucdrBuffer* ub,
uint16_t length,
void* args)
{
(void) session; (void) object_id; (void) request_id; (void) stream_id; (void) length;
msbot_master topic;
msbot_master_deserialize_topic(ub, &topic);
printf("Received topic: %s, %s, %s, %s, %s, id: %i\n", topic.message, topic.name, topic.id, topic.dof, topic.make, topic.index);
uint32_t* count_ptr = (uint32_t*) args;
(*count_ptr)++;
}
void on_topic_1(
uxrSession* session,
uxrObjectId object_id,
uint16_t request_id,
uxrStreamId stream_id,
struct ucdrBuffer* ub,
uint16_t length,
void* args)
{
(void) session; (void) object_id; (void) request_id; (void) stream_id; (void) length;
HelloWorld topic;
HelloWorld_deserialize_topic(ub, &topic);
printf("Received topic: %s, id: %i\n", topic.message, topic.index);
uint32_t* count_ptr = (uint32_t*) args;
(*count_ptr)++;
}
int main(
int args,
char** argv)
{
// CLI
if (3 > args || 0 == atoi(argv[2]))
{
printf("usage: program [-h | --help] | ip port [<max_topics>]\n");
return 0;
}
char* ip = argv[1];
char* port = argv[2];
uint32_t max_topics = (args == 4) ? (uint32_t)atoi(argv[3]) : UINT32_MAX;
// State
uint32_t count = 0;
// Transport
uxrUDPTransport transport;
if (!uxr_init_udp_transport(&transport, UXR_IPv4, ip, port))
{
printf("Error at create transport.\n");
return 1;
}
// Session
uxrSession session;
uxr_init_session(&session, &transport.comm, 0xCCCCDDDD);
uxr_set_topic_callback(&session, on_topic, &count);
uxr_set_topic_callback(&session, on_topic_1, &count);
if (!uxr_create_session(&session))
{
printf("Error at create session.\n");
return 1;
}
// Streams
uint8_t output_reliable_stream_buffer[BUFFER_SIZE];
uxrStreamId reliable_out = uxr_create_output_reliable_stream(&session, output_reliable_stream_buffer, BUFFER_SIZE,
STREAM_HISTORY);
uint8_t input_reliable_stream_buffer[BUFFER_SIZE];
uxrStreamId reliable_in = uxr_create_input_reliable_stream(&session, input_reliable_stream_buffer, BUFFER_SIZE,
STREAM_HISTORY);
// Create entities
uxrObjectId participant_id = uxr_object_id(0x01, UXR_PARTICIPANT_ID);
const char* participant_xml = "<dds>"
"<participant>"
"<rtps>"
"<name>default_xrce_participant</name>"
"</rtps>"
"</participant>"
"</dds>";
uint16_t participant_req = uxr_buffer_create_participant_xml(&session, reliable_out, participant_id, 0,
participant_xml, UXR_REPLACE);
uxrObjectId topic_id = uxr_object_id(0x01, UXR_TOPIC_ID);
const char* topic_xml = "<dds>"
"<topic>"
"<name>msbot_masterTopic</name>"
"<dataType>msbot_master</dataType>"
"</topic>"
"</dds>";
uint16_t topic_req = uxr_buffer_create_topic_xml(&session, reliable_out, topic_id, participant_id, topic_xml,
UXR_REPLACE);
uxrObjectId subscriber_id = uxr_object_id(0x01, UXR_SUBSCRIBER_ID);
const char* subscriber_xml = "";
uint16_t subscriber_req = uxr_buffer_create_subscriber_xml(&session, reliable_out, subscriber_id, participant_id,
subscriber_xml, UXR_REPLACE);
uxrObjectId datareader_id = uxr_object_id(0x01, UXR_DATAREADER_ID);
const char* datareader_xml = "<dds>"
"<data_reader>"
"<topic>"
"<kind>NO_KEY</kind>"
"<name>msbot_masterTopic</name>"
"<dataType>msbot_master</dataType>"
"</topic>"
"</data_reader>"
"</dds>";
uint16_t datareader_req = uxr_buffer_create_datareader_xml(&session, reliable_out, datareader_id, subscriber_id,
datareader_xml, UXR_REPLACE);
// Send create entities message and wait its status
uxrObjectId topic_id_1 = uxr_object_id(0x01, UXR_TOPIC_ID);
const char* topic_xml_1 = "<dds>"
"<topic>"
"<name>HelloWorldTopic</name>"
"<dataType>HelloWorld</dataType>"
"</topic>"
"</dds>";
uint16_t topic_req_1 = uxr_buffer_create_topic_xml(&session, reliable_out, topic_id_1, participant_id, topic_xml_1,
UXR_REPLACE);
uxrObjectId subscriber_id_1 = uxr_object_id(0x01, UXR_SUBSCRIBER_ID);
const char* subscriber_xml_1 = "";
uint16_t subscriber_req_1 = uxr_buffer_create_subscriber_xml(&session, reliable_out, subscriber_id_1, participant_id,
subscriber_xml_1, UXR_REPLACE);
uxrObjectId datareader_id_1 = uxr_object_id(0x01, UXR_DATAREADER_ID);
const char* datareader_xml_1 = "<dds>"
"<data_reader>"
"<topic>"
"<kind>NO_KEY</kind>"
"<name>HelloWorldTopic</name>"
"<dataType>HelloWorld</dataType>"
"</topic>"
"</data_reader>"
"</dds>";
uint16_t datareader_req_1 = uxr_buffer_create_datareader_xml(&session, reliable_out, datareader_id_1, subscriber_id_1,
datareader_xml_1, UXR_REPLACE);
// Send create entities message and wait its status
uint8_t status[7];
uint16_t requests[7] = {
participant_req, topic_req, subscriber_req, datareader_req,topic_req_1, subscriber_req_1, datareader_req_1
};
if (!uxr_run_session_until_all_status(&session, 1000, requests, status, 7))
{
printf("Error at create entities: participant: %i topic: %i subscriber: %i datareader: %i\n", status[0],
status[1], status[2], status[3]);
return 1;
}
// Request topics
uxrDeliveryControl delivery_control = {
0
};
delivery_control.max_samples = UXR_MAX_SAMPLES_UNLIMITED;
uint16_t read_data_req = uxr_buffer_request_data(&session, reliable_out, datareader_id, reliable_in,
&delivery_control);
uint16_t read_data_req_1 = uxr_buffer_request_data(&session, reliable_out, datareader_id_1, reliable_in,
&delivery_control);
// Read topics
bool connected = true;
while (connected && count < max_topics)
{
uint8_t read_data_status;
connected = uxr_run_session_until_all_status(&session, UXR_TIMEOUT_INF, &read_data_req, &read_data_status, 1);
connected &= uxr_run_session_until_all_status(&session, UXR_TIMEOUT_INF, &read_data_req_1, &read_data_status, 1);
}
// Delete resources
uxr_delete_session(&session);
uxr_close_udp_transport(&transport);
return 0;
}
To subscribe to two publishers, does it need to have two callbacks? one for each publisher. See the code below, I have on_mas_topic() and on_topic().
No, in the XRCE Client all the subscriptions use the same callback, you can determine to what subscription are they related by using the object_id
argument.
uxr_set_topic_callback(&session, on_topic, &count);
uxr_set_topic_callback(&session, on_topic_1, &count);
The former code is overwriting the callback and you only use on_topic_1
How does the code look like, for uxr_buffer_request_data for subscribing to two topics? see the code below. I have two uxr_buffer_request_data().
It is correct to have a uxr_buffer_request_data
for every subscriber because you are asking the agent to provide data for each one in every independent call to the data request function.
In you main loop:
while (connected && count < max_topics)
{
uint8_t read_data_status;
connected = uxr_run_session_until_all_status(&session, UXR_TIMEOUT_INF, &read_data_req, &read_data_status, 1);
connected &= uxr_run_session_until_all_status(&session, UXR_TIMEOUT_INF, &read_data_req_1, &read_data_status, 1);
}
You are running the session until the data request message has been acknowledged, but I guess that is better to use uxr_run_session_time
or uxr_run_session_timeout
(check here)
Many thanks. That was very useful information. I have read about using object_id to determine the subscription of interest. However, I could not find any examples relating to that. my doubts on the use of object_id, I have no clues of what object_id values of each subscription. Do you any sample code?
the same object id that you create for example here:
uxrObjectId datareader_id_1 = uxr_object_id(0x01, UXR_DATAREADER_ID);
will be passed to the callback when this DataReader receives a topic.
Many thanks. It progresses a bit, but not entirely. Here are the issues.
Very appreciate your comments, please.
uxrObjectId topic_id_1 = uxr_object_id(0x02, UXR_TOPIC_ID);
const char* topic_xml_1 = "
uxrObjectId subscriber_id_1 = uxr_object_id(0x02, UXR_SUBSCRIBER_ID);
const char* subscriber_xml_1 = "";
uint16_t subscriber_req_1 = uxr_buffer_create_subscriber_xml(&session, reliable_out, subscriber_id_1, participant_id,
subscriber_xml_1, UXR_REPLACE);
datareader_id_1 = uxr_object_id(0x02, UXR_DATAREADER_ID);
const char* datareader_xml_1 = "<dds>"
"<data_reader>"
"<topic>"
"<kind>NO_KEY</kind>"
"<name>HelloWorldTopic</name>"
"<dataType>HelloWorld</dataType>"
"</topic>"
"</data_reader>"
"</dds>";
uint16_t datareader_req_1 = uxr_buffer_create_datareader_xml(&session, reliable_out, datareader_id_1, subscriber_id_1,
datareader_xml_1, UXR_REPLACE);
Sorry, I was wrong about issue #2 -- Copy and Paste mistake.
"/* To know which kind of Topic has been received, we can use the object_id parameter or the request_id. The id of the object_id corresponds to the DataReader that has read the Topic, so it can be useful to discretize among different topics."
Out of curiosity, based on the statement above I wonder how request_id is being generated? as a subscriber, how would I know the values for checking them?
About the quitting issue of one publisher when the other publisher is being executed, I wonder what causes it?
Could you share your code? It's a bit difficult to understand your setup...
// Copyright 2017 Proyectos y Sistemas de Mantenimiento SL (eProsima).
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "msbot_master.h"
#include "HelloWorld.h"
#include <uxr/client/client.h>
#include <stdio.h> //printf
#include <string.h> //strcmp
#include <stdlib.h> //atoi
#define STREAM_HISTORY 8
#define BUFFER_SIZE UXR_CONFIG_UDP_TRANSPORT_MTU* STREAM_HISTORY
uxrObjectId datareader_id;
uxrObjectId datareader_id_1;
void on_topic(
uxrSession* session,
uxrObjectId object_id,
uint16_t request_id,
uxrStreamId stream_id,
struct ucdrBuffer* ub,
uint16_t length,
void* args)
{
(void) session; (void) object_id; (void) request_id; (void) stream_id; (void) length;
msbot_master topic;
msbot_master_deserialize_topic(ub, &topic);
if (object_id.id == datareader_id.id) {
printf(" Received MsBOT object_id.id = %d request_id = %d\n", datareader_id.id, request_id);
}
else {
printf(" Received HelloWorld object_id.id = %d request_id = %d\n", datareader_id_1.id, request_id);
}
printf("Received topic: %s, %s, %s, %s, %s, id: %i\n", topic.message, topic.name, topic.id, topic.dof, topic.make, topic.index);
uint32_t* count_ptr = (uint32_t*) args;
(*count_ptr)++;
}
int main(
int args,
char** argv)
{
// CLI
if (3 > args || 0 == atoi(argv[2]))
{
printf("usage: program [-h | --help] | ip port [<max_topics>]\n");
return 0;
}
char* ip = argv[1];
char* port = argv[2];
uint32_t max_topics = (args == 4) ? (uint32_t)atoi(argv[3]) : UINT32_MAX;
// State
uint32_t count = 0;
// Transport
uxrUDPTransport transport;
if (!uxr_init_udp_transport(&transport, UXR_IPv4, ip, port))
{
printf("Error at create transport.\n");
return 1;
}
// Session
uxrSession session;
uxr_init_session(&session, &transport.comm, 0xCCCCDDDD);
uxr_set_topic_callback(&session, on_topic, &count);
if (!uxr_create_session(&session))
{
printf("Error at create session.\n");
return 1;
}
// Streams
uint8_t output_reliable_stream_buffer[BUFFER_SIZE];
uxrStreamId reliable_out = uxr_create_output_reliable_stream(&session, output_reliable_stream_buffer, BUFFER_SIZE,
STREAM_HISTORY);
uint8_t input_reliable_stream_buffer[BUFFER_SIZE];
uxrStreamId reliable_in = uxr_create_input_reliable_stream(&session, input_reliable_stream_buffer, BUFFER_SIZE,
STREAM_HISTORY);
// Create entities
uxrObjectId participant_id = uxr_object_id(0x01, UXR_PARTICIPANT_ID);
const char* participant_xml = "<dds>"
"<participant>"
"<rtps>"
"<name>default_xrce_participant</name>"
"</rtps>"
"</participant>"
"</dds>";
uint16_t participant_req = uxr_buffer_create_participant_xml(&session, reliable_out, participant_id, 0,
participant_xml, UXR_REPLACE);
uxrObjectId topic_id = uxr_object_id(0x01, UXR_TOPIC_ID);
const char* topic_xml = "<dds>"
"<topic>"
"<name>msbot_masterTopic</name>"
"<dataType>msbot_master</dataType>"
"</topic>"
"</dds>";
uint16_t topic_req = uxr_buffer_create_topic_xml(&session, reliable_out, topic_id, participant_id, topic_xml,
UXR_REPLACE);
uxrObjectId subscriber_id = uxr_object_id(0x01, UXR_SUBSCRIBER_ID);
const char* subscriber_xml = "";
uint16_t subscriber_req = uxr_buffer_create_subscriber_xml(&session, reliable_out, subscriber_id, participant_id,
subscriber_xml, UXR_REPLACE);
datareader_id = uxr_object_id(0x01, UXR_DATAREADER_ID);
const char* datareader_xml = "<dds>"
"<data_reader>"
"<topic>"
"<kind>NO_KEY</kind>"
"<name>msbot_masterTopic</name>"
"<dataType>msbot_master</dataType>"
"</topic>"
"</data_reader>"
"</dds>";
uint16_t datareader_req = uxr_buffer_create_datareader_xml(&session, reliable_out, datareader_id, subscriber_id,
datareader_xml, UXR_REPLACE);
// second subscriber
uxrObjectId topic_id_1 = uxr_object_id(0x02, UXR_TOPIC_ID);
const char* topic_xml_1 = "<dds>"
"<topic>"
"<name>HelloWorldTopic</name>"
"<dataType>HelloWorld</dataType>"
"</topic>"
"</dds>";
uint16_t topic_req_1 = uxr_buffer_create_topic_xml(&session, reliable_out, topic_id_1, participant_id, topic_xml_1,
UXR_REPLACE);
uxrObjectId subscriber_id_1 = uxr_object_id(0x02, UXR_SUBSCRIBER_ID);
const char* subscriber_xml_1 = "";
uint16_t subscriber_req_1 = uxr_buffer_create_subscriber_xml(&session, reliable_out, subscriber_id_1, participant_id,
subscriber_xml_1, UXR_REPLACE);
datareader_id_1 = uxr_object_id(0x02, UXR_DATAREADER_ID);
const char* datareader_xml_1 = "<dds>"
"<data_reader>"
"<topic>"
"<kind>NO_KEY</kind>"
"<name>HelloWorldTopic</name>"
"<dataType>HelloWorld</dataType>"
"</topic>"
"</data_reader>"
"</dds>";
uint16_t datareader_req_1 = uxr_buffer_create_datareader_xml(&session, reliable_out, datareader_id_1, subscriber_id_1,
datareader_xml_1, UXR_REPLACE);
// end of second subsriber
// Send create entities message and wait its status
uint8_t status[7];
uint16_t requests[7] = {
participant_req, topic_req, subscriber_req, datareader_req, topic_req_1, subscriber_req_1, datareader_req_1
};
if (!uxr_run_session_until_all_status(&session, 1000, requests, status, 4))
{
printf("Error at create entities: participant: %i topic: %i subscriber: %i datareader: %i\n", status[0],
status[1], status[2], status[3]);
return 1;
}
// Request topics
uxrDeliveryControl delivery_control = {
0
};
delivery_control.max_samples = UXR_MAX_SAMPLES_UNLIMITED;
uint16_t read_data_req = uxr_buffer_request_data(&session, reliable_out, datareader_id, reliable_in,
&delivery_control);
uint16_t read_data_req_1 = uxr_buffer_request_data(&session, reliable_out, datareader_id_1, reliable_in,
&delivery_control);
uint8_t read_data_status;
// Read topics
if (!uxr_run_session_until_all_status(&session, UXR_TIMEOUT_INF, &read_data_req, &read_data_status, 1))
{
printf("Error at create entities: participant: %i topic: %i subscriber: %i datareader: %i\n", status[0],
status[1], status[2], status[3]);
return 1;
}
bool connected = true;
while (connected && count < max_topics)
{
//uint8_t read_data_status;
//connected = uxr_run_session_until_all_status(&session, UXR_TIMEOUT_INF, &read_data_req, &read_data_status, 1);
connected = uxr_run_session_time(&session, 1000);
}
// Delete resources
uxr_delete_session(&session);
uxr_close_udp_transport(&transport);
return 0;
}
HelloWorld_main.c <-- Publisher #1
// Copyright 2017 Proyectos y Sistemas de Mantenimiento SL (eProsima).
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "HelloWorld.h"
#include <uxr/client/client.h>
#include <ucdr/microcdr.h>
#include <stdio.h> //printf
#include <string.h> //strcmp
#include <stdlib.h> //atoi
#define STREAM_HISTORY 8
#define BUFFER_SIZE UXR_CONFIG_UDP_TRANSPORT_MTU* STREAM_HISTORY
int main(
int args,
char** argv)
{
// CLI
if (3 > args || 0 == atoi(argv[2]))
{
printf("usage: program [-h | --help] | ip port [<max_topics>]\n");
return 0;
}
char* ip = argv[1];
char* port = argv[2];
uint32_t max_topics = (args == 4) ? (uint32_t)atoi(argv[3]) : UINT32_MAX;
// Transport
uxrUDPTransport transport;
if (!uxr_init_udp_transport(&transport, UXR_IPv4, ip, port))
{
printf("Error at create transport.\n");
return 1;
}
// Session
uxrSession session;
uxr_init_session(&session, &transport.comm, 0xAAAABBBB);
if (!uxr_create_session(&session))
{
printf("Error at create session.\n");
return 1;
}
// Streams
uint8_t output_reliable_stream_buffer[BUFFER_SIZE];
uxrStreamId reliable_out = uxr_create_output_reliable_stream(&session, output_reliable_stream_buffer, BUFFER_SIZE,
STREAM_HISTORY);
uint8_t input_reliable_stream_buffer[BUFFER_SIZE];
uxr_create_input_reliable_stream(&session, input_reliable_stream_buffer, BUFFER_SIZE, STREAM_HISTORY);
// Create entities
uxrObjectId participant_id = uxr_object_id(0x01, UXR_PARTICIPANT_ID);
const char* participant_xml = "<dds>"
"<participant>"
"<rtps>"
"<name>default_xrce_participant</name>"
"</rtps>"
"</participant>"
"</dds>";
uint16_t participant_req = uxr_buffer_create_participant_xml(&session, reliable_out, participant_id, 0,
participant_xml, UXR_REPLACE);
uxrObjectId topic_id = uxr_object_id(0x01, UXR_TOPIC_ID);
const char* topic_xml = "<dds>"
"<topic>"
"<name>HelloWorldTopic</name>"
"<dataType>HelloWorld</dataType>"
"</topic>"
"</dds>";
uint16_t topic_req = uxr_buffer_create_topic_xml(&session, reliable_out, topic_id, participant_id, topic_xml,
UXR_REPLACE);
uxrObjectId publisher_id = uxr_object_id(0x01, UXR_PUBLISHER_ID);
const char* publisher_xml = "";
uint16_t publisher_req = uxr_buffer_create_publisher_xml(&session, reliable_out, publisher_id, participant_id,
publisher_xml, UXR_REPLACE);
uxrObjectId datawriter_id = uxr_object_id(0x01, UXR_DATAWRITER_ID);
const char* datawriter_xml = "<dds>"
"<data_writer>"
"<topic>"
"<kind>NO_KEY</kind>"
"<name>HelloWorldTopic</name>"
"<dataType>HelloWorld</dataType>"
"</topic>"
"</data_writer>"
"</dds>";
uint16_t datawriter_req = uxr_buffer_create_datawriter_xml(&session, reliable_out, datawriter_id, publisher_id,
datawriter_xml, UXR_REPLACE);
// Send create entities message and wait its status
uint8_t status[4];
uint16_t requests[4] = {
participant_req, topic_req, publisher_req, datawriter_req
};
if (!uxr_run_session_until_all_status(&session, 1000, requests, status, 4))
{
printf("Error at create entities: participant: %i topic: %i publisher: %i datawriter: %i\n", status[0],
status[1], status[2], status[3]);
return 1;
}
// Write topics
bool connected = true;
uint32_t count = 0;
while (connected && count < max_topics)
{
HelloWorld topic = {
++count, "Hello DDS world!"
};
ucdrBuffer ub;
uint32_t topic_size = HelloWorld_size_of_topic(&topic, 0);
uxr_prepare_output_stream(&session, reliable_out, datawriter_id, &ub, topic_size);
HelloWorld_serialize_topic(&ub, &topic);
printf("Send topic: %s, id: %i\n", topic.message, topic.index);
connected = uxr_run_session_time(&session, 1000);
}
// Delete resources
uxr_delete_session(&session);
uxr_close_udp_transport(&transport);
return 0;
}
MsBOT-Master -- Publisher #2
// Copyright 2017 Proyectos y Sistemas de Mantenimiento SL (eProsima).
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "msbot_master.h"
#include <uxr/client/client.h>
#include <ucdr/microcdr.h>
#include <stdio.h> //printf
#include <string.h> //strcmp
#include <stdlib.h> //atoi
#define STREAM_HISTORY 8
#define BUFFER_SIZE UXR_CONFIG_UDP_TRANSPORT_MTU* STREAM_HISTORY
int main(
int args,
char** argv)
{
// CLI
if (3 > args || 0 == atoi(argv[2]))
{
printf("usage: program [-h | --help] | ip port [<max_topics>]\n");
return 0;
}
char* ip = argv[1];
char* port = argv[2];
uint32_t max_topics = (args == 4) ? (uint32_t)atoi(argv[3]) : UINT32_MAX;
// Transport
uxrUDPTransport transport;
if (!uxr_init_udp_transport(&transport, UXR_IPv4, ip, port))
{
printf("Error at create transport.\n");
return 1;
}
// Session
uxrSession session;
uxr_init_session(&session, &transport.comm, 0xAAAABBBB);
if (!uxr_create_session(&session))
{
printf("Error at create session.\n");
return 1;
}
// Streams
uint8_t output_reliable_stream_buffer[BUFFER_SIZE];
uxrStreamId reliable_out = uxr_create_output_reliable_stream(&session, output_reliable_stream_buffer, BUFFER_SIZE,
STREAM_HISTORY);
uint8_t input_reliable_stream_buffer[BUFFER_SIZE];
uxr_create_input_reliable_stream(&session, input_reliable_stream_buffer, BUFFER_SIZE, STREAM_HISTORY);
// Create entities
uxrObjectId participant_id = uxr_object_id(0x01, UXR_PARTICIPANT_ID);
const char* participant_xml = "<dds>"
"<participant>"
"<rtps>"
"<name>default_xrce_participant</name>"
"</rtps>"
"</participant>"
"</dds>";
uint16_t participant_req = uxr_buffer_create_participant_xml(&session, reliable_out, participant_id, 0,
participant_xml, UXR_REPLACE);
uxrObjectId topic_id = uxr_object_id(0x01, UXR_TOPIC_ID);
const char* topic_xml = "<dds>"
"<topic>"
"<name>msbot_masterTopic</name>"
"<dataType>msbot_master</dataType>"
"</topic>"
"</dds>";
uint16_t topic_req = uxr_buffer_create_topic_xml(&session, reliable_out, topic_id, participant_id, topic_xml,
UXR_REPLACE);
uxrObjectId publisher_id = uxr_object_id(0x01, UXR_PUBLISHER_ID);
const char* publisher_xml = "";
uint16_t publisher_req = uxr_buffer_create_publisher_xml(&session, reliable_out, publisher_id, participant_id,
publisher_xml, UXR_REPLACE);
uxrObjectId datawriter_id = uxr_object_id(0x02, UXR_DATAWRITER_ID);
const char* datawriter_xml = "<dds>"
"<data_writer>"
"<topic>"
"<kind>NO_KEY</kind>"
"<name>msbot_masterTopic</name>"
"<dataType>msbot_master</dataType>"
"</topic>"
"</data_writer>"
"</dds>";
uint16_t datawriter_req = uxr_buffer_create_datawriter_xml(&session, reliable_out, datawriter_id, publisher_id,
datawriter_xml, UXR_REPLACE);
// Send create entities message and wait its status
uint8_t status[4];
uint16_t requests[4] = {
participant_req, topic_req, publisher_req, datawriter_req
};
if (!uxr_run_session_until_all_status(&session, 1000, requests, status, 4))
{
printf("Error at create entities: participant: %i topic: %i publisher: %i datawriter: %i\n", status[0],
status[1], status[2], status[3]);
return 1;
}
// Write topics
bool connected = true;
uint32_t count = 0;
while (connected && count < max_topics)
{
msbot_master topic = {
++count, "MSBOT_MASTER", "MSBOT_V1","X100Y100Z100", "8-4-2021","MASSEY_ENGINEERING_DEP"
};
ucdrBuffer ub;
uint32_t topic_size = msbot_master_size_of_topic(&topic, 0);
uxr_prepare_output_stream(&session, reliable_out, datawriter_id, &ub, topic_size);
msbot_master_serialize_topic(&ub, &topic);
printf("Send topic: %s, %s, %s, %s, %s, id: %i\n", topic.message, topic.name, topic.id, topic.dof, topic.make, topic.index);
connected = uxr_run_session_time(&session, 5000);
}
// Delete resources
uxr_delete_session(&session);
uxr_close_udp_transport(&transport);
return 0;
}
For next times, you can upload files to Github comments, and also you can format your code
Share also msbot_master.h and msbot_master.c please
Apologies, still reading the "format your code". Not fully understand that for now. Hence, still uploading them through comment space.
//msbot_master.h
// Copyright 2016 Proyectos y Sistemas de Mantenimiento SL (eProsima).
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*!
* @file msbot_master.h
* This header file contains the declaration of the described types in the IDL file.
*
* This file was generated by the tool gen.
*/
#ifndef _msbot_master_H_
#define _msbot_master_H_
#ifdef __cplusplus
extern "C"
{
#endif
#include <stdint.h>
#include <stdbool.h>
/*!
* @brief This struct represents the structure msbot_master defined by the user in the IDL file.
* @ingroup MSBOT_MASTER
*/
typedef struct msbot_master
{
uint32_t index;
char message[255];
char name[255];
char id[255];
char dof[255];
char make[255];
} msbot_master;
struct ucdrBuffer;
bool msbot_master_serialize_topic(struct ucdrBuffer* writer, const msbot_master* topic);
bool msbot_master_deserialize_topic(struct ucdrBuffer* reader, msbot_master* topic);
uint32_t msbot_master_size_of_topic(const msbot_master* topic, uint32_t size);
#ifdef __cplusplus
}
#endif
#endif // _msbot_master_H_
-----------------------------------------------------------------------------------
// Copyright 2016 Proyectos y Sistemas de Mantenimiento SL (eProsima).
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*!
* @file msbot_master.c
* This source file contains the definition of the described types in the IDL file.
*
* This file was generated by the tool gen.
*/
#include "msbot_master.h"
#include <ucdr/microcdr.h>
#include <string.h>
bool msbot_master_serialize_topic(ucdrBuffer* writer, const msbot_master* topic)
{
(void) ucdr_serialize_uint32_t(writer, topic->index);
(void) ucdr_serialize_string(writer, topic->message);
(void) ucdr_serialize_string(writer, topic->name);
(void) ucdr_serialize_string(writer, topic->id);
(void) ucdr_serialize_string(writer, topic->dof);
(void) ucdr_serialize_string(writer, topic->make);
return !writer->error;
}
bool msbot_master_deserialize_topic(ucdrBuffer* reader, msbot_master* topic)
{
(void) ucdr_deserialize_uint32_t(reader, &topic->index);
(void) ucdr_deserialize_string(reader, topic->message, 255);
(void) ucdr_deserialize_string(reader, topic->name, 255);
(void) ucdr_deserialize_string(reader, topic->id, 255);
(void) ucdr_deserialize_string(reader, topic->dof, 255);
(void) ucdr_deserialize_string(reader, topic->make, 255);
return !reader->error;
}
uint32_t msbot_master_size_of_topic(const msbot_master* topic, uint32_t size)
{
uint32_t previousSize = size;
size += ucdr_alignment(size, 4) + 4;
size += ucdr_alignment(size, 4) + 4 + (uint32_t)strlen(topic->message) + 1;
size += ucdr_alignment(size, 4) + 4 + (uint32_t)strlen(topic->name) + 1;
size += ucdr_alignment(size, 4) + 4 + (uint32_t)strlen(topic->id) + 1;
size += ucdr_alignment(size, 4) + 4 + (uint32_t)strlen(topic->dof) + 1;
size += ucdr_alignment(size, 4) + 4 + (uint32_t)strlen(topic->make) + 1;
return size - previousSize;
}
Ok, I have done some minor changes but the main point of your app is that you are using the same client key for both publishers.
Check the uxr_init_session(&session, &transport.comm, 0xAAAABBBB);
. Every session must have a different key.
Find attached my example: test.zip
Very appreciate that. I tested it as well. They work.
I was wondering if you know how to get the values of request_id? where it can you use with object_id for checking the topic of interest
I don't know if I understand the question...
In the topic callback, the parameter request_id
will be related to the XRCE request that asked for that data in this case it should be one of these two:
uint16_t read_data_req = uxr_buffer_request_data(&session, reliable_out, datareader_id, reliable_in, &delivery_control);
uint16_t read_data_req_1 = uxr_buffer_request_data(&session, reliable_out, datareader_id_1, reliable_in, &delivery_control);
Yes, that is exactly what I question is. Thank you.
On Mon, 19 Apr 2021 at 23:18, Pablo Garrido @.***> wrote:
I don't know if I understand the question...
In the topic callback, the parameter request_id will be related to the XRCE request that asked for that data in this case it should be one of these two:
uint16_t read_data_req = uxr_buffer_request_data(&session, reliable_out, datareader_id, reliable_in, &delivery_control);uint16_t read_data_req_1 = uxr_buffer_request_data(&session, reliable_out, datareader_id_1, reliable_in, &delivery_control);
— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/eProsima/Micro-XRCE-DDS/issues/86#issuecomment-822389724, or unsubscribe https://github.com/notifications/unsubscribe-auth/ADCYQVSOVZEFFDSFK4JQTP3TJQGR5ANCNFSM43EDN2DA .
Ok, closing.
Hi teams,
It would very much appreciate if you share some thoughts about what went wrong here. I have five clients namely Master, Health_inventory, uclient_AA, uclient_BB, and uclient_CC. However, the main issues encountered are, in each uclient_AA, uclient_BB, and uclient_CC, it subscribe to Master and one of the other three uclients. Since each uclient_AA subscribes to two two-topics, I have the code as follow, not the full source. I only show the master-related source. However, they all do not work.
Something I need your clarification are:
Nonetheless, the three uClients do not get any messages from any publishers. Appreciate your comments.
== callback code ==
=====================================================