dRonin  adbada4
dRonin GCS
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Groups Pages
configmodulewidget.cpp
Go to the documentation of this file.
1 
12 /*
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 3 of the License, or
16  * (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful, but
19  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
20  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21  * for more details.
22  *
23  * You should have received a copy of the GNU General Public License along
24  * with this program; if not, see <http://www.gnu.org/licenses/>
25  */
26 
27 #include "configmodulewidget.h"
28 
29 #include <coreplugin/iboardtype.h>
31 
32 #include "airspeedsettings.h"
33 #include "flightbatterysettings.h"
34 #include "hottsettings.h"
35 #include "flightbatterystate.h"
36 #include "geofencesettings.h"
37 #include "modulesettings.h"
38 #include "vibrationanalysissettings.h"
39 #include "taskinfo.h"
40 #include "loggingsettings.h"
41 #include "rgbledsettings.h"
42 
43 #include <QColorDialog>
44 #include <QDebug>
45 #include <QPointer>
46 
48  : ConfigTaskWidget(parent)
49 {
50  ui = new Ui::Modules();
51  ui->setupUi(this);
52 
53  // override anything set in .ui file by Qt Designer
54  ui->moduleTab->setCurrentIndex(0);
55 
56  connect(this, &ConfigTaskWidget::autoPilotConnected, this, &ConfigModuleWidget::recheckTabs);
57 
58  // Populate UAVO strings
59  AirspeedSettings *airspeedSettings;
60  airspeedSettings = AirspeedSettings::GetInstance(getObjectManager());
61 
62  // Don't allow these to be changed here, only in the respective tabs.
63  ui->cbAutotune->setDisabled(true);
64  ui->cbTxPid->setDisabled(true);
65  ui->cbCameraStab->setDisabled(true);
66 
67  // This will be un-hidden as required by boards, but keep the unformatted string for later
68  ui->lblOnBoardLeds->setVisible(false);
69  ui->lblOnBoardLeds->setProperty("format", QVariant::fromValue(ui->lblOnBoardLeds->text()));
70 
71  // Connect auto-cell detection logic
72  connect(ui->gbAutoCellDetection, &QGroupBox::toggled, this,
73  &ConfigModuleWidget::autoCellDetectionToggled);
74  connect(ui->sbMaxCellVoltage, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this,
75  &ConfigModuleWidget::maxCellVoltageChanged);
76 
77  // Connect the voltage and current checkboxes, such that the ADC pins are toggled and vice versa
78  connect(ui->gb_measureVoltage, &QGroupBox::toggled, this,
79  &ConfigModuleWidget::toggleBatteryMonitoringPin);
80  connect(ui->gb_measureCurrent, &QGroupBox::toggled, this,
81  &ConfigModuleWidget::toggleBatteryMonitoringPin);
82  connect(ui->cbVoltagePin, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
83  &ConfigModuleWidget::toggleBatteryMonitoringGb);
84  connect(ui->cbCurrentPin, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
85  &ConfigModuleWidget::toggleBatteryMonitoringGb);
86 
87  // connect the voltage ratio and factor boxes so they update each other when edited
88  connect(ui->sb_voltageRatio, &QAbstractSpinBox::editingFinished, this,
89  &ConfigModuleWidget::updateVoltageRatio);
90  connect(ui->sb_voltageFactor, &QAbstractSpinBox::editingFinished, this,
91  &ConfigModuleWidget::updateVoltageFactor);
92  connect(FlightBatterySettings::GetInstance(getObjectManager()),
93  &FlightBatterySettings::SensorCalibrationFactor_VoltageChanged, this,
94  &ConfigModuleWidget::updateVoltageFactorFromUavo);
95 
96  // Connect Airspeed Settings
97  connect(airspeedSettings, &UAVObject::objectUpdated, this,
98  &ConfigModuleWidget::updateAirspeedGroupbox);
99  connect(ui->gb_airspeedGPS, &QGroupBox::clicked, this,
100  &ConfigModuleWidget::enableAirspeedTypeGPS);
101  connect(ui->gb_airspeedPitot, &QGroupBox::clicked, this,
102  &ConfigModuleWidget::enableAirspeedTypePitot);
103 
104  setupLedTab();
105 
107  this, &ConfigModuleWidget::updateAnnunciatorTab);
108  updateAnnunciatorTab();
109 
110  enableBatteryTab(false);
111  enableAirspeedTab(false);
112  enableHoTTTelemetryTab(false);
113  enableGpsTab(false);
114  enableLoggingTab(false);
115 
116  // Load UAVObjects to widget relations from UI file
117  // using objrelation dynamic property
118  autoLoadWidgets();
119 
120  // Refresh widget contents
122 
123  // Prevent mouse wheel from changing values
125 
131 }
132 
134 {
135  delete ui;
136 }
137 
138 void ConfigModuleWidget::resizeEvent(QResizeEvent *event)
139 {
140  QWidget::resizeEvent(event);
141 }
142 
144 {
145  Q_UNUSED(enable);
146 }
147 
149 void ConfigModuleWidget::recheckTabs()
150 {
151  // clear checkboxes in-case taskinfo object doesn't exist (it will look like the last connected
152  // board's modules are still enabled)
153  bool dirty = isDirty();
154  ui->cbComBridge->setChecked(false);
155  ui->cbGPS->setChecked(false);
156  ui->cbUavoMavlink->setChecked(false);
157  ui->cbUAVOHottBridge->setChecked(false);
158  ui->cbUAVOLighttelemetryBridge->setChecked(false);
159  ui->cbUAVOFrskyBridge->setChecked(false);
160  ui->cbUAVOMSPBridge->setChecked(false);
161  ui->cbUAVOFrSkySPortBridge->setChecked(false);
162  setDirty(dirty);
163 
164  UAVObject *obj;
165 
167  connect(obj, QOverload<UAVObject *, bool>::of(&UAVObject::transactionCompleted), this,
168  &ConfigModuleWidget::objectUpdated, Qt::UniqueConnection);
169  obj->requestUpdate();
170 
172  connect(obj, QOverload<UAVObject *, bool>::of(&UAVObject::transactionCompleted), this,
173  &ConfigModuleWidget::objectUpdated, Qt::UniqueConnection);
174  obj->requestUpdate();
175 
177  connect(obj, QOverload<UAVObject *, bool>::of(&UAVObject::transactionCompleted), this,
178  &ConfigModuleWidget::objectUpdated, Qt::UniqueConnection);
179 
180  TaskInfo *taskInfo = qobject_cast<TaskInfo *>(getObjectManager()->getObject(TaskInfo::NAME));
181  if (taskInfo && taskInfo->getIsPresentOnHardware()) {
182  connect(taskInfo, QOverload<UAVObject *, bool>::of(&UAVObject::transactionCompleted), obj,
183  &UAVObject::requestUpdate, Qt::UniqueConnection);
184  taskInfo->requestUpdate();
185  } else {
186  obj->requestUpdate();
187  }
188 
190  connect(obj, QOverload<UAVObject *, bool>::of(&UAVObject::transactionCompleted), this,
191  &ConfigModuleWidget::objectUpdated, Qt::UniqueConnection);
192  obj->requestUpdate();
193 
194  // This requires re-evaluation so that board connection doesn't re-enable
195  // the fields. TODO: use new ConfigTaskWidget::setWidgetEnabled function
196  ui->cbAutotune->setDisabled(true);
197  ui->cbTxPid->setDisabled(true);
198  ui->cbCameraStab->setDisabled(true);
199 }
200 
202 void ConfigModuleWidget::objectUpdated(UAVObject *obj, bool success)
203 {
204  if (!obj)
205  return;
206 
207  ModuleSettings *moduleSettings =
208  qobject_cast<ModuleSettings *>(getObjectManager()->getObject(ModuleSettings::NAME));
209  Q_ASSERT(moduleSettings);
210  TaskInfo *taskInfo = qobject_cast<TaskInfo *>(getObjectManager()->getObject(TaskInfo::NAME));
211  bool enableHott = (taskInfo && taskInfo->getIsPresentOnHardware())
212  ? (taskInfo->getRunning_UAVOHoTTBridge() == TaskInfo::RUNNING_TRUE)
213  : true;
214  bool enableGps = (taskInfo && taskInfo->getIsPresentOnHardware())
215  ? (taskInfo->getRunning_GPS() == TaskInfo::RUNNING_TRUE)
216  : true;
217  enableGps &= moduleSettings->getIsPresentOnHardware();
218 
219  enableGpsTab(enableGps);
220 
221  QString objName = obj->getName();
222  if (objName.compare(AirspeedSettings::NAME) == 0) {
223  enableAirspeedTab(success
224  && moduleSettings->getAdminState_Airspeed()
225  == ModuleSettings::ADMINSTATE_ENABLED);
226  } else if (objName.compare(FlightBatterySettings::NAME) == 0) {
227  enableBatteryTab(success
228  && moduleSettings->getAdminState_Battery()
229  == ModuleSettings::ADMINSTATE_ENABLED);
230  refreshAdcNames();
231  } else if (objName.compare(HoTTSettings::NAME) == 0) {
232  enableHoTTTelemetryTab(success && enableHott);
233  } else if (objName.compare(LoggingSettings::NAME) == 0) {
234  enableLoggingTab(success
235  && moduleSettings->getAdminState_Logging()
236  == ModuleSettings::ADMINSTATE_ENABLED);
237  }
238 }
239 
243 void ConfigModuleWidget::toggleBatteryMonitoringPin()
244 {
245  if (!ui->gb_measureVoltage->isChecked())
246  ui->cbVoltagePin->setCurrentIndex(ui->cbVoltagePin->findText("NONE"));
247 
248  if (!ui->gb_measureCurrent->isChecked())
249  ui->cbCurrentPin->setCurrentIndex(ui->cbCurrentPin->findText("NONE"));
250 }
251 
255 void ConfigModuleWidget::toggleBatteryMonitoringGb()
256 {
257  if (ui->cbVoltagePin->currentText().compare("NONE") != 0)
258  ui->gb_measureVoltage->setChecked(true);
259  else
260  ui->gb_measureVoltage->setChecked(false);
261 
262  if (ui->cbCurrentPin->currentText().compare("NONE") != 0)
263  ui->gb_measureCurrent->setChecked(true);
264  else
265  ui->gb_measureCurrent->setChecked(false);
266 }
267 
272 void ConfigModuleWidget::updateAirspeedGroupbox(UAVObject *obj)
273 {
274  Q_UNUSED(obj);
275 
276  AirspeedSettings *airspeedSettings;
277  airspeedSettings = AirspeedSettings::GetInstance(getObjectManager());
278  AirspeedSettings::DataFields airspeedSettingsData;
279  airspeedSettingsData = airspeedSettings->getData();
280 
281  ui->gb_airspeedGPS->setChecked(false);
282  ui->gb_airspeedPitot->setChecked(false);
283 
284  if (airspeedSettingsData.AirspeedSensorType == AirspeedSettings::AIRSPEEDSENSORTYPE_GPSONLY) {
285  ui->gb_airspeedGPS->setChecked(true);
286  } else {
287  ui->gb_airspeedPitot->setChecked(true);
288  }
289 }
290 
295 void ConfigModuleWidget::enableAirspeedTypeGPS(bool checked)
296 {
297  if (checked) {
298  AirspeedSettings *airspeedSettings;
299  airspeedSettings = AirspeedSettings::GetInstance(getObjectManager());
300  AirspeedSettings::DataFields airspeedSettingsData;
301  airspeedSettingsData = airspeedSettings->getData();
302  airspeedSettingsData.AirspeedSensorType = AirspeedSettings::AIRSPEEDSENSORTYPE_GPSONLY;
303  airspeedSettings->setData(airspeedSettingsData);
304  }
305 }
306 
311 void ConfigModuleWidget::enableAirspeedTypePitot(bool checked)
312 {
313  if (checked) {
314  AirspeedSettings *airspeedSettings;
315  airspeedSettings = AirspeedSettings::GetInstance(getObjectManager());
316  AirspeedSettings::DataFields airspeedSettingsData;
317  airspeedSettingsData = airspeedSettings->getData();
318  airspeedSettingsData.AirspeedSensorType =
319  AirspeedSettings::AIRSPEEDSENSORTYPE_EAGLETREEAIRSPEEDV3;
320  airspeedSettings->setData(airspeedSettingsData);
321  }
322 }
323 
325 void ConfigModuleWidget::enableBatteryTab(bool enabled)
326 {
327  int idx = ui->moduleTab->indexOf(ui->tabBattery);
328  ui->moduleTab->setTabEnabled(idx, enabled);
329 }
330 
332 void ConfigModuleWidget::enableAirspeedTab(bool enabled)
333 {
334  int idx = ui->moduleTab->indexOf(ui->tabAirspeed);
335  ui->moduleTab->setTabEnabled(idx, enabled);
336 }
337 
339 void ConfigModuleWidget::enableHoTTTelemetryTab(bool enabled)
340 {
341  int idx = ui->moduleTab->indexOf(ui->tabHoTTTelemetry);
342  ui->moduleTab->setTabEnabled(idx, enabled);
343 }
344 
346 void ConfigModuleWidget::enableGpsTab(bool enabled)
347 {
348  int idx = ui->moduleTab->indexOf(ui->tabGPS);
349  ui->moduleTab->setTabEnabled(idx, enabled);
350 }
351 
353 void ConfigModuleWidget::enableLoggingTab(bool enabled)
354 {
355  int idx = ui->moduleTab->indexOf(ui->tabLogging);
356  ui->moduleTab->setTabEnabled(idx, enabled);
357 }
358 
360 void ConfigModuleWidget::refreshAdcNames(void)
361 {
362  QStringList names;
364  if (board)
365  names = board->getAdcNames();
366  if (names.isEmpty())
367  return;
368 
369  for (int i = 0; i <= 8; i++) {
370  QString name;
371  if (i < names.length())
372  name = names[i] + QString(" (ADC%1)").arg(i);
373  else
374  name = QString("N/A (ADC%1)").arg(i);
375 
376  if (i < ui->cbVoltagePin->count())
377  ui->cbVoltagePin->setItemText(i, name);
378  if (i < ui->cbCurrentPin->count())
379  ui->cbCurrentPin->setItemText(i, name);
380  }
381 }
382 
383 void ConfigModuleWidget::updateVoltageRatio()
384 {
385  ui->sb_voltageFactor->setValue(1000.0 / ui->sb_voltageRatio->value());
386 }
387 
388 void ConfigModuleWidget::updateVoltageFactor()
389 {
390  ui->sb_voltageRatio->setValue(1000.0 / ui->sb_voltageFactor->value());
391 }
392 
393 void ConfigModuleWidget::updateVoltageFactorFromUavo(float value)
394 {
395  ui->sb_voltageRatio->setValue(1000.0 / (double)value);
396 }
397 
398 void ConfigModuleWidget::autoCellDetectionToggled(bool checked)
399 {
400  ui->sbMaxCellVoltage->setEnabled(checked);
401  ui->lblMaxCellVoltage->setEnabled(checked);
402  ui->sb_numBatteryCells->setEnabled(!checked);
403  ui->lblNumBatteryCells->setEnabled(!checked);
404  if (checked) {
405  if (ui->sbMaxCellVoltage->property("ValueBackup").isValid())
406  ui->sbMaxCellVoltage->setValue(
407  ui->sbMaxCellVoltage->property("ValueBackup").toDouble());
408  else
409  ui->sbMaxCellVoltage->setValue(
410  4.2); // TODO: set this to default UAVO val instead of hardcoding?
411  } else {
412  ui->sbMaxCellVoltage->setProperty("ValueBackup", ui->sbMaxCellVoltage->value());
413  ui->sbMaxCellVoltage->setValue(0.0);
414  }
415 }
416 
417 void ConfigModuleWidget::maxCellVoltageChanged(double value)
418 {
419  if (value > 0.0) {
420  if (!ui->gbAutoCellDetection->isChecked())
421  ui->gbAutoCellDetection->setChecked(true);
422  } else if (ui->gbAutoCellDetection->isChecked()) {
423  ui->gbAutoCellDetection->setChecked(false);
424  }
425 }
426 
427 void ConfigModuleWidget::setupLedTab()
428 {
429  QPointer<UAVObjectManager> objMgr = getObjectManager();
430  if (!objMgr) // hope it can only be destructed in this thread
431  return;
432 
433  auto obj = qobject_cast<UAVDataObject *>(objMgr->getObject("RGBLEDSettings"));
434  if (!obj)
435  return;
436 
437  connect(obj, &UAVObject::objectUpdated, this, &ConfigModuleWidget::ledTabUpdate);
438  connect(ui->btnLEDDefaultColor, &QPushButton::clicked, this,
439  &ConfigModuleWidget::ledTabSetColor);
440  connect(ui->btnLEDRange1Begin, &QPushButton::clicked, this,
441  &ConfigModuleWidget::ledTabSetColor);
442  connect(ui->btnLEDRange1End, &QPushButton::clicked, this, &ConfigModuleWidget::ledTabSetColor);
443  connect(obj,
444  static_cast<void (UAVDataObject::*)(bool)>(&UAVDataObject::presentOnHardwareChanged),
445  [=](bool enable) { tabEnable(ui->tabLED, enable); });
446  tabEnable(ui->tabLED, obj->getIsPresentOnHardware());
447 }
448 
449 void ConfigModuleWidget::ledTabUpdate(UAVObject *obj)
450 {
451  auto rgb = qobject_cast<RGBLEDSettings *>(obj);
452  if (!rgb) {
453  Q_ASSERT(false);
454  qWarning() << "Invalid object!";
455  return;
456  }
457 
458  auto data = rgb->getData();
459 
460  ui->lblLEDDefaultColor->setStyleSheet(QString("background: rgb(%0, %1, %2);")
461  .arg(data.DefaultColor[0])
462  .arg(data.DefaultColor[1])
463  .arg(data.DefaultColor[2]));
464  ui->lblLEDRange1Begin->setStyleSheet(QString("background: rgb(%0, %1, %2);")
465  .arg(data.RangeBaseColor[0])
466  .arg(data.RangeBaseColor[1])
467  .arg(data.RangeBaseColor[2]));
468  ui->lblLEDRange1End->setStyleSheet(QString("background: rgb(%0, %1, %2);")
469  .arg(data.RangeEndColor[0])
470  .arg(data.RangeEndColor[1])
471  .arg(data.RangeEndColor[2]));
472 }
473 
474 void ConfigModuleWidget::ledTabSetColor()
475 {
476  QPointer<QPushButton> btn = qobject_cast<QPushButton *>(sender());
477  if (!btn)
478  return;
479 
480  QPointer<UAVObjectManager> objMgr = getObjectManager();
481  if (!objMgr)
482  return;
483 
484  auto obj = objMgr->getObject("RGBLEDSettings");
485  if (!obj)
486  return;
487  auto field = obj->getField(btn->property("fieldname").toString());
488  if (!field)
489  return;
490 
491  const QColor initial(field->getValue(0).toInt(), field->getValue(1).toInt(),
492  field->getValue(2).toInt());
493  QColorDialog picker(initial, this);
494  picker.raise();
495  if (picker.exec() != QDialog::Accepted)
496  return;
497 
498  const QColor &col = picker.selectedColor();
499  field->setValue(col.red(), 0);
500  field->setValue(col.green(), 1);
501  field->setValue(col.blue(), 2);
502 
503  QPointer<QLabel> lbl(ui->tabLED->findChild<QLabel *>(btn->objectName().replace("btn", "lbl")));
504  if (!lbl)
505  return;
506 
507  lbl->setStyleSheet(
508  QString("background: rgb(%0, %1, %2);").arg(col.red()).arg(col.green()).arg(col.blue()));
509 }
510 
511 void ConfigModuleWidget::tabEnable(QWidget *tab, bool enable)
512 {
513  int idx = ui->moduleTab->indexOf(tab);
514  if (ui->moduleTab->currentIndex() == idx)
515  ui->moduleTab->setCurrentIndex(0);
516  if (idx >= 0)
517  ui->moduleTab->setTabEnabled(idx, enable);
518 }
519 
523 void ConfigModuleWidget::updateAnnunciatorTab()
524 {
525  struct AnuncType {
527  QString widgetName;
528  };
529  static const std::vector<AnuncType> annuncTypes = {
535  };
536  static const std::vector<QString> widgets = {
537  "lbl%0Anytime",
538  "cbx%0Anytime",
539  "lbl%0Armed",
540  "cbx%0Armed",
541  };
542 
543  auto board = utilMngr->getBoardType();
544  if (!board)
545  return;
546 
547  for (const auto &annunc : annuncTypes) {
548  bool have = board->hasAnnunciator(annunc.type);
549 
550  for (const auto &name : widgets) {
551  const auto widget = ui->tabAnnunc->findChild<QWidget *>(name.arg(annunc.widgetName));
552  if (widget)
553  widget->setVisible(have);
554  else
555  qWarning() << "Failed to get widget:" << name.arg(annunc.widgetName);
556  }
557  }
558 
559  // tell the user if some of the LEDs are on the PCB
560  const int onBoard = board->onBoardRgbLeds();
561  ui->lblOnBoardLeds->setVisible(onBoard > 0);
562  if (onBoard > 0) {
563  ui->lblOnBoardLeds->setText(
564  ui->lblOnBoardLeds->property("format").toString().arg(onBoard));
565  }
566 }
567 
void setDirty(bool value)
virtual int onBoardRgbLeds() const
Number of RGB LEDs located on the board The first n LEDs in the chain will apply to on-board LEDs rat...
Definition: iboardtype.h:266
UAVObjectUtilManager * utilMngr
virtual QStringList getAdcNames()
Definition: iboardtype.h:237
void setNotMandatory(QString object)
void requestUpdate()
Definition: uavobject.cpp:163
void autoPilotConnected()
for i
Definition: OPPlots.m:140
ConfigModuleWidget(QWidget *parent=nullptr)
virtual bool hasAnnunciator(AnnunciatorType annunc)
Check if the board has the given type of annunciator.
Definition: iboardtype.h:258
void objectUpdated(UAVObject *obj)
Signal sent whenever any field of the object is updated.
DataFields data
void transactionCompleted(UAVObject *obj, bool success)
transactionCompleted. Triggered by a call to emitTransactionCompleted - done in telemetry.cpp whenever a transaction finishes.
UAVObjectField * getField(const QString &name)
Definition: uavobject.cpp:236
void resizeEvent(QResizeEvent *event)
() NAME()
QString getName()
Definition: uavobject.cpp:131
virtual void refreshWidgetsValues(UAVObject *obj=NULL)
UAVObject * getObject(const QString &name, quint32 instId=0)
Core::IBoardType * getBoardType()
Get the IBoardType corresponding to the connected board.
Configure the optional modules.
UAVObjectManager * getObjectManager()
ConfigTaskWidget::getObjectManager Utility function to get a pointer to the object manager...
void presentOnHardwareChanged(UAVDataObject *)
virtual void enableControls(bool enable)