20 #include <QFileDialog> 21 #include <QMessageBox> 33 #include <H5Ipublic.h> 42 , buttonGroup(new QGroupBox)
43 , blockList(new QComboBox)
44 , channelList(new QComboBox)
45 , typeList(new QComboBox)
46 , selectionBox(new QListWidget)
47 , recordStatus(new QLabel)
48 , downsampleSpin(new QSpinBox(this))
49 , fileNameEdit(new QLineEdit)
50 , timeStampEdit(new QLineEdit)
51 , fileSizeLbl(new QLabel)
52 , fileSize(new QLabel)
53 , trialLengthLbl(new QLabel)
54 , trialLength(new QLabel)
55 , trialNumLbl(new QLabel)
56 , trialNum(new QLabel)
57 , recording_timer(new QTimer(this))
60 "<p><b>Data Recorder:</b><br>The Data Recorder writes data to an HDF5 " 62 "All available signals for saving to file are automatically detected. " 64 "loaded user modules are listed in the \"Block\" drop-down box. " 65 "Available DAQ cards " 66 "are listed here as /proc/analogy/devices. Use the \"Type\" and " 67 "\"Channel\" drop-down boxes " 68 "to select the signals that you want to save. Use the left and right " 70 "add these signals to the file. You may select a downsampling rate that " 72 "to the real-time period for execution (set in the System Control " 73 "Panel). The real-time " 74 "period and the data downsampling rate are both saved as metadata in the " 76 "so that you can reconstruct your data correctly. The current recording " 78 "the Data Recorder is shown at the bottom.</p>");
79 auto* layout =
new QGridLayout;
81 channelGroup =
new QGroupBox(tr(
"Channel Selection"));
82 auto* channelLayout =
new QVBoxLayout;
84 channelLayout->addWidget(
new QLabel(tr(
"Block:")));
85 channelLayout->addWidget(blockList);
87 blockList, SIGNAL(activated(
int)),
this, SLOT(buildChannelList()));
89 channelLayout->addWidget(
new QLabel(tr(
"Type:")));
91 channelLayout->addWidget(typeList);
92 typeList->addItem(
"Output", QVariant::fromValue(
IO::OUTPUT));
93 typeList->addItem(
"Input", QVariant::fromValue(
IO::INPUT));
95 typeList, SIGNAL(activated(
int)),
this, SLOT(buildChannelList()));
97 channelLayout->addWidget(
new QLabel(tr(
"Channel:")));
99 channelLayout->addWidget(channelList);
102 channelGroup->setLayout(channelLayout);
105 addRecorderButton =
new QPushButton(
"Add");
106 channelLayout->addWidget(addRecorderButton);
108 addRecorderButton, SIGNAL(released()),
this, SLOT(insertChannel()));
109 addRecorderButton->setEnabled(
false);
110 removeRecorderButton =
new QPushButton(
"Remove");
111 channelLayout->addWidget(removeRecorderButton);
113 removeRecorderButton, SIGNAL(released()),
this, SLOT(removeChannel()));
114 removeRecorderButton->setEnabled(
false);
117 stampGroup =
new QGroupBox(tr(
"Tag Data"));
118 auto* stampLayout =
new QHBoxLayout;
122 stampLayout->addWidget(timeStampEdit);
123 addTag =
new QPushButton(tr(
"Tag"));
124 stampLayout->addWidget(addTag);
125 QObject::connect(addTag, SIGNAL(released()),
this, SLOT(addNewTag()));
128 stampGroup->setLayout(stampLayout);
131 sampleGroup =
new QGroupBox(tr(
"Trial Metadata"));
132 auto* sampleLayout =
new QHBoxLayout;
136 trialNumLbl->setText(
"Trial #:");
137 trialNumLbl->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
138 sampleLayout->addWidget(trialNumLbl);
140 trialNum->setText(
"0");
141 trialNum->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
142 sampleLayout->addWidget(trialNum);
144 trialLengthLbl->setText(
"Trial Length (s):");
145 sampleLayout->addWidget(trialLengthLbl);
147 trialLength->setText(
"No data recorded");
148 trialLength->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
149 sampleLayout->addWidget(trialLength);
151 fileSizeLbl->setText(
"File Size (MB):");
152 sampleLayout->addWidget(fileSizeLbl);
154 fileSize->setText(
"No data recorded");
155 sampleLayout->addWidget(fileSize);
156 fileSize->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
159 sampleGroup->setLayout(sampleLayout);
162 fileGroup =
new QGroupBox(tr(
"File Control"));
163 auto* fileLayout =
new QHBoxLayout;
166 fileLayout->addWidget(
new QLabel(tr(
"File Name:")));
168 fileNameEdit->setReadOnly(
true);
169 fileLayout->addWidget(fileNameEdit);
170 auto* fileChangeButton =
new QPushButton(
"Choose File");
171 fileLayout->addWidget(fileChangeButton);
173 fileChangeButton, SIGNAL(released()),
this, SLOT(changeDataFile()));
175 fileLayout->addWidget(
new QLabel(tr(
"Downsample \nRate:")));
177 downsampleSpin->setMinimum(1);
178 downsampleSpin->setMaximum(500);
179 fileLayout->addWidget(downsampleSpin);
180 QObject::connect(downsampleSpin,
181 SIGNAL(valueChanged(
int)),
186 fileGroup->setLayout(fileLayout);
189 listGroup =
new QGroupBox(tr(
"Currently Recording"));
190 auto* listLayout =
new QGridLayout;
194 listLayout->addWidget(selectionBox, 1, 1, 4, 5);
197 listGroup->setLayout(listLayout);
201 auto* buttonLayout =
new QHBoxLayout;
204 startRecordButton =
new QPushButton(
"Start Recording");
207 buttonLayout->addWidget(startRecordButton);
208 startRecordButton->setEnabled(
false);
209 stopRecordButton =
new QPushButton(
"Stop Recording");
212 buttonLayout->addWidget(stopRecordButton);
213 stopRecordButton->setEnabled(
false);
214 closeButton =
new QPushButton(
"Close");
216 closeButton, SIGNAL(released()), parentWidget(), SLOT(close()));
217 buttonLayout->addWidget(closeButton);
219 buttonLayout->addWidget(recordStatus);
220 recordStatus->setText(
"Not ready.");
221 recordStatus->setFrameStyle(QFrame::Panel);
222 recordStatus->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
225 buttonGroup->setLayout(buttonLayout);
228 layout->addWidget(channelGroup, 0, 0, 1, 2);
229 layout->addWidget(listGroup, 0, 2, 1, 4);
230 layout->addWidget(stampGroup, 2, 0, 2, 6);
231 layout->addWidget(fileGroup, 4, 0, 1, 6);
232 layout->addWidget(sampleGroup, 5, 0, 1, 6);
233 layout->addWidget(buttonGroup, 6, 0, 1, 6);
239 this->
getMdiWindow()->setFixedSize(this->minimumSizeHint());
241 this->buildBlockList();
242 this->buildChannelList();
244 this->recording_timer->setInterval(1000);
246 this->recording_timer, SIGNAL(timeout()),
this, SLOT(processData()));
249 QObject::connect(this->fileNameEdit,
250 SIGNAL(textChanged(
const QString&)),
252 SLOT(syncEnableRecordingButtons(
const QString&)));
253 recording_timer->start();
256 void DataRecorder::Panel::buildBlockList()
260 this->getRTXIEventManager()->postEvent(&event);
262 std::any_cast<std::vector<IO::Block*>>(
event.getParam(
"blockList"));
263 auto prev_selected_block = blockList->currentData();
265 for (
auto* blockptr : blockPtrList) {
266 if (blockptr->getName().find(
"Probe") != std::string::npos
267 || blockptr->getName().find(
"Recording") != std::string::npos)
271 blockList->addItem(QString(blockptr->getName().c_str()) +
" " 272 + QString::number(blockptr->getID()),
273 QVariant::fromValue(blockptr));
275 blockList->setCurrentIndex(blockList->findData(prev_selected_block));
278 void DataRecorder::Panel::buildChannelList()
280 channelList->clear();
281 if (blockList->count() == 0 || blockList->currentIndex() < 0) {
285 auto* block = blockList->currentData().value<
IO::Block*>();
287 auto type = this->typeList->currentData().value<
IO::flags_t>();
288 for (
size_t i = 0; i < block->getCount(type); ++i) {
289 channelList->addItem(QString(block->getChannelName(type, i).c_str()),
290 QVariant::fromValue(i));
292 addRecorderButton->setEnabled(channelList->count() != 0);
295 void DataRecorder::Panel::changeDataFile()
297 QFileDialog fileDialog(
this);
299 fileDialog.setAcceptMode(QFileDialog::AcceptSave);
300 fileDialog.setFileMode(QFileDialog::AnyFile);
301 fileDialog.setWindowTitle(
"Select Data File");
304 QSettings::setPath(QSettings::NativeFormat,
305 QSettings::SystemScope,
306 "/usr/local/share/rtxi/");
307 fileDialog.setDirectory(
308 userprefs.value(
"/dirs/data", getenv(
"HOME")).toString());
310 QStringList filterList;
311 filterList.push_back(
"HDF5 files (*.h5)");
312 filterList.push_back(
"All files (*.*)");
313 fileDialog.setNameFilters(filterList);
314 fileDialog.selectNameFilter(
"HDF5 files (*.h5)");
316 fileDialog.selectFile(
317 QString(
"rtxi_datafile_") + QDate::currentDate().toString(
"yyyyMMdd")
318 + QString(
"_") + QTime::currentTime().toString(
"hhmmss"));
320 if (fileDialog.exec() != QDialog::Accepted) {
323 files = fileDialog.selectedFiles();
325 if (files.isEmpty() || files[0] ==
nullptr || files[0] ==
"/") {
329 if (!filename.toLower().endsWith(QString(
".h5"))) {
334 userprefs.setValue(
"/dirs/data", fileDialog.directory().path());
338 this->fileNameEdit->setText(QString(hplugin->getOpenFilename().c_str()));
342 void DataRecorder::Panel::insertChannel()
344 if ((blockList->count() == 0) || (channelList->count() == 0)) {
351 endpoint.
port = channelList->currentData().value<
size_t>();
353 for (
int row = 0; row < this->selectionBox->count(); row++) {
354 if (this->selectionBox->item(row)->data(Qt::UserRole).value<
IO::endpoint>()
357 this->selectionBox->setCurrentRow(row);
367 "DataRecorder::Panel::insertChannel : Unable to create recording " 372 QListWidgetItem* temp_item =
nullptr;
373 const std::string formatting =
"{} {} direction: {} port: {}";
374 const std::string temp_name =
375 fmt::format(formatting,
380 temp_item =
new QListWidgetItem(QString(temp_name.c_str()));
381 temp_item->setData(Qt::UserRole, QVariant::fromValue(
endpoint));
382 selectionBox->addItem(temp_item);
384 removeRecorderButton->setEnabled(selectionBox->count() != 0);
387 void DataRecorder::Panel::removeChannel()
389 if ((selectionBox->count() == 0) || selectionBox->selectedItems().isEmpty()) {
392 QListWidgetItem* currentItem =
393 this->selectionBox->takeItem(this->selectionBox->currentRow());
395 this->selectionBox->setCurrentRow(-1);
396 this->selectionBox->removeItemWidget(currentItem);
402 removeRecorderButton->setEnabled(selectionBox->count() != 0);
405 void DataRecorder::Panel::addNewTag()
409 const std::string tag = this->timeStampEdit->text().toStdString();
410 if (hplugin->apply_tag(tag) != 0) {
411 ERROR_MSG(
"DataRecorder::Panel::addNewTag : could not tag data with tag {}",
413 timeStampEdit->clear();
414 recordStatus->setText(
"Tagging Failed!");
417 timeStampEdit->clear();
418 recordStatus->setText(
"Tagged");
424 if (fileNameEdit->text().isEmpty()) {
425 QMessageBox::critical(
this,
426 "Data file not specified.",
427 "Please specify a file to write data to.",
429 QMessageBox::NoButton);
435 this->recordStatus->setText(hplugin->isRecording() ?
"Recording..." 437 if (hplugin->isRecording()) {
438 this->starting_record_time = QTime::currentTime();
439 this->trialNum->setNum(hplugin->getTrialCount());
440 this->trialLength->setText(
"Recording...");
449 this->recordStatus->setText(!hplugin->isRecording() ?
"Ready" 451 if (!hplugin->isRecording()) {
452 this->trialNum->setNum(hplugin->getTrialCount());
453 this->trialLength->setNum(
454 this->starting_record_time.secsTo(QTime::currentTime()));
455 this->fileSize->setNum(
456 static_cast<double>(QFile(fileNameEdit->text()).size())
457 / (1024.0 * 1024.0));
464 this->downsample_rate = rate;
469 std::vector<QListWidgetItem*> all_recorders;
471 for (
int row = 0; row < this->selectionBox->count(); row++) {
473 this->selectionBox->item(row)->data(Qt::UserRole).value<
IO::endpoint>();
474 if (temp_endpoint.
block == block) {
475 all_recorders.push_back(this->selectionBox->item(row));
478 for (
auto* item : all_recorders) {
479 this->selectionBox->removeItemWidget(item);
483 void DataRecorder::Panel::processData()
489 void DataRecorder::Panel::syncEnableRecordingButtons(
const QString& )
493 startRecordButton->setEnabled(ready);
494 stopRecordButton->setEnabled(ready);
495 this->recordStatus->setText(ready ?
"Ready" :
"Not ready");
506 this->stopRecording();
509 std::vector<Event::Object> unload_events;
510 for (
auto& entry : this->m_recording_channels_list) {
511 unload_events.emplace_back(event_type);
512 unload_events.back().setParam(
513 "thread", std::any(
static_cast<RT::Thread*
>(entry.component.get())));
515 this->getEventManager()->postEvent(unload_events);
521 std::vector<IO::endpoint> endpoints;
526 ->removeRecorders(block);
527 for (
const auto& entry : this->m_recording_channels_list) {
528 if (entry.channel.endpoint.block == block) {
529 endpoints.push_back(entry.channel.endpoint);
532 for (
const auto&
endpoint : endpoints) {
548 if (this->recording.load() || this->m_recording_channels_list.empty()) {
551 const std::unique_lock<std::shared_mutex> lk(this->m_channels_list_mut);
552 this->append_new_trial();
554 std::vector<Event::Object> start_recording_event;
555 for (
auto& rec_channel : this->m_recording_channels_list) {
556 start_recording_event.emplace_back(event_type);
557 start_recording_event.back().setParam(
558 "thread",
static_cast<RT::Thread*
>(rec_channel.component.get()));
560 this->getEventManager()->postEvent(start_recording_event);
561 this->recording.store(
true);
566 if (!this->recording.load()) {
569 const std::unique_lock<std::shared_mutex> lk(this->m_channels_list_mut);
571 std::vector<Event::Object> stop_recording_event;
572 for (
auto& rec_chan : this->m_recording_channels_list) {
573 stop_recording_event.emplace_back(event_type);
574 stop_recording_event.back().setParam(
575 "thread",
static_cast<RT::Thread*
>(rec_chan.component.get()));
577 this->getEventManager()->postEvent(stop_recording_event);
578 this->recording.store(
false);
581 void DataRecorder::Plugin::close_trial_group()
583 if (!open_file.load()) {
586 for (
auto& channel : this->m_recording_channels_list) {
587 if (channel.hdf5_data_handle != H5I_INVALID_HID) {
588 H5PTclose(channel.hdf5_data_handle);
589 channel.hdf5_data_handle = H5I_INVALID_HID;
592 if (this->hdf5_handles.sync_group_handle != H5I_INVALID_HID) {
593 H5Gclose(this->hdf5_handles.sync_group_handle);
594 this->hdf5_handles.sync_group_handle = H5I_INVALID_HID;
596 if (this->hdf5_handles.async_group_handle != H5I_INVALID_HID) {
597 H5Gclose(this->hdf5_handles.async_group_handle);
598 this->hdf5_handles.async_group_handle = H5I_INVALID_HID;
600 if (this->hdf5_handles.sys_data_group_handle != H5I_INVALID_HID) {
601 H5Gclose(this->hdf5_handles.sys_data_group_handle);
602 this->hdf5_handles.sys_data_group_handle = H5I_INVALID_HID;
604 if (this->hdf5_handles.trial_group_handle != H5I_INVALID_HID) {
605 H5Gclose(this->hdf5_handles.trial_group_handle);
606 this->hdf5_handles.trial_group_handle = H5I_INVALID_HID;
610 void DataRecorder::Plugin::open_trial_group()
612 this->trial_count += 1;
613 hid_t compression_property = H5I_INVALID_HID;
614 std::string trial_name =
"/Trial";
615 trial_name += std::to_string(this->trial_count);
616 this->hdf5_handles.trial_group_handle =
617 H5Gcreate(this->hdf5_handles.file_handle,
622 this->hdf5_handles.sync_group_handle =
623 H5Gcreate(this->hdf5_handles.trial_group_handle,
624 (trial_name +
"/Synchronous Data").c_str(),
628 this->hdf5_handles.async_group_handle =
629 H5Gcreate(this->hdf5_handles.trial_group_handle,
630 (trial_name +
"/Asynchronous Data").c_str(),
634 this->hdf5_handles.sys_data_group_handle =
635 H5Gcreate(this->hdf5_handles.trial_group_handle,
636 (trial_name +
"/System Settings").c_str(),
640 for (
auto& channel : this->m_recording_channels_list) {
641 compression_property = H5Pcreate(H5P_DATASET_CREATE);
642 H5Pset_deflate(compression_property, 7);
643 channel.hdf5_data_handle =
644 H5PTcreate(this->hdf5_handles.sync_group_handle,
645 channel.channel.name.c_str(),
646 this->hdf5_handles.channel_datatype_handle,
647 this->m_data_chunk_size,
648 compression_property);
652 void DataRecorder::Plugin::append_new_trial()
654 this->close_trial_group();
656 std::array<data_token_t, 100> tempbuffer {};
657 for (
auto& recorder : this->m_recording_channels_list) {
658 while (recorder.channel.data_source->read(
665 this->open_trial_group();
670 if (this->open_file.load()) {
673 const std::unique_lock<std::shared_mutex> lk(this->m_channels_list_mut);
674 this->hdf5_handles.file_handle =
675 H5Fcreate(file_name.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
676 if (this->hdf5_handles.file_handle == H5I_INVALID_HID) {
677 ERROR_MSG(
"DataRecorder::Plugin::openFile : Unable to open file {}",
679 H5Fclose(this->hdf5_handles.file_handle);
680 this->hdf5_filename =
"";
683 this->hdf5_filename = file_name;
684 this->trial_count = 0;
685 this->hdf5_handles.channel_datatype_handle =
687 H5Tinsert(this->hdf5_handles.channel_datatype_handle,
691 H5Tinsert(this->hdf5_handles.channel_datatype_handle,
696 this->open_file.store(
true);
701 if (!this->open_file.load()) {
704 const std::unique_lock<std::shared_mutex> lk(this->m_channels_list_mut);
707 H5Tclose(this->hdf5_handles.channel_datatype_handle);
708 if (H5Fclose(this->hdf5_handles.file_handle) != 0) {
709 ERROR_MSG(
"DataRecorder::Plugin::closeFile : Unable to close file {}",
710 this->hdf5_filename);
712 this->open_file =
false;
718 this->openFile(file_name);
726 auto iter = std::find_if(this->m_recording_channels_list.begin(),
727 this->m_recording_channels_list.end(),
729 { return rec.channel.endpoint == endpoint; });
730 if (iter != this->m_recording_channels_list.end()) {
738 chan.
name +=
"Recording Component";
740 std::unique_ptr<DataRecorder::Component> component =
741 std::make_unique<DataRecorder::Component>(
this, chan.
name);
744 component->setActive(this->recording.load());
745 event.setParam(
"thread",
static_cast<RT::Thread*
>(component.get()));
746 this->getEventManager()->postEvent(&event);
751 connection.
dest = component.get();
754 connect_event.
setParam(
"connection", std::any(connection));
755 this->getEventManager()->postEvent(&connect_event);
756 hid_t data_handle = H5I_INVALID_HID;
757 const std::unique_lock<std::shared_mutex> lk(this->m_channels_list_mut);
758 if (this->hdf5_handles.file_handle != H5I_INVALID_HID
759 && this->hdf5_handles.sync_group_handle != H5I_INVALID_HID)
761 const hid_t compression_property = H5Pcreate(H5P_DATASET_CREATE);
762 H5Pset_deflate(compression_property, 7);
763 data_handle = H5PTcreate(this->hdf5_handles.sync_group_handle,
765 this->hdf5_handles.channel_datatype_handle,
766 this->m_data_chunk_size,
767 compression_property);
769 this->m_recording_channels_list.emplace_back(
770 chan, std::move(component), data_handle);
779 this->getEventManager()->postEvent(&pause_event);
782 this->getEventManager()->postEvent(&unplug_event);
783 const std::unique_lock<std::shared_mutex> recorder_lock(
784 this->m_channels_list_mut);
785 auto iter = std::find_if(this->m_recording_channels_list.begin(),
786 this->m_recording_channels_list.end(),
787 [component](
const recorder_t& rec_chan)
788 { return rec_chan.component.get() == component; });
789 if (iter == this->m_recording_channels_list.end()) {
792 H5PTclose(iter->hdf5_data_handle);
793 this->m_recording_channels_list.erase(iter);
798 const std::shared_lock<std::shared_mutex> lk(this->m_channels_list_mut);
799 auto iter = std::find_if(this->m_recording_channels_list.begin(),
800 this->m_recording_channels_list.end(),
801 [
endpoint](
const recorder_t& rec_chan)
802 { return rec_chan.channel.endpoint == endpoint; });
803 if (iter == this->m_recording_channels_list.end()) {
806 return iter->channel.name;
812 const std::shared_lock<std::shared_mutex> lk(this->m_channels_list_mut);
813 auto iter = std::find_if(this->m_recording_channels_list.begin(),
814 this->m_recording_channels_list.end(),
815 [
endpoint](
const recorder_t& rec_chan)
816 { return rec_chan.channel.endpoint == endpoint; });
817 if (iter == this->m_recording_channels_list.end()) {
820 return iter->component.get();
823 std::vector<DataRecorder::record_channel>
826 const std::shared_lock<std::shared_mutex> lk(this->m_channels_list_mut);
827 std::vector<DataRecorder::record_channel> result(
828 this->m_recording_channels_list.size());
829 for (
size_t i = 0; i < result.size(); i++) {
830 result[i] = this->m_recording_channels_list[i].channel;
842 if (!this->open_file) {
845 std::vector<DataRecorder::data_token_t> data_buffer(this->m_data_chunk_size);
847 int64_t read_bytes = 0;
848 size_t packet_count = 0;
849 const std::shared_lock<std::shared_mutex> lk(this->m_channels_list_mut);
850 for (
auto& channel : this->m_recording_channels_list) {
851 while (read_bytes = channel.channel.data_source->read(
852 data_buffer.data(), packet_byte_size * data_buffer.size()),
855 packet_count =
static_cast<size_t>(read_bytes) / packet_byte_size;
856 DataRecorder::Plugin::save_data(
857 channel.hdf5_data_handle, data_buffer, packet_count);
862 void DataRecorder::Plugin::save_data(
864 const std::vector<DataRecorder::data_token_t>& data,
868 H5PTappend(data_id,
static_cast<hsize_t
>(packet_count), data.data());
870 ERROR_MSG(
"Unable to write data into hdf5 file!");
875 const std::string& probe_name)
882 ERROR_MSG(
"Unable to create xfifo for Oscilloscope Component {}",
890 const double value = readinput(0);
891 switch (this->getState()) {
894 data_sample.
value = value;
910 return this->m_fifo.get();
916 return std::make_unique<DataRecorder::Plugin>(ev_manager);
929 return std::unique_ptr<DataRecorder::Component>(
nullptr);
RT::OS::Fifo * get_fifo()
Component(Widgets::Plugin *hplugin, const std::string &probe_name)
void updateDownsampleRate(size_t rate)
Panel(const Panel &)=delete
void startRecordClicked()
void removeRecorders(IO::Block *block)
void process_data_worker()
void destroy_component(IO::endpoint endpoint)
int apply_tag(const std::string &tag)
void openFile(const std::string &file_name)
std::string getRecorderName(IO::endpoint endpoint)
void change_file(const std::string &file_name)
int create_component(IO::endpoint endpoint)
DataRecorder::Component * getRecorderPtr(IO::endpoint endpoint)
void receiveEvent(Event::Object *event) override
Plugin(const Plugin &)=delete
std::vector< record_channel > get_recording_channels()
void setParam(const std::string ¶m_name, const std::any ¶m_value)
Event::Type getType() const
std::string getName() const
void ERROR_MSG(const std::string &errmsg, Args... args)
constexpr std::string_view MODULE_NAME
constexpr size_t DEFAULT_BUFFER_SIZE
constexpr std::string_view MODULE_NAME
Widgets::FactoryMethods getFactories()
std::unique_ptr< Widgets::Plugin > createRTXIPlugin(Event::Manager *ev_manager)
struct DataRecorder::data_token_t data_token_t
std::vector< Widgets::Variable::Info > get_default_vars()
std::unique_ptr< Widgets::Component > createRTXIComponent(Widgets::Plugin *host_plugin)
Widgets::Panel * createRTXIPanel(QMainWindow *mwindow, Event::Manager *ev_manager)
std::vector< IO::channel_t > get_default_channels()
@ RT_THREAD_UNPAUSE_EVENT
struct IO::endpoint endpoint
int getFifo(std::unique_ptr< Fifo > &fifo, size_t fifo_size)
RT::OS::Fifo * data_source
IO::flags_t src_port_type