34  , buttonGroup(new QGroupBox)
  35  , deviceList(new QComboBox)
  36  , analogChannelList(new QComboBox)
  37  , analogRangeList(new QComboBox)
  38  , analogDownsampleList(new QComboBox)
  39  , analogReferenceList(new QComboBox)
  40  , analogSubdeviceList(new QComboBox)
  41  , analogUnitPrefixList(new QComboBox)
  42  , analogUnitList(new QComboBox)
  43  , analogUnitPrefixList2(new QComboBox)
  44  , analogGainEdit(new QLineEdit)
  45  , analogZeroOffsetEdit(new QLineEdit)
  46  , digitalChannelList(new QComboBox)
  47  , digitalDirectionList(new QComboBox)
  48  , digitalSubdeviceList(new QComboBox)
  50  , freqUnitList(new QComboBox)
  51  , periodUnitList(new QComboBox)
  52  , freqEdit(new QLineEdit)
  53  , periodEdit(new QLineEdit)
  56  "<p><b>System Control Panel:</b><br>This control panel allows you to "  58  "the channels on your DAQ card. RTXI automatically detects the number "  60  "of channels that are available. You should set the \"Scale\" of the "  62  "to be the inverse of the gain that is applied to the signal through the "  63  "combination of hardware and software that you are using. To acquire "  65  "a channel, you must set it to be Active using the toggle button. Any "  67  "settings such as the \"Range\" or \"Scale\" must be set by clicking the "  69  "button.<br><br> The \"Thread\" tab allows you to set the period for "  71  "execution. You must click \"Apply\" to change this setting and "  73  "to other user modules such as the Data Recorder. Custom user modules "  75  "execute special code when the real-time period is changed using the "  79  auto* layout = 
new QGridLayout;
  82  deviceGroup = 
new QGroupBox(tr(
"DAQ Setup"));
  83  auto* deviceLayout = 
new QGridLayout;
  86  deviceLayout->addWidget(
new QLabel(tr(
"Device:")), 0, 0);
  88  deviceLayout->addWidget(deviceList, 0, 1, 1, 5);
  91  deviceList, SIGNAL(activated(
int)), 
this, SLOT(
updateDevice()));
  94  deviceLayout->addWidget(
new QLabel(tr(
"Frequency:")), 1, 0);
  95  deviceLayout->addWidget(freqEdit, 1, 1);
  99  auto period = std::any_cast<int64_t>(get_period_event.
getParam(
"period"));
  104  freqEdit, SIGNAL(textEdited(
const QString&)), 
this, SLOT(
updatePeriod()));
  105  freqUnitList->setFixedWidth(50);
  106  freqUnitList->addItem(
" Hz", 1);
  107  freqUnitList->addItem(
"kHz", 1000);
  108  deviceLayout->addWidget(freqUnitList, 1, 2);
  110  freqUnitList, SIGNAL(activated(
int)), 
this, SLOT(
updatePeriod()));
  113  deviceLayout->addWidget(
new QLabel(tr(
"Period:")), 1, 3);
  114  deviceLayout->addWidget(periodEdit, 1, 4);
  116  periodEdit, SIGNAL(textEdited(
const QString&)), 
this, SLOT(
updateFreq()));
  117  deviceLayout->addWidget(periodUnitList, 1, 5);
  118  periodUnitList->setFixedWidth(50);
  119  periodUnitList->addItem(
" s", 1.0);
  120  periodUnitList->addItem(
"ms", 1e-3);
  121  periodUnitList->addItem(
"us", 1e-6);
  122  periodUnitList->addItem(
"ns", 1e-9);
  124  periodUnitList, SIGNAL(activated(
int)), 
this, SLOT(
updateFreq()));
  128  deviceGroup->setLayout(deviceLayout);
  131  analogGroup = 
new QGroupBox(tr(
"Analog Channels"));
  132  auto* analogLayout = 
new QGridLayout;
  135  analogLayout->addWidget(
new QLabel(tr(
"Channel:")), 1, 0);
  137  analogSubdeviceList->addItem(
"Input",
  139  analogSubdeviceList->addItem(
"Output",
  142  analogSubdeviceList, SIGNAL(activated(
int)), 
this, SLOT(
updateDevice()));
  143  analogLayout->addWidget(analogSubdeviceList, 1, 1);
  146  analogChannelList, SIGNAL(activated(
int)), 
this, SLOT(
display()));
  147  analogLayout->addWidget(analogChannelList, 1, 2);
  149  analogActiveButton = 
new QPushButton(
"Active");
  150  analogActiveButton->setCheckable(
true);
  151  analogLayout->addWidget(analogActiveButton, 1, 3);
  153  analogLayout->addWidget(
new QLabel(tr(
"Range:")), 2, 0, 1, 1);
  154  analogLayout->addWidget(analogRangeList, 2, 1, 1, 2);
  155  analogRangeList->clear();
  156  const std::string formatting = 
"{:.1f}";
  157  std::string range_list_text;
  160  auto [min, max] = range;
  161  range_list_text = fmt::format(formatting, min) + std::string(
" to ")
  162  + fmt::format(formatting, max);
  163  analogRangeList->addItem(QString(range_list_text.c_str()),
  164  QVariant::fromValue(indx));
  168  analogLayout->addWidget(analogReferenceList, 2, 3, 1, 2);
  169  analogLayout->addWidget(
new QLabel(tr(
"Scale:")), 3, 0);
  170  analogReferenceList->clear();
  171  analogReferenceList->addItem(
  174  analogReferenceList->addItem(
  177  analogReferenceList->addItem(
"Differential",
  180  analogReferenceList->addItem(
  184  analogGainEdit->setAlignment(Qt::AlignRight);
  185  analogLayout->addWidget(analogGainEdit, 3, 1);
  187  analogUnitPrefixList->addItem(
"yotta-", 1e24);
  188  analogUnitPrefixList->addItem(
"zetta-", 1e21);
  189  analogUnitPrefixList->addItem(
"exa-", 1e18);
  190  analogUnitPrefixList->addItem(
"peta-", 1e15);
  191  analogUnitPrefixList->addItem(
"tera-", 1e12);
  192  analogUnitPrefixList->addItem(
"giga-", 1e9);
  193  analogUnitPrefixList->addItem(
"mega-", 1e6);
  194  analogUnitPrefixList->addItem(
"kilo-", 1e3);
  195  analogUnitPrefixList->addItem(
"", 1);
  196  analogUnitPrefixList->addItem(
"milli-", 1e-3);
  197  analogUnitPrefixList->addItem(
"micro-", 1e-6);
  198  analogUnitPrefixList->addItem(
"nano-", 1e-9);
  199  analogUnitPrefixList->addItem(
"pico-", 1e-12);
  200  analogUnitPrefixList->addItem(
"femto-", 1e-15);
  201  analogUnitPrefixList->addItem(
"atto-", 1e-18);
  202  analogUnitPrefixList->addItem(
"zepto-", 1e-21);
  203  analogUnitPrefixList->addItem(
"yocto-", 1e-24);
  204  analogLayout->addWidget(analogUnitPrefixList, 3, 2);
  206  analogLayout->addWidget(analogUnitList, 3, 3);
  207  analogUnitList->clear();
  210  analogUnitList->addItem(QString(units.c_str()),
  211  QVariant::fromValue(units_index));
  214  analogLayout->addWidget(
new QLabel(tr(
" / Volt")), 3, 4);
  215  analogLayout->addWidget(
new QLabel(tr(
"Offset:")), 4, 0);
  216  analogZeroOffsetEdit->setText(
"0");
  217  analogZeroOffsetEdit->setAlignment(Qt::AlignRight);
  218  analogLayout->addWidget(analogZeroOffsetEdit, 4, 1);
  221  analogUnitPrefixList2->addItem(
"yotta-", 1e24);
  222  analogUnitPrefixList2->addItem(
"zetta-", 1e21);
  223  analogUnitPrefixList2->addItem(
"exa-", 1e18);
  224  analogUnitPrefixList2->addItem(
"peta-", 1e15);
  225  analogUnitPrefixList2->addItem(
"tera-", 1e12);
  226  analogUnitPrefixList2->addItem(
"giga-", 1e9);
  227  analogUnitPrefixList2->addItem(
"mega-", 1e6);
  228  analogUnitPrefixList2->addItem(
"kilo-", 1e3);
  229  analogUnitPrefixList2->addItem(
"", 1);
  230  analogUnitPrefixList2->addItem(
"milli-", 1e-3);
  231  analogUnitPrefixList2->addItem(
"micro-", 1e-6);
  232  analogUnitPrefixList2->addItem(
"nano-", 1e-9);
  233  analogUnitPrefixList2->addItem(
"pico-", 1e-12);
  234  analogUnitPrefixList2->addItem(
"femto-", 1e-15);
  235  analogUnitPrefixList2->addItem(
"atto-", 1e-18);
  236  analogUnitPrefixList2->addItem(
"zepto-", 1e-21);
  237  analogUnitPrefixList2->addItem(
"yocto-", 1e-24);
  239  analogLayout->addWidget(analogUnitPrefixList2, 4, 2, 1, 1);
  240  analogLayout->addWidget(
new QLabel(tr(
" Volt/Amps")), 4, 3);
  241  analogLayout->addWidget(
new QLabel(tr(
"Downsample:")), 5, 0);
  242  analogDownsampleList->addItem(
"1", 1);
  243  analogDownsampleList->addItem(
"2", 2);
  244  analogDownsampleList->addItem(
"4", 4);
  245  analogDownsampleList->addItem(
"6", 6);
  246  analogDownsampleList->addItem(
"8", 8);
  247  analogDownsampleList->addItem(
"10", 10);
  248  analogLayout->addWidget(analogDownsampleList, 5, 1);
  251  analogGroup->setLayout(analogLayout);
  254  digitalGroup = 
new QGroupBox(tr(
"Digital I/O"));
  255  auto* digitalLayout = 
new QGridLayout;
  258  digitalLayout->addWidget(
new QLabel(tr(
"Channel:")), 1, 0, 1, 1);
  260  digitalSubdeviceList->addItem(
"I/O");
  262  digitalSubdeviceList, SIGNAL(activated(
int)), 
this, SLOT(
updateDevice()));
  263  digitalLayout->addWidget(digitalSubdeviceList, 1, 1, 1, 1);
  266  digitalChannelList, SIGNAL(activated(
int)), 
this, SLOT(
display()));
  267  digitalLayout->addWidget(digitalChannelList, 1, 2, 1, 1);
  269  digitalDirectionList->addItem(
"Input",
  271  digitalDirectionList->addItem(
"Output",
  273  digitalLayout->addWidget(digitalDirectionList, 1, 3, 1, 1);
  275  digitalActiveButton = 
new QPushButton(
"Active");
  276  digitalActiveButton->setCheckable(
true);
  277  digitalLayout->addWidget(digitalActiveButton, 1, 4, 1, 1);
  280  digitalGroup->setLayout(digitalLayout);
  283  auto* buttonLayout = 
new QHBoxLayout;
  286  auto* applyButton = 
new QPushButton(
"Apply");
  287  QObject::connect(applyButton, SIGNAL(released()), 
this, SLOT(
apply()));
  288  buttonLayout->addWidget(applyButton);
  289  auto* cancelButton = 
new QPushButton(
"Close");
  291  cancelButton, SIGNAL(released()), parentWidget(), SLOT(close()));
  292  buttonLayout->addWidget(cancelButton);
  295  buttonGroup->setLayout(buttonLayout);
  298  layout->addWidget(deviceGroup, 1, 0);
  299  layout->addWidget(analogGroup, 2, 0);
  300  layout->addWidget(digitalGroup, 3, 0);
  301  layout->addWidget(buttonGroup, 4, 0);
  305  setWindowTitle(
"System Control Panel");
  308  this->
getMdiWindow()->setFixedSize(this->minimumSizeHint());
  315 void SystemControl::Panel::submitAnalogChannelUpdate()
  317  auto* dev = deviceList->currentData().value<
DAQ::Device*>();
  318  auto a_chan = analogChannelList->currentData().value<
DAQ::index_t>();
  321  const double a_gain = analogGainEdit->text().toDouble()
  322  * analogUnitPrefixList->currentData().toDouble();
  323  const double a_zerooffset = analogZeroOffsetEdit->text().toDouble()
  324  * analogUnitPrefixList2->currentData().toDouble();
  327  if (!analogActiveButton->isChecked()) {
  330  dev->setAnalogGain(a_type, a_chan, a_gain);
  331  dev->setAnalogZeroOffset(a_type, a_chan, a_zerooffset);
  333  a_type, a_chan, analogRangeList->currentData().value<
DAQ::index_t>());
  334  dev->setAnalogReference(
  335  a_type, a_chan, analogReferenceList->currentData().value<
DAQ::index_t>());
  337  a_type, a_chan, analogUnitList->currentData().value<
DAQ::index_t>());
  340  ->itemData(analogDownsampleList->currentIndex(), Qt::DisplayRole)
  342  dev->setAnalogDownsample(a_type, a_chan, 
static_cast<size_t>(value));
  343  dev->setAnalogCounter(a_type, a_chan);
  346 void SystemControl::Panel::submitDigitalChannelUpdate()
  348  auto* dev = deviceList->currentData().value<
DAQ::Device*>();
  349  auto d_chan = digitalChannelList->currentData().value<
DAQ::index_t>();
  354  dev->setChannelActive(d_type, d_chan, digitalActiveButton->isChecked());
  355  if (!digitalActiveButton->isChecked()) {
  359  dev->setDigitalDirection(d_chan, d_dir);
  365  int64_t freq = freqEdit->text().toInt();
  366  freq *= freqUnitList->currentData().toInt();
  369  event.setParam(
"period", std::any(period));
  370  this->getRTXIEventManager()->postEvent(&event);
  373  if (deviceList->count() == 0 || deviceList->currentIndex() < 0) {
  377  auto* device = this->deviceList->currentData().value<
DAQ::Device*>();
  379  disable_device.setParam(
"device", std::any(
static_cast<RT::Device*
>(device)));
  383  this->getRTXIEventManager()->postEvent(&disable_device);
  384  if (analogActiveButton->isEnabled()) {
  385  this->submitAnalogChannelUpdate();
  387  if (digitalActiveButton->isEnabled()) {
  388  this->submitDigitalChannelUpdate();
  390  this->getRTXIEventManager()->postEvent(&enable_device);
  397  if (this->deviceList->currentIndex() < 0) {
  401  auto* dev = deviceList->currentData().value<
DAQ::Device*>();
  402  analogChannelList->clear();
  403  digitalChannelList->clear();
  407  for (
size_t i = 0; i < dev->getChannelCount(type); ++i) {
  408  analogChannelList->addItem(
  409  QString::number(i), QVariant::fromValue(
static_cast<DAQ::index_t>(i)));
  413  for (
size_t i = 0; i < dev->getChannelCount(type); ++i) {
  414  digitalChannelList->addItem(
  415  QString::number(i), QVariant::fromValue(
static_cast<DAQ::index_t>(i)));
  424  auto period = periodEdit->text().toDouble();
  425  period *= periodUnitList->currentData().toDouble();
  426  auto freq = 1 / period;
  433  freqEdit->setText(QString::number(freq));
  434  freqUnitList->setCurrentIndex(index);
  442  auto freq = freqEdit->text().toDouble();
  443  freq *= freqUnitList->currentData().toDouble();
  445  auto period = 1 / freq;
  447  while (period < .001 && (index < 4)) {
  452  periodEdit->setText(QString::number(period));
  453  periodUnitList->setCurrentIndex(index);
  456 void SystemControl::Panel::buildDAQDeviceList()
  459  this->getRTXIEventManager()->postEvent(&device_list_request);
  460  auto devices = std::any_cast<std::vector<DAQ::Device*>>(
  461  device_list_request.getParam(
"devices"));
  462  for (
auto* device : devices) {
  463  this->deviceList->addItem(QString(device->getName().c_str()),
  464  QVariant::fromValue(device));
  471  if (deviceList->count() == 0) {
  472  deviceList->setEnabled(
false);
  473  analogSubdeviceList->setEnabled(
false);
  474  digitalSubdeviceList->setEnabled(
false);
  476  displayAnalogGroup();
  477  displayDigitalGroup();
  481  this->getRTXIEventManager()->postEvent(&get_period_event);
  482  auto tmp = std::any_cast<int64_t>(get_period_event.
getParam(
"period"));
  483  while ((tmp >= 1000) && ((index) != 0)) {
  487  periodEdit->setText(QString::number(
static_cast<int64_t
>(tmp)));
  488  periodUnitList->setCurrentIndex(index);
  494  if (deviceList->count() == 0 || deviceList->currentIndex() < 0) {
  497  if (analogChannelList->count() == 0 || analogChannelList->currentIndex() < 0)
  499  analogActiveButton->setChecked(
false);
  500  analogActiveButton->setEnabled(
false);
  501  analogRangeList->setEnabled(
false);
  502  analogDownsampleList->setEnabled(
false);
  503  analogReferenceList->setEnabled(
false);
  504  analogGainEdit->setEnabled(
false);
  505  analogZeroOffsetEdit->setEnabled(
false);
  506  analogUnitPrefixList->setEnabled(
false);
  507  analogUnitPrefixList2->setEnabled(
false);
  508  analogUnitList->setEnabled(
false);
  511  auto* dev = deviceList->currentData().value<
DAQ::Device*>();
  514  auto chan = analogChannelList->currentData().value<
DAQ::index_t>();
  518  analogActiveButton->setEnabled(
true);
  519  analogChannelList->setEnabled(
true);
  520  analogRangeList->setEnabled(
true);
  521  analogReferenceList->setEnabled(
true);
  522  analogGainEdit->setEnabled(
true);
  523  analogZeroOffsetEdit->setEnabled(
true);
  524  analogUnitPrefixList->setEnabled(
true);
  525  analogUnitPrefixList2->setEnabled(
true);
  526  analogUnitList->setEnabled(
true);
  528  analogActiveButton->setChecked(dev->getChannelActive(type, chan));
  529  analogRangeList->setCurrentIndex(
  530  static_cast<int>(dev->getAnalogRange(type, chan)));
  531  analogDownsampleList->setCurrentIndex(analogDownsampleList->findData(
  532  QVariant::fromValue(dev->getAnalogDownsample(type, chan)),
  534  analogReferenceList->setCurrentIndex(analogReferenceList->findData(
  535  QVariant::fromValue(dev->getAnalogReference(type, chan))));
  536  analogUnitList->setCurrentIndex(analogUnitList->findData(
  537  QVariant::fromValue(dev->getAnalogUnits(type, chan))));
  544  while (((tmp >= 1000) && (indx > 0)) || ((tmp < 1) && (indx < 16))) {
  553  analogGainEdit->setText(QString::number(gain));
  556  analogUnitPrefixList->setCurrentIndex(indx);
  560  const double offset = dev->getAnalogZeroOffset(type, chan);
  562  while (((tmp >= 1000) && (indx > 0)) || ((tmp < 1) && (indx < 16))) {
  571  analogZeroOffsetEdit->setText(QString::number(offset));
  573  analogUnitPrefixList2->setCurrentIndex(indx);
  578  if (deviceList->count() == 0 || deviceList->currentIndex() < 0) {
  581  if (digitalChannelList->count() == 0) {
  582  digitalActiveButton->setChecked(
false);
  583  digitalActiveButton->setEnabled(
false);
  584  digitalChannelList->setEnabled(
false);
  585  digitalDirectionList->setEnabled(
false);
  588  auto* dev = deviceList->currentData().value<
DAQ::Device*>();
  589  auto chan = digitalChannelList->currentData().value<
DAQ::index_t>();
  593  digitalActiveButton->setEnabled(
true);
  594  digitalChannelList->setEnabled(
true);
  595  digitalDirectionList->setCurrentIndex(
  596  digitalDirectionList->findData(QVariant::fromValue(direction)));
  599  digitalActiveButton->setChecked(dev->getChannelActive(type, chan));
  605  return std::make_unique<SystemControl::Plugin>(ev_manager);
 virtual double getAnalogGain(ChannelType::type_t type, index_t index) const =0
virtual int setChannelActive(ChannelType::type_t type, index_t index, bool state)=0
void postEvent(Object *event)
void setParam(const std::string ¶m_name, const std::any ¶m_value)
std::any getParam(const std::string ¶m_name) const
void displayAnalogGroup()
Panel(QMainWindow *mw, Event::Manager *ev_manager)
void displayDigitalGroup()
constexpr std::string_view MODULE_NAME
std::array< std::string, 2 > get_default_units()
std::array< analog_range_t, 7 > get_default_ranges()
@ RT_DEVICE_UNPAUSE_EVENT
const int64_t SECONDS_TO_NANOSECONDS
std::unique_ptr< Widgets::Plugin > createRTXIPlugin(Event::Manager *ev_manager)
Widgets::FactoryMethods getFactories()
std::unique_ptr< Widgets::Component > createRTXIComponent(Widgets::Plugin *host_plugin)
Widgets::Panel * createRTXIPanel(QMainWindow *main_window, Event::Manager *ev_manager)