11#ifndef RTCTK_STANDALONETOOLS_SHMSUBSCRIBER_H
12#define RTCTK_STANDALONETOOLS_SHMSUBSCRIBER_H
14#include <boost/io/ios_state.hpp>
19#include <ipcq/adapter.hpp>
20#include <ipcq/reader.hpp>
43 int Run(
int argc,
char* argv[]);
114 return m_sample_counter;
126 bool ParseArguments(
int argc,
char* argv[]);
127 void WriteBufferToFile(
const void* buffer,
size_t size);
128 bool TerminateProcess();
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;
149template <
typename Topic,
150 class ConditionPolicy = ipcq::BoostConditionPolicy,
151 class ShmTraits = ipcq::detail::BoostInterprocessTraits>
174 boost::io::ios_flags_saver saved_state(std::cout);
176 auto buffer =
reinterpret_cast<const uint8_t*
>(&sample);
177 size_t max_bytes_to_print = 64;
179 max_bytes_to_print = std::numeric_limits<size_t>::max();
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) {
187 last_was_endl =
true;
190 last_was_endl =
false;
193 if (not last_was_endl) {
196 if (
sizeof(Topic) > max_bytes_to_print) {
197 std::cout <<
"... (data continues) ...\n";
202 using Reader = ipcq::BasicReader<Topic, ConditionPolicy, ShmTraits>;
207 void Initialise()
override {
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 '" +
213 throw std::runtime_error(msg);
220 void Finalise()
override {
222 m_reader.reset(
nullptr);
223 }
catch (
const std::exception& error) {
224 std::string msg =
"Failed to destroy the shared memory reader for queue '" +
226 throw std::runtime_error(msg);
238 bool ReadSample()
override {
239 if (not m_samples.empty()) {
240 m_samples.pop_front();
242 if (not m_samples.empty()) {
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);
249 if (error == ipcq::make_error_code(ipcq::Error::Timeout)) {
251 }
else if (error == ipcq::make_error_code(ipcq::Error::InconsistentState)) {
257 if (!m_reader->Reset()) {
260 std::cerr <<
"Note: SHM reader state reset.\n";
264 std::string msg =
"Failed to read from shared memory: " + error.message();
265 throw std::runtime_error(msg);
268 return num_elements > 0;
275 assert(not m_samples.empty());
282 const void* GetSampleData()
const override {
283 assert(not m_samples.empty());
284 return reinterpret_cast<const void*
>(&m_samples.front());
290 size_t GetSampleSize()
const override {
291 return sizeof(Topic);
294 std::deque<Topic> m_samples;
295 std::unique_ptr<Reader> m_reader;