RTC Toolkit 6.0.0
Loading...
Searching...
No Matches
shmSubscriber.hpp
Go to the documentation of this file.
1
11#ifndef RTCTK_STANDALONETOOLS_SHMSUBSCRIBER_H
12#define RTCTK_STANDALONETOOLS_SHMSUBSCRIBER_H
13
14#include <boost/io/ios_state.hpp>
15#include <cassert>
16#include <deque>
17#include <iomanip>
18#include <iostream>
19#include <ipcq/adapter.hpp>
20#include <ipcq/reader.hpp>
21#include <limits>
22#include <memory>
23#include <string>
24
25namespace rtctk::standaloneTools {
26
34public:
35 ShmSubscriberBase() = default;
36 // Do not allow copying or moving of this object.
41
42 virtual ~ShmSubscriberBase() = default;
43 int Run(int argc, char* argv[]);
44
45protected:
53 virtual void Initialise() = 0;
54
60 virtual void Finalise() = 0;
61
75 virtual bool ReadSample() = 0;
76
83 virtual void PrintSample() = 0;
84
88 virtual const void* GetSampleData() const = 0;
89
93 virtual size_t GetSampleSize() const = 0;
94
98 inline const std::string& GetQueueName() const {
99 return m_queue_name;
100 }
101
106 inline const std::string& GetFilename() const {
107 return m_filename;
108 }
109
113 inline const int64_t GetSampleNumber() const {
114 return m_sample_counter;
115 }
116
121 inline const int64_t PrintWihtLongFormat() const {
122 return m_print_long;
123 }
124
125private:
126 bool ParseArguments(int argc, char* argv[]);
127 void WriteBufferToFile(const void* buffer, size_t size);
128 bool TerminateProcess();
129
130 std::string m_queue_name;
131 std::string m_filename;
132 int64_t m_max_samples = 0;
133 int64_t m_skip_samples = 0;
134 bool m_print_samples = false;
135 bool m_print_long = false;
136 int64_t m_sample_counter = 0;
137};
138
149template <typename Topic,
150 class ConditionPolicy = ipcq::BoostConditionPolicy,
151 class ShmTraits = ipcq::detail::BoostInterprocessTraits>
153public:
154 ShmSubscriber() = default;
155 ~ShmSubscriber() override = default;
156 // Do not allow copying or moving of this object.
157 ShmSubscriber(const ShmSubscriber& rhs) = delete;
158 ShmSubscriber& operator=(const ShmSubscriber& rhs) = delete;
159 ShmSubscriber(ShmSubscriber&& rhs) noexcept = default;
160 ShmSubscriber& operator=(ShmSubscriber&& rhs) noexcept = default;
161
162protected:
173 virtual void PrintSample(const Topic& sample) {
174 boost::io::ios_flags_saver saved_state(std::cout);
175 std::cout << "Sample " << GetSampleNumber() << ":\n";
176 auto buffer = reinterpret_cast<const uint8_t*>(&sample);
177 size_t max_bytes_to_print = 64;
178 if (PrintWihtLongFormat()) {
179 max_bytes_to_print = std::numeric_limits<size_t>::max();
180 }
181 bool last_was_endl = false;
182 for (size_t n = 0; n < sizeof(Topic) and n < max_bytes_to_print; ++n) {
183 std::cout << "0x" << std::setfill('0') << std::setw(2) << std::right << std::noshowbase
184 << std::hex << static_cast<unsigned int>(buffer[n]);
185 if ((n + 1) % 16 == 0) {
186 std::cout << "\n";
187 last_was_endl = true;
188 } else {
189 std::cout << " ";
190 last_was_endl = false;
191 }
192 }
193 if (not last_was_endl) {
194 std::cout << "\n";
195 }
196 if (sizeof(Topic) > max_bytes_to_print) {
197 std::cout << "... (data continues) ...\n";
198 }
199 }
200
201private:
202 using Reader = ipcq::BasicReader<Topic, ConditionPolicy, ShmTraits>;
203
207 void Initialise() override {
208 try {
209 m_reader = std::make_unique<Reader>(GetQueueName().c_str());
210 } catch (const std::exception& error) {
211 std::string msg = "Failed to create the shared memory reader for queue '" +
212 GetQueueName() + "': " + error.what();
213 throw std::runtime_error(msg);
214 }
215 }
216
220 void Finalise() override {
221 try {
222 m_reader.reset(nullptr);
223 } catch (const std::exception& error) {
224 std::string msg = "Failed to destroy the shared memory reader for queue '" +
225 GetQueueName() + "': " + error.what();
226 throw std::runtime_error(msg);
227 }
228 m_samples.clear();
229 }
230
238 bool ReadSample() override {
239 if (not m_samples.empty()) {
240 m_samples.pop_front();
241 }
242 if (not m_samples.empty()) {
243 return true;
244 }
245 using namespace std::chrono_literals;
246 auto count = m_reader->NumAvailable();
247 auto [error, num_elements] = m_reader->Read(ipcq::BackInserter(m_samples), count, 100ms);
248 if (error) {
249 if (error == ipcq::make_error_code(ipcq::Error::Timeout)) {
250 return false;
251 } else if (error == ipcq::make_error_code(ipcq::Error::InconsistentState)) {
252 // Use case for this tool is not conserned about missed samples. So when we get
253 // InconsistentState because of e.g. late joining we simply reset.
254 // Reset may fail if queue is Closed or if it is empty (nothing to reset to). We
255 // ignore that as well. Eventually there will be data in the queue and Reset() will
256 // succeed, or queue will be closed and Reset won't be attempted again.
257 if (!m_reader->Reset()) {
258 // Only log in the successful case as attempts to Reset will possibly otherwise
259 // flood the console with attempts if theres no data in the queue.
260 std::cerr << "Note: SHM reader state reset.\n";
261 }
262 return false;
263 } else {
264 std::string msg = "Failed to read from shared memory: " + error.message();
265 throw std::runtime_error(msg);
266 }
267 }
268 return num_elements > 0;
269 }
270
274 void PrintSample() override {
275 assert(not m_samples.empty());
276 PrintSample(m_samples.front());
277 }
278
282 const void* GetSampleData() const override {
283 assert(not m_samples.empty());
284 return reinterpret_cast<const void*>(&m_samples.front());
285 }
286
290 size_t GetSampleSize() const override {
291 return sizeof(Topic);
292 }
293
294 std::deque<Topic> m_samples;
295 std::unique_ptr<Reader> m_reader;
296};
297
298} // namespace rtctk::standaloneTools
299
300#endif // RTCTK_STANDALONETOOLS_SHMSUBSCRIBER_H
ShmSubscriberBase & operator=(ShmSubscriberBase &&rhs)=default
const int64_t PrintWihtLongFormat() const
Definition shmSubscriber.hpp:121
virtual void Initialise()=0
Should perform any needed initialisation steps for the program.
ShmSubscriberBase(const ShmSubscriberBase &rhs)=delete
int Run(int argc, char *argv[])
Executes the shared memory subscriber program.
Definition shmSubscriber.cpp:46
virtual bool ReadSample()=0
Should read a sample into internal buffers from the shared memory.
ShmSubscriberBase & operator=(const ShmSubscriberBase &rhs)=delete
virtual void Finalise()=0
Must cleanup any objects created in Initialise.
ShmSubscriberBase(ShmSubscriberBase &&rhs)=default
const int64_t GetSampleNumber() const
Definition shmSubscriber.hpp:113
virtual void PrintSample()=0
Should print the contents of the read sample to console in a human readable format.
virtual const void * GetSampleData() const =0
virtual size_t GetSampleSize() const =0
const std::string & GetFilename() const
Definition shmSubscriber.hpp:106
const std::string & GetQueueName() const
Definition shmSubscriber.hpp:98
ShmSubscriber(const ShmSubscriber &rhs)=delete
ShmSubscriber & operator=(ShmSubscriber &&rhs) noexcept=default
ShmSubscriber(ShmSubscriber &&rhs) noexcept=default
virtual void PrintSample(const Topic &sample)
Prints a hex dump of the sample.
Definition shmSubscriber.hpp:173
ShmSubscriber & operator=(const ShmSubscriber &rhs)=delete
Definition genDdsPublisher.hpp:19