7.2.1. Binary: Blob#

After you have learned a lot about the pre-compiled applications that come with eCAL, let’s create our own! We will see how to create publisher and subscriber applications that send and receive binary data. We will provide samples for all supported programming languages: C++, C, C# and Python.

The most low level publisher and subscriber objects are the binary ones. We will focus on them in this section. As we are just sending an arbitrary “blob” of data (filled with random printable characters), the applications are called “blob sender” and “blob receiver”. For sending structured / typed data, please refer to the following sections.

7.2.1.1. Blob Publisher#

Let’s begin with the publisher side of our “Blob” application.

The base initialization of the eCAL publisher is the same in all languages:

  1. Before you do anything else, you need to initialize eCAL with Initialize(..).

  2. Then you create the publisher and send a message in the frequency you want. In our example we will send the message every 500 ms in an infinite loop. You can add a stop condition to the loop, if you want to send just a limited amount of messages.

  3. After you are done with publishing data and you don’t need eCAL anymore, you can call the Finalize() function to clean up the resources and unregister the process.

For simplicity, we will use the same message type in all languages.

 1// Include the eCAL convenience header
 2#include <ecal/ecal.h>
 3
 4#include <algorithm>
 5#include <iostream>
 6#include <chrono>
 7#include <random>
 8
 9/*
10  Some helper function to generate binary data into a buffer.
11  Clears the vector, resizes it to a specified size and fills it with random printable ascii characters.
12*/
13void fillBinaryBuffer(std::vector<unsigned char>& buffer) { 
14  constexpr unsigned int buffer_size = 16;
15
16  static std::random_device random_device;
17  static std::mt19937 generator(random_device());
18  // Useful random characters are in the range [32, 126]
19  static std::uniform_int_distribution<> printable_ascii_char(32, 126);
20  
21  buffer.clear();
22  buffer.resize(buffer_size);
23
24  for (unsigned int i = 0; i < buffer_size; ++i) {
25    buffer[i] = static_cast<char>(printable_ascii_char(generator));
26  }
27}
28
29int main()
30{
31  std::cout << "-------------------" << "\n";
32  std::cout << " C++: BLOB SENDER"   << "\n";
33  std::cout << "-------------------" << "\n";
34
35  /*
36    Initialize eCAL. You always have to initialize eCAL before using its API.
37    The name of our eCAL Process will be "blob send". 
38    This name will be visible in the eCAL Monitor, once the process is running.
39  */
40  eCAL::Initialize("blob send");
41
42  /*
43    Print some eCAL version information.
44  */
45  std::cout << "eCAL " << eCAL::GetVersionString() << " (" << eCAL::GetVersionDateString() << ")" << "\n";
46
47  /*
48    Set the state for the program.
49    You can vary between different states like healthy, warning, critical ...
50    This can be used to communicate the application state to applications like eCAL Monitor/Sys.
51  */
52  eCAL::Process::SetState(eCAL::Process::eSeverity::healthy, eCAL::Process::eSeverityLevel::level1, "I feel good!");
53
54  /*
55    Now we create a new publisher that will publish the topic "blob".
56  */
57  eCAL::CPublisher pub("blob");
58
59  /*
60    Construct a message. As we are sending binary data, we just create a buffer of unsigned characters.
61  */
62  std::vector<unsigned char> binary_buffer;
63
64  /*
65    Creating an infinite publish-loop.
66    eCAL Supports a stop signal; when an eCAL Process is stopped, eCAL_Ok() will return false.
67  */
68  while (eCAL::Ok())
69  {
70    /*
71      Fill the buffer with the character that is defined by the counter variable.
72    */
73    fillBinaryBuffer(binary_buffer);
74
75    /*
76      Send the message. The message is sent to all subscribers that are currently connected to the topic "blob".
77      For binary data you need to set a buffer pointer and the size of the buffer.
78    */
79    if (pub.Send(binary_buffer.data(), binary_buffer.size()))
80      std::cout << "Sent binary data in C++: " << std::string(binary_buffer.begin(), binary_buffer.end()) << "\n";
81    else
82      std::cout << "Sending binary data in C++ failed!" << "\n";
83
84    /*
85      Sleep for 500ms to send in a frequency of 2 hz.
86    */
87    eCAL::Process::SleepMS(500);
88  }
89
90  /*
91    Finalize eCAL. This will stop all eCAL processes and free all resources.
92    You should always finalize eCAL when you are done using it.
93  */
94  eCAL::Finalize();
95
96  return(0);
97}

├─  C++
│  └─  blob_send.cpp
│
├─  C
│  └─  blob_send.c
│
├─  C#
│  └─  blob_send.cs
│
├─  Python
│  └─  blob_send.py
│
└─  Python (legacy)
   └─  blob_send.py

7.2.1.2. Blob Subscriber#

Now let’s have a look at the subscriber side. Basically, the initialization is the same as for the publisher. Instead of sending data, a callback function is assigned to the subscriber, which will be called every time a new message arrives.

  1. Call Initialize() to initialize eCAL.

  2. Create the subscriber.

  3. Assign a callback function to the subscriber with SetReceiveCallback.

  4. Do something to keep the process alive. In our example we will use a simple infinite loop. Process the incoming messages as you wish.

  5. After you are done with receiving data and you don’t need eCAL anymore, you can call the Finalize() function to clean up the resources and unregister the process.

 1// Include the eCAL convenience header
 2#include <ecal/ecal.h>
 3
 4#include <iostream>
 5#include <sstream>
 6#include <chrono>
 7#include <thread>
 8#include <string>
 9
10/*
11  Here we create the subscriber callback function that is called everytime,
12  when a new message arrived from a publisher.
13*/
14void OnReceive(const eCAL::STopicId& topic_id_, const eCAL::SDataTypeInformation& /*data_type_info_*/, const eCAL::SReceiveCallbackData& data_)
15{
16  if (data_.buffer_size < 1) return;
17  const char* char_buffer = static_cast<const char*>(data_.buffer);
18  
19  std::cout << "------------------------------------------------------------"                  << "\n";
20  std::cout << " Received binary buffer from topic \"" << topic_id_.topic_name << "\" in C++ " << "\n";
21  std::cout << "------------------------------------------------------------"                  << "\n";
22  std::cout << " Size    : " << data_.buffer_size                                              << "\n";
23  std::cout << " Time    : " << data_.send_timestamp                                           << "\n";
24  std::cout << " Clock   : " << data_.send_clock                                               << "\n";
25  std::cout << " Content : " << std::string(char_buffer, data_.buffer_size)                    << "\n";
26  std::cout << "\n";
27}
28
29int main()
30{
31  std::cout << "---------------------" << "\n";
32  std::cout << " C++: BLOB RECEIVER"   << "\n";
33  std::cout << "---------------------" << "\n";
34
35  /*
36    Initialize eCAL. You always have to initialize eCAL before using its API.
37    The name of our eCAL Process will be "blob receive". 
38    This name will be visible in the eCAL Monitor, once the process is running.
39  */
40  eCAL::Initialize("blob receive");
41
42  /*
43    Print some eCAL version information.
44  */
45  std::cout << "eCAL " << eCAL::GetVersionString() << " (" << eCAL::GetVersionDateString() << ")" << "\n";
46
47  /*
48    Set the state for the program.
49    You can vary between different states like healthy, warning, critical ...
50    This can be used to communicate the application state to applications like eCAL Monitor/Sys.
51  */
52  eCAL::Process::SetState(eCAL::Process::eSeverity::healthy, eCAL::Process::eSeverityLevel::level1, "I feel good!");
53
54  /*
55    Creating the eCAL Subscriber. An eCAL Process can create multiple subscribers (and publishers).
56    The topic we are going to receive is called "blob".
57  */
58  eCAL::CSubscriber subscriber("blob");
59
60  /*
61    Register a receive callback. The callback will be called whenever a new message is received.
62  */
63  subscriber.SetReceiveCallback(OnReceive);
64
65  /*
66    Creating an infinite loop.
67    eCAL Supports a stop signal; when an eCAL Process is stopped, eCAL::Ok() will return false.
68  */
69  while (eCAL::Ok())
70  {
71    /*
72      Sleep for 500ms to avoid busy waiting.
73    */
74    std::this_thread::sleep_for(std::chrono::milliseconds(500));
75  }
76
77  /*
78    Finalize eCAL. This will stop all eCAL processes and free all resources.
79    You should always finalize eCAL before exiting your application.
80  */
81  eCAL::Finalize();
82
83  return(0);
84}

├─  C++
│  └─  blob_receive.cpp
│
├─  C
│  └─  blob_receive.c
│
├─  C#
│  └─  blob_receive.cs
│
├─  Python
│  └─  blob_receive.py
│
└─  Python (legacy)
   └─  blob_receive.py