dRonin  adbada4
dRonin GCS
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Groups Pages
systemhealthgadgetwidget.cpp
Go to the documentation of this file.
1 
13 /*
14  * This program is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 3 of the License, or
17  * (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful, but
20  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
21  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  * for more details.
23  *
24  * You should have received a copy of the GNU General Public License along
25  * with this program; if not, see <http://www.gnu.org/licenses/>
26  */
27 
31 #include "systemalarms.h"
32 #include <coreplugin/icore.h>
33 #include <QDebug>
34 #include <QWhatsThis>
35 
36 /*
37  * Initialize the widget
38  */
40  : QGraphicsView(parent)
41 {
42  setMinimumSize(128, 64);
43  setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
44  setScene(new QGraphicsScene(this));
45 
46  m_renderer = new QSvgRenderer();
47  background = new QGraphicsSvgItem();
48  foreground = new QGraphicsSvgItem();
49  nolink = new QGraphicsSvgItem();
50 
51  paint();
52 
53  // Now connect the widget to the SystemAlarms UAVObject
54  ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
55  UAVObjectManager *objManager = pm->getObject<UAVObjectManager>();
56 
57  SystemAlarms *obj = SystemAlarms::GetInstance(objManager);
58  connect(obj, &UAVObject::objectUpdated, this, &SystemHealthGadgetWidget::updateAlarms);
59 
60  // Listen to autopilot connection events
61  TelemetryManager *telMngr = pm->getObject<TelemetryManager>();
62  connect(telMngr, &TelemetryManager::connected, this,
63  &SystemHealthGadgetWidget::onAutopilotConnect);
64  connect(telMngr, &TelemetryManager::disconnected, this,
65  &SystemHealthGadgetWidget::onAutopilotDisconnect);
66 
67  setToolTip(tr("Displays flight system errors. Click on an alarm for more information."));
68 }
69 
73 void SystemHealthGadgetWidget::onAutopilotConnect()
74 {
75  ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
76  UAVObjectManager *objManager = pm->getObject<UAVObjectManager>();
77  SystemAlarms *obj = SystemAlarms::GetInstance(objManager);
78 
79  if (obj->getIsPresentOnHardware()) {
80  nolink->setVisible(false);
81  } else {
82  nolink->setVisible(true);
83  }
84 }
85 
89 void SystemHealthGadgetWidget::onAutopilotDisconnect()
90 {
91  nolink->setVisible(true);
92 }
93 
94 void SystemHealthGadgetWidget::updateAlarms(UAVObject *systemAlarm)
95 {
96  static QList<QString> warningClean;
97  // This code does not know anything about alarms beforehand, and
98  // I found no efficient way to locate items inside the scene by
99  // name, so it's just as simple to reset the scene:
100  // And add the one with the right name.
101  QGraphicsScene *m_scene = scene();
102  foreach (QGraphicsItem *item, background->childItems()) {
103  m_scene->removeItem(item);
104  delete item; // removeItem does _not_ delete the item.
105  }
106 
107  UAVObjectField *field = systemAlarm->getField("Alarm");
108  Q_ASSERT(field);
109  if (field == NULL)
110  return;
111 
112  for (auto i = 0; i < field->getNumElements(); ++i) {
113  QString element = field->getElementNames()[i];
114  QString value = field->getValue(i).toString();
115  if (m_renderer->elementExists(element)) {
116  QMatrix blockMatrix = m_renderer->matrixForElement(element);
117  qreal startX = blockMatrix.mapRect(m_renderer->boundsOnElement(element)).x();
118  qreal startY = blockMatrix.mapRect(m_renderer->boundsOnElement(element)).y();
119  QString element2 = element + "-" + value;
120  if (m_renderer->elementExists(element2)) {
121  QGraphicsSvgItem *ind = new QGraphicsSvgItem();
122  ind->setSharedRenderer(m_renderer);
123  ind->setElementId(element2);
124  ind->setParentItem(background);
125  QTransform matrix;
126  matrix.translate(startX, startY);
127  ind->setTransform(matrix, false);
128  } else {
129  if ((value.compare("Uninitialised") != 0) && !warningClean.contains(element2)) {
130  qDebug() << "[SystemHealth] Warning: The SystemHealth SVG does not contain a "
131  "graphical element for the "
132  << element2 << " alarm.";
133  warningClean.append(element2);
134  }
135  }
136  } else if (!warningClean.contains(element)) {
137  qDebug() << "[SystemHealth] Warning: The SystemHealth SVG does not contain a graphical "
138  "element for the "
139  << element << " alarm.";
140  warningClean.append(element);
141  }
142  }
143 }
144 
146 {
147  // Do nothing
148 }
149 
151 {
152  if (QFile::exists(dfn)) {
153  m_renderer->load(dfn);
154  if (m_renderer->isValid()) {
155  fgenabled = false;
156  background->setSharedRenderer(m_renderer);
157  background->setElementId("background");
158 
159  if (m_renderer->elementExists("foreground")) {
160  foreground->setSharedRenderer(m_renderer);
161  foreground->setElementId("foreground");
162  foreground->setZValue(99);
163  fgenabled = true;
164  }
165  if (m_renderer->elementExists("nolink")) {
166  nolink->setSharedRenderer(m_renderer);
167  nolink->setElementId("nolink");
168  nolink->setZValue(100);
169  }
170 
171  QGraphicsScene *l_scene = scene();
172  l_scene->setSceneRect(background->boundingRect());
173  fitInView(background, Qt::KeepAspectRatio);
174 
175  // Check whether the autopilot is connected already, by the way:
176  ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
177  UAVObjectManager *objManager = pm->getObject<UAVObjectManager>();
178  TelemetryManager *telMngr = pm->getObject<TelemetryManager>();
179  if (telMngr->isConnected()) {
180  onAutopilotConnect();
181  SystemAlarms *obj = SystemAlarms::GetInstance(objManager);
182  updateAlarms(obj);
183  }
184  }
185  } else {
186  qDebug() << "SystemHealthGadget: no file";
187  }
188 }
189 
191 {
192  QGraphicsScene *l_scene = scene();
193  l_scene->clear();
194  l_scene->addItem(background);
195  l_scene->addItem(foreground);
196  l_scene->addItem(nolink);
197  update();
198 }
199 
200 void SystemHealthGadgetWidget::paintEvent(QPaintEvent *event)
201 {
202  // Skip painting until the dial file is loaded
203  if (!m_renderer->isValid()) {
204  qDebug() << "SystemHealthGadget: System file not loaded, not rendering";
205  return;
206  }
207  QGraphicsView::paintEvent(event);
208 }
209 
210 // This event enables the dial to be dynamically resized
211 // whenever the gadget is resized, taking advantage of the vector
212 // nature of SVG dials.
213 void SystemHealthGadgetWidget::resizeEvent(QResizeEvent *event)
214 {
215  Q_UNUSED(event);
216  fitInView(background, Qt::KeepAspectRatio);
217 }
218 
220 {
221  QGraphicsScene *graphicsScene = scene();
222  if (graphicsScene) {
223  QPoint point = event->pos();
224  bool haveAlarmItem = false;
225  foreach (QGraphicsItem *sceneItem, items(point)) {
226  QGraphicsSvgItem *clickedItem = dynamic_cast<QGraphicsSvgItem *>(sceneItem);
227 
228  if (clickedItem) {
229  if ((clickedItem != foreground) && (clickedItem != background)) {
230  // Clicked an actual alarm. We need to set haveAlarmItem to true
231  // as two of the items in this loop will always be foreground and
232  // background. Without this flag, at some point in the loop we
233  // would always call showAllAlarmDescriptions...
234  haveAlarmItem = true;
235  QString itemId = clickedItem->elementId();
236  if (itemId.contains("OK")) {
237  // No alarm set for this item
238  showAlarmDescriptionForItemId("AlarmOK", event->globalPos());
239  } else {
240  // Warning, error or critical alarm
241  showAlarmDescriptionForItemId(itemId, event->globalPos());
242  }
243  }
244  }
245  }
246  if (!haveAlarmItem) {
247  // Clicked foreground or background
248  showAllAlarmDescriptions(event->globalPos());
249  }
250  }
251 }
252 
253 void SystemHealthGadgetWidget::showAlarmDescriptionForItemId(const QString itemId,
254  const QPoint &location)
255 {
256  QFile alarmDescription(getAlarmDescriptionFileName(itemId));
257  if (alarmDescription.open(QIODevice::ReadOnly | QIODevice::Text)) {
258  QTextStream textStream(&alarmDescription);
259  QWhatsThis::showText(location, textStream.readAll());
260  }
261 }
262 
263 void SystemHealthGadgetWidget::showAllAlarmDescriptions(const QPoint &location)
264 {
265  QGraphicsScene *graphicsScene = scene();
266  if (graphicsScene) {
267  QString alarmsText;
268  // Loop through all items in the scene looking for svg items that represent alarms
269  foreach (QGraphicsItem *curItem, graphicsScene->items()) {
270  QGraphicsSvgItem *curSvgItem = dynamic_cast<QGraphicsSvgItem *>(curItem);
271  if (curSvgItem && (curSvgItem != foreground) && (curSvgItem != background)) {
272  QString elementId = curSvgItem->elementId();
273  if (!elementId.contains("OK")) {
274  // Found an alarm, get its corresponding alarm html file contents
275  // and append to the cumulative string for all alarms.
276  QFile alarmDescription(getAlarmDescriptionFileName(elementId));
277  if (alarmDescription.open(QIODevice::ReadOnly | QIODevice::Text)) {
278  QTextStream textStream(&alarmDescription);
279  alarmsText.append(textStream.readAll());
280  alarmDescription.close();
281  }
282  }
283  }
284  }
285  // Show alarms text if we have any
286  if (alarmsText.length() > 0) {
287  QWhatsThis::showText(location, alarmsText);
288  }
289  }
290 }
291 
292 QString SystemHealthGadgetWidget::getAlarmDescriptionFileName(const QString itemId)
293 {
294  QString alarmDescriptionFileName;
295  ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
296  UAVObjectManager *objManager = pm->getObject<UAVObjectManager>();
297  SystemAlarms::DataFields systemAlarmsData = SystemAlarms::GetInstance(objManager)->getData();
298  if (itemId.contains("SystemConfiguration-")) {
299  switch (systemAlarmsData.ConfigError) {
300  case SystemAlarms::CONFIGERROR_STABILIZATION:
301  alarmDescriptionFileName =
302  QString(":/systemhealth/html/SystemConfiguration-Error-Stabilization.html");
303  break;
304  case SystemAlarms::CONFIGERROR_NAVFILTER:
305  alarmDescriptionFileName =
306  QString(":/systemhealth/html/SystemConfiguration-Error-NavFilter.html");
307  break;
308  case SystemAlarms::CONFIGERROR_MULTIROTOR:
309  alarmDescriptionFileName =
310  QString(":/systemhealth/html/SystemConfiguration-Error-Multirotor.html");
311  break;
312  case SystemAlarms::CONFIGERROR_AUTOTUNE:
313  alarmDescriptionFileName =
314  QString(":/systemhealth/html/SystemConfiguration-Error-AutoTune.html");
315  break;
316  case SystemAlarms::CONFIGERROR_ALTITUDEHOLD:
317  alarmDescriptionFileName =
318  QString(":/systemhealth/html/SystemConfiguration-Error-AltitudeHold.html");
319  break;
320  case SystemAlarms::CONFIGERROR_POSITIONHOLD:
321  alarmDescriptionFileName =
322  QString(":/systemhealth/html/SystemConfiguration-Error-PositionHold.html");
323  break;
324  case SystemAlarms::CONFIGERROR_DUPLICATEPORTCFG:
325  alarmDescriptionFileName =
326  QString(":/systemhealth/html/SystemConfiguration-Error-DuplicatePortCfg.html");
327  break;
328  case SystemAlarms::CONFIGERROR_PATHPLANNER:
329  alarmDescriptionFileName =
330  QString(":/systemhealth/html/SystemConfiguration-Error-PathPlanner.html");
331  break;
332  case SystemAlarms::CONFIGERROR_UNSAFETOARM:
333  alarmDescriptionFileName =
334  QString(":/systemhealth/html/SystemConfiguration-Error-UnsafeToArm.html");
335  break;
336  case SystemAlarms::CONFIGERROR_LQG:
337  alarmDescriptionFileName =
338  QString(":/systemhealth/html/SystemConfiguration-Error-LQG.html");
339  break;
340  case SystemAlarms::CONFIGERROR_UNDEFINED:
341  alarmDescriptionFileName =
342  QString(":/systemhealth/html/SystemConfiguration-Undefined.html");
343  break;
344  default:
345  alarmDescriptionFileName = QString(":/systemhealth/html/SystemConfiguration-None.html");
346  break;
347  }
348  } else if (itemId.contains("ManualControl-")) {
349  switch (systemAlarmsData.ManualControl) {
350  case SystemAlarms::MANUALCONTROL_SETTINGS:
351  alarmDescriptionFileName =
352  QString(":/systemhealth/html/ManualControl-Critical-Settings.html");
353  break;
354  case SystemAlarms::MANUALCONTROL_NORX:
355  alarmDescriptionFileName =
356  QString(":/systemhealth/html/ManualControl-Warning-NoRx.html");
357  break;
358  case SystemAlarms::MANUALCONTROL_ACCESSORY:
359  alarmDescriptionFileName =
360  QString(":/systemhealth/html/ManualControl-Warning-Accessory.html");
361  break;
362  case SystemAlarms::MANUALCONTROL_ALTITUDEHOLD:
363  alarmDescriptionFileName =
364  QString(":/systemhealth/html/ManualControl-Error-AltitudeHold.html");
365  break;
366  case SystemAlarms::MANUALCONTROL_PATHFOLLOWER:
367  alarmDescriptionFileName =
368  QString(":/systemhealth/html/ManualControl-Critical-PathFollower.html");
369  break;
370  case SystemAlarms::MANUALCONTROL_CHANNELCONFIGURATION:
371  alarmDescriptionFileName =
372  QString(":/systemhealth/html/ManualControl-Warning-ChannelConfiguration.html");
373  break;
374  case SystemAlarms::MANUALCONTROL_UNDEFINED:
375  alarmDescriptionFileName = QString(":/systemhealth/html/ManualControl-Undefined.html");
376  break;
377  default:
378  alarmDescriptionFileName = QString(":/systemhealth/html/ManualControl-None.html");
379  break;
380  }
381  } else if (itemId.contains("StateEstimation-") || itemId.contains("Attitude-")) {
382  switch (systemAlarmsData.StateEstimation) {
383  case SystemAlarms::STATEESTIMATION_GYROQUEUENOTUPDATING:
384  alarmDescriptionFileName =
385  QString(":/systemhealth/html/StateEstimation-Gyro-Queue-Not-Updating.html");
386  break;
387  case SystemAlarms::STATEESTIMATION_ACCELEROMETERQUEUENOTUPDATING:
388  alarmDescriptionFileName = QString(
389  ":/systemhealth/html/StateEstimation-Accelerometer-Queue-Not-Updating.html");
390  break;
391  case SystemAlarms::STATEESTIMATION_NOGPS:
392  alarmDescriptionFileName = QString(":/systemhealth/html/StateEstimation-No-GPS.html");
393  break;
394  case SystemAlarms::STATEESTIMATION_NOMAGNETOMETER:
395  alarmDescriptionFileName =
396  QString(":/systemhealth/html/StateEstimation-No-Magnetometer.html");
397  break;
398  case SystemAlarms::STATEESTIMATION_NOBAROMETER:
399  alarmDescriptionFileName =
400  QString(":/systemhealth/html/StateEstimation-No-Barometer.html");
401  break;
402  case SystemAlarms::STATEESTIMATION_TOOFEWSATELLITES:
403  alarmDescriptionFileName =
404  QString(":/systemhealth/html/StateEstimation-Too-Few-Satellites.html");
405  break;
406  case SystemAlarms::STATEESTIMATION_PDOPTOOHIGH:
407  alarmDescriptionFileName =
408  QString(":/systemhealth/html/StateEstimation-PDOP-Too-High.html");
409  break;
410  case SystemAlarms::STATEESTIMATION_UNDEFINED:
411  alarmDescriptionFileName =
412  QString(":/systemhealth/html/StateEstimation-Undefined.html");
413  break;
414  case SystemAlarms::STATEESTIMATION_NOHOME:
415  alarmDescriptionFileName = QString(":/systemhealth/html/StateEstimation-NoHome.html");
416  break;
417  default:
418  alarmDescriptionFileName = QString(":/systemhealth/html/StateEstimation-None.html");
419  break;
420  }
421  } else {
422  alarmDescriptionFileName = QString(":/systemhealth/html/" + itemId + ".html");
423  }
424  return alarmDescriptionFileName;
425 }
void paintEvent(QPaintEvent *event)
void resizeEvent(QResizeEvent *event)
Core plugin system that manages the plugins, their life cycle and their registered objects...
Definition: pluginmanager.h:53
QVariant getValue(int index=0) const
int getNumElements() const
for i
Definition: OPPlots.m:140
void objectUpdated(UAVObject *obj)
Signal sent whenever any field of the object is updated.
UAVObjectField * getField(const QString &name)
Definition: uavobject.cpp:236
QStringList getElementNames() const
x
Definition: OPPlots.m:100
SystemHealthGadgetWidget(QWidget *parent=nullptr)
void mousePressEvent(QMouseEvent *event)
y
Definition: OPPlots.m:101