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