-
Notifications
You must be signed in to change notification settings - Fork 10
/
monitoringwidget.cpp
775 lines (591 loc) · 29.4 KB
/
monitoringwidget.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
/*
This file is part of the Automon Project (OBD Diagnostics) - http://www.automon.io/
Source Repository: https://github.com/donaloconnor/automon/
Copyright (c) 2015, Donal O'Connor <[email protected]>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <QLabel>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QTableWidget>
#include <QList>
#include <QPushButton>
#include <QComboBox>
#include <QColor>
#include <QRgb>
#include "monitoringwidget.h"
#include "rule.h"
#include "automonapp.h"
MonitoringWidget::MonitoringWidget(Automon * kernel, QWidget * parent)
: QWidget(parent), m_kernel(kernel)
{
/* Create all our layouts managers */
m_mainLayout = new QHBoxLayout(this);
m_verticalLayout = new QVBoxLayout();
m_mainSensorLayout = new QHBoxLayout();
m_sensorLeftLayout = new QVBoxLayout();
m_sensorRightLayout = new QVBoxLayout();
m_sensorAddRemoveButtonsLayout = new QVBoxLayout();
m_mainRuleLayout = new QHBoxLayout();
m_ruleLeftLayout = new QVBoxLayout();
m_ruleRightLayout = new QVBoxLayout();
m_ruleAddRemoveButtonsLayout = new QVBoxLayout();
m_sensorComboboxes = new QHBoxLayout();
m_ruleComboboxes = new QHBoxLayout();
m_sensorComboboxes->setAlignment(Qt::AlignTop);
/* This variable is used by this widget to determine if we've started monitoring */
m_isMonitoring = false;
/* Create our tables. The sensor table list and the rules list */
m_sensorsList = new QTableWidget();
m_addedRulesList = new QTableWidget();
/* Set the stylesheets for our tables */
m_sensorsList->setStyleSheet("color:beige");
m_addedRulesList->setStyleSheet("color:beige");
/* Set some behaviours, to avoid multi selection and make it row selection */
m_sensorsList->setSelectionBehavior(QAbstractItemView::SelectRows);
m_addedRulesList->setSelectionBehavior(QAbstractItemView::SelectRows);
m_sensorsList->setSelectionMode(QAbstractItemView::SingleSelection);
m_addedRulesList->setSelectionMode(QAbstractItemView::SingleSelection);
/* Create our push buttons viewable on screen */
m_addRuleButton = new QPushButton(tr("Add Rule"));
m_removeRuleButton = new QPushButton(tr("Remove Rule"));
m_addSensorButton = new QPushButton(tr("Add Sensor"));
m_removeSensorButton = new QPushButton(tr("Remove Sensor"));
m_ruleEditorButton = new QPushButton(tr("Rule Editor"));
m_startStopMonitoring = new QPushButton(tr("Start Monitoring"));
/* Connect the clicked signal of push buttons to their appropiate slots */
connect(m_addSensorButton, SIGNAL(clicked()), this, SLOT(addSensor()));
connect(m_removeSensorButton, SIGNAL(clicked()), this, SLOT(removeSensor()));
connect(m_startStopMonitoring, SIGNAL(clicked()), this, SLOT(startMonitoring()));
connect(m_ruleEditorButton, SIGNAL(clicked()), this, SLOT(displayRuleEditor()));
connect(m_addRuleButton, SIGNAL(clicked()), this, SLOT(addRule()));
connect(m_removeRuleButton, SIGNAL(clicked()), this, SLOT(removeRule()));
/* Create a combo for the available rules list */
m_availableRulesList = new QComboBox();
/* Populate the available rules in the combo box */
populateRulesAvailableList();
/* Create our sensor combo that will hold available sensors */
m_sensorComboList = new QComboBox();
/* Populate the sensor's combo with all SUPPORTED sensors for the current vehicle */
populateSensorCombo();
/* Create a combo to select the frequency update. This specifies how often a sensor gets access to the ELM */
m_frequencyUpdateList = new QComboBox();
/* Populate the 1 - 30 Hz frequencies in the combo box */
populateFrequencyUpdateList();
/* Create our header and make font bigger with color green */
m_header = new QLabel(tr("Monitoring"));
m_header->setStyleSheet("color: #ace413; font-size:25px");
/* Add a layout to our main layout */
m_mainLayout->addLayout(m_verticalLayout);
/* Add the header text to the layout */
m_verticalLayout->addWidget(m_header);
/* Create a welcome/introduction label and add this to the layout next */
QLabel * welcome = new QLabel(tr("Welcome to Monitoring. Simply add which sensors, their frequency of update and what rules you want to apply."));
m_verticalLayout->addWidget(welcome);
/* Create new sensor label, and frequency labels setting their fixed widths */
QLabel * addSensorLabel = new QLabel(tr("Add Sensor: "));
addSensorLabel->setFixedWidth(80);
QLabel * updateFrequencyLabel = new QLabel(tr("Update Frequency: "));
updateFrequencyLabel->setFixedWidth(120);
/* Create the add Rule label and set it's fixed width */
QLabel * addRuleLabel = new QLabel(tr("Add Rule: "));
addRuleLabel->setFixedWidth(80);
/* Set the table width using the size hints of the other widgets we we make table full width */
m_tableWidth = QSize(addSensorLabel->sizeHint()+m_sensorComboList->sizeHint()+updateFrequencyLabel->sizeHint()+m_frequencyUpdateList->sizeHint()).width();
/* Set alignment of layouts */
m_verticalLayout->setAlignment(Qt::AlignTop);
m_mainLayout->setAlignment(Qt::AlignTop);
/* Set up more Layouts */
m_verticalLayout->addLayout(m_mainSensorLayout);
m_verticalLayout->addLayout(m_mainRuleLayout);
m_mainSensorLayout->addLayout(m_sensorLeftLayout);
m_mainSensorLayout->addLayout(m_sensorRightLayout);
m_mainRuleLayout->addLayout(m_ruleLeftLayout);
m_mainRuleLayout->addLayout(m_ruleRightLayout);
m_sensorLeftLayout->addLayout(m_sensorComboboxes);
m_sensorRightLayout->addLayout(m_sensorAddRemoveButtonsLayout);
m_ruleLeftLayout->addLayout(m_ruleComboboxes);
m_ruleRightLayout->addLayout(m_ruleAddRemoveButtonsLayout);
/* Add widgets to their associated layouts */
m_sensorComboboxes->addWidget(addSensorLabel);
m_sensorComboboxes->addWidget(m_sensorComboList);
m_sensorComboboxes->addWidget(updateFrequencyLabel);
m_sensorComboboxes->addWidget(m_frequencyUpdateList);
m_sensorAddRemoveButtonsLayout->addWidget(m_addSensorButton);
m_sensorAddRemoveButtonsLayout->addWidget(m_removeSensorButton);
m_sensorAddRemoveButtonsLayout->addWidget(m_startStopMonitoring);
m_ruleComboboxes->addWidget(addRuleLabel);
m_ruleComboboxes->addWidget(m_availableRulesList);
m_ruleAddRemoveButtonsLayout->addWidget(m_addRuleButton);
m_ruleAddRemoveButtonsLayout->addWidget(m_removeRuleButton);
m_ruleAddRemoveButtonsLayout->addWidget(m_ruleEditorButton);
m_ruleLeftLayout->addWidget(m_addedRulesList);
m_sensorLeftLayout->addWidget(m_sensorsList);
/* Set the main layout */
setLayout(m_mainLayout);
}
void MonitoringWidget::populateRulesAvailableList()
{
/*
This method is responsible for adding a list of available rules to the combo box for
available rules
*/
/* We may be calling this more than once, if we use rule editor so clear to prevent appending too many */
m_availableRulesList->clear();
/* Get available rules from the kernel */
QStringList rulesAvailable = m_kernel->getRuleList();
if (rulesAvailable.size() == 0)
{
/* If no rules available, add this to the rules List */
m_availableRulesList->addItem(tr("No Rules Available!"), 0);
return;
}
/*
Otherwise, for each rule, add it to the combo box, making the human readable version for the text, and the normal
representation for the value
*/
for (int i = 0; i < rulesAvailable.size(); i++)
m_availableRulesList->addItem(m_kernel->convertRuleToEnglish(rulesAvailable.at(i)), rulesAvailable.at(i));
}
void MonitoringWidget::addRule()
{
/* This is the slot that is called when the user clicks to add a rule */
/* The rule's table will only ever have a single column, the rule in human readable format */
m_addedRulesList->setColumnCount(1);
/* Get the rule to add */
QString ruleToAdd = m_availableRulesList->itemData(m_availableRulesList->currentIndex()).toString();
/* Convert to human readable text */
QString ruleEnglishMeaning = m_availableRulesList->itemText(m_availableRulesList->currentIndex());
for (int i = 0; i < m_addedRulesList->rowCount(); i++)
if (m_addedRulesList->item(i,0)->data(Qt::DisplayRole).toString().compare(ruleEnglishMeaning) == 0)
{
/* Rule is already added so exit */
emit changeStatus("Rule already added!");
return;
}
/* Update row count of rule table to add in another rule */
m_addedRulesList->setRowCount(m_addedRulesList->rowCount()+1);
/* Create the cell item */
QTableWidgetItem * columnItem = new QTableWidgetItem(ruleEnglishMeaning);
/* Disable it from being editable by setting these flags */
columnItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
/* Set the item in the correct position in the rules table */
m_addedRulesList->setItem(m_addedRulesList->rowCount()-1, 0, columnItem);
/* If the row count is > 2, scroll bars appear so make adjustments to the width of table to accomodate this */
if (m_addedRulesList->rowCount() > 2)
m_addedRulesList->setColumnWidth(0, m_tableWidth-15);
else
m_addedRulesList->setColumnWidth(0, m_tableWidth);
/* Set the table header labels */
QStringList headerItemsRules;
headerItemsRules.append(tr("Added Rules"));
m_addedRulesList->setHorizontalHeaderLabels(headerItemsRules);
}
void MonitoringWidget::removeRule()
{
/*
This method is a slot that is called by the remove rule button. It removes a rule from the table, the selected one
*/
/* Get current row in rules table that is selected */
int currentRowSelected = m_addedRulesList->currentRow();
if (currentRowSelected == -1)
{
/* No row is selected so let user know and exit */
emit changeStatus(tr("No Rule Selected!"));
return;
}
/* Simply remove the current row */
m_addedRulesList->removeRow(currentRowSelected);
emit changeStatus(tr("Rule removed"));
}
void MonitoringWidget::addSensor()
{
/*
This slot is what is called when the user clicks the add sensor button.
*/
/* The sensor list will have 4 columns always: English Meaning, Code, Frequency and value */
m_sensorsList->setColumnCount(4);
/* Current Sensor */
QString englishMeaning = m_sensorComboList->currentText();
QString code = m_sensorComboList->itemData(m_sensorComboList->currentIndex()).toString();
/* Check is used for conversion of QString to int */
bool check;
/* Convert the QVariant data to integer */
int frequency = m_frequencyUpdateList->itemData(m_frequencyUpdateList->currentIndex()).toInt(&check);
/* Get the current number of rows */
int currentNumRows = m_sensorsList->rowCount();
/* First ensure sensor not already added */
for (int i = 0; i < currentNumRows; i++)
if (m_sensorsList->item(i,1)->data(Qt::DisplayRole).toString().compare(code) == 0)
{
/* Sensor already present. Exit */
emit changeStatus(tr("Sensor already present!"));
return;
}
/* Update the row count to + 1 to accomodate a new sensor */
m_sensorsList->setRowCount(currentNumRows+1);
/* Create the cell items, 4 of them in total and set them to not editable by setting flags */
QTableWidgetItem * column1Item = new QTableWidgetItem(englishMeaning);
column1Item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
QTableWidgetItem * column2Item = new QTableWidgetItem(code);
column2Item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
QTableWidgetItem * column3Item = new QTableWidgetItem(QString(QString::number(frequency)+"Hz"));
column3Item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
QTableWidgetItem * column4Item = new QTableWidgetItem("0");
column4Item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
/* Set the items in their correct column/row positions */
m_sensorsList->setItem(currentNumRows, 0, column1Item);
m_sensorsList->setItem(currentNumRows, 1, column2Item);
m_sensorsList->setItem(currentNumRows, 2, column3Item);
m_sensorsList->setItem(currentNumRows, 3, column4Item);
/* Set the widths of each column */
int col1Width = m_tableWidth * .5;
int col2Width = m_tableWidth * .15;
int col3Width = m_tableWidth * .15;
int col4Width = m_tableWidth * .20;
/* If the row count is > 2, scroll bars present so reduce first column to accomodate the scroll bars */
if (m_sensorsList->rowCount() > 2)
col1Width -= m_tableWidth*.05;
/* Set the column widths */
m_sensorsList->setColumnWidth(0,col1Width);
m_sensorsList->setColumnWidth(1,col2Width);
m_sensorsList->setColumnWidth(2,col3Width);
m_sensorsList->setColumnWidth(3,col4Width);
/* Set the column header labels */
QStringList headerItemsSensors;
headerItemsSensors.append(tr("Sensor Name"));
headerItemsSensors.append(tr("Code"));
headerItemsSensors.append(tr("Frequency"));
headerItemsSensors.append(tr("Value"));
m_sensorsList->setHorizontalHeaderLabels(headerItemsSensors);
/* Reset frequency combo box to first element (1Hz) for convienence */
m_frequencyUpdateList->setCurrentIndex(0);
emit changeStatus(tr("Sensor added to monitoring list!"));
}
void MonitoringWidget::removeSensor()
{
/*
This slot is called when the user clicks remove sensor.
*/
/* We just have to find the selected Item. It's row will give us what we need */
int currentRowSelected = m_sensorsList->currentRow();
if (currentRowSelected == -1)
{
/* User has selected no sensor in the table so return */
emit changeStatus(tr("No Sensor Selected!"));
return;
}
/* Otherwise, they have so remove the selected row */
m_sensorsList->removeRow(currentRowSelected);
emit changeStatus(tr("Sensor removed"));
}
void MonitoringWidget::populateSensorCombo()
{
/*
This method is responsible for inserting all the available sensors into the sensor combo box
*/
/* Clear first to avoid appending to old ones */
m_sensorComboList->clear();
/* Get list of sensor pointers */
QList<Sensor*> availableSensors = m_kernel->getAllSensors();
for (int i = 0; i < availableSensors.size(); i++)
{
if (availableSensors.at(i)->isSupported())
{
/* Only add a sensor to the combo box if it is supported by the current vehicle */
m_sensorComboList->addItem(availableSensors.at(i)->getName(), availableSensors.at(i)->getPid());
}
}
}
void MonitoringWidget::populateFrequencyUpdateList()
{
/*
This method simply populates the Frequency combo with frequency ranges, 1Hz to 30Hz
*/
for (int i = 1; i <= 30; i++)
m_frequencyUpdateList->addItem(QString(QString::number(i)+"Hz (Every "+QString::number(i)+" cycles)"),i);
}
void MonitoringWidget::display(double sensorVal)
{
/*
This is the slot that is called by all sensors added to monitor when their values change
It is responsible for locating the correct cell in the table and updating the new value
*/
/* Get calling sensor pointer */
Sensor * caller = dynamic_cast<Sensor*>(QObject::sender());
/* Get the command of the sensor, ie its pid */
QString sensorCode = caller->getPid();
/* Go through each row and find the row that matches this sensor */
for (int i = 0; i < m_sensorsList->rowCount(); i++)
if (m_sensorsList->item(i,1)->data(Qt::DisplayRole).toString().compare(sensorCode) == 0) /* We have the pid/code match */
m_sensorsList->item(i,3)->setData(Qt::DisplayRole, QString::number(sensorVal)); /* Update the value cell with new value */
}
void MonitoringWidget::startMonitoring()
{
/*
This is the method that is called when the user clicks the start/stop monitoring button.
This is a complex method in that it looks after setting up the rules as well and ensuring
that the rules can work, ie: all sensors in the rules are currently added to the monitoring etc
*/
if (!m_isMonitoring && m_kernel->isMonitoring())
{
/* Automon is currently working on some other task so let user know and return */
emit changeStatus(tr("Automon is currently busy with another task. Stop this first"));
return;
}
/* Clear all active sensors from Serial I/O thread */
m_kernel->removeAllActiveSensors();
if (m_sensorsList->rowCount() == 0)
{
/* No sensors are added to the sensor table. Let user know and return */
emit changeStatus(tr("No Sensors to Monitor!"));
return;
}
/* Disable all buttons to prevent user interrupting */
m_startStopMonitoring->setEnabled(false);
m_addSensorButton->setEnabled(false);
m_removeSensorButton->setEnabled(false);
m_addRuleButton->setEnabled(false);
m_removeRuleButton->setEnabled(false);
m_ruleEditorButton->setEnabled(false);
if (m_isMonitoring)
{
/* We are already monitoring so this button press is to stop monitoring */
m_startStopMonitoring->setEnabled(false);
for (int i = 0; i < m_sensorsList->rowCount(); i++)
{
/* For each sensor in the table, get its sensor code */
QString sensorCode = m_sensorsList->item(i,1)->data(Qt::DisplayRole).toString();
/* Disconnect the sensor's changeValue signal from our custom slot in this widget */
disconnect(m_kernel->getActiveSensorByCommand(sensorCode), SIGNAL(changeOccurred(double)), this, SLOT(display(double)));
/* Get a pointer to the current sensor */
Sensor * thisSensor = m_kernel->getActiveSensorByCommand(sensorCode);
/* Remove the sensor from the active list in the serial thread */
if (!m_kernel->removeActiveSensorByCommand(sensorCode))
emit changeStatus(tr("Sensor : ")+sensorCode+tr(" could not be removed!"));
/* Reset the sensor, such as sensor change times etc. State has to be reversed */
thisSensor->resetSensor();
}
/* Stop the serial thread */
m_kernel->stopMonitoring();
/* Change text on push button to more appropiate text */
m_startStopMonitoring->setText(tr("Start Monitoring"));
emit changeStatus(tr("Monitoring Stopped!"));
/* Update this variable so next time we know that monitoring has stopped */
m_isMonitoring = false;
/* Re enable all push buttons */
m_startStopMonitoring->setEnabled(true);
m_addSensorButton->setEnabled(true);
m_removeSensorButton->setEnabled(true);
m_addRuleButton->setEnabled(true);
m_removeRuleButton->setEnabled(true);
m_ruleEditorButton->setEnabled(true);
return;
}
/* If we get this far, monitoring is starting */
/* Reset the background of all rules */
for (int i = 0; i < m_addedRulesList->rowCount(); i++)
{
m_addedRulesList->item(i,0)->setBackground(QBrush(QColor(0,0,0,0)));
m_addedRulesList->item(i,0)->setForeground(QBrush(Qt::white));
}
for (int i = 0; i < m_sensorsList->rowCount(); i++)
{
/* For each sensor in the list of sensors to monitor... */
/* Get sensor code */
QString sensorCode = m_sensorsList->item(i,1)->data(Qt::DisplayRole).toString();
/* Bool is used for QString->Interger conversion */
bool check;
/* Get the frequency from the table */
QString frequencyStr = m_sensorsList->item(i,2)->data(Qt::DisplayRole).toString();
/* Convert to integer frequency */
int frequency = frequencyStr.section("", 0,frequencyStr.indexOf("Hz")).toInt(&check);
/* Add the sensor to the serial thread */
if (m_kernel->addActiveSensor(m_kernel->getSensorByCommand(sensorCode)))
{
/* Sensor added successfully, now update it's refresh frequency to the user defined one in table */
m_kernel->setSensorFrequency(m_kernel->getSensorByCommand(sensorCode), frequency);
/* Connect the sensor's signal to our slot */
connect(m_kernel->getActiveSensorByCommand(sensorCode), SIGNAL(changeOccurred(double)), this, SLOT(display(double)));
}
else
emit changeStatus(tr("Sensor : ")+sensorCode+tr(" could not be added!"));
}
/* Now it is time to create the rules */
/* Clear old rules and delete them */
for (int i = 0; i < m_rules.size(); i++)
{
disconnect(m_rules.at(i), SIGNAL(sendAlert(QString)), this, SLOT(ruleHandler(QString)));
delete(m_rules.at(i));
}
/* Clear rules list */
m_rules.clear();
for (int i = 0; i < m_addedRulesList->rowCount(); i++)
{
/* For each rule in the table list */
/* Get the rule from the table, it is in human readable format */
QString currentRuleEnglishName = m_addedRulesList->item(i,0)->data(Qt::DisplayRole).toString();
for (int j = 0; j < m_availableRulesList->count(); j++)
{
/* For each rule in the available rules list ... */
/* Convert it to human readable format and compare to the one in the table */
if (m_kernel->convertRuleToEnglish(m_availableRulesList->itemData(j).toString()).compare(currentRuleEnglishName) == 0)
{
/* Found the rule we working on. Get the real rule string, not human readable one */
QString nonEnglishRule = m_availableRulesList->itemData(j).toString();
/* Now we also must verify that all sensors present in the kernel active sensoring*/
QStringList sensorsInRule = m_kernel->extractSensorsFromRule(nonEnglishRule);
bool ruleCanBeAdded = true;
for (int k = 0; k < sensorsInRule.size(); k++)
/* Now for each sensor in the rule, check if it is in the active sensors */
if (m_kernel->getActiveSensorByCommand(sensorsInRule.at(k)) == NULL)
ruleCanBeAdded = false;
if (ruleCanBeAdded)
{
/* The rulecanbeadded variable didn't change to false so all sensors are in the serial thread */
/* Safe to create rule now */
Rule * thisRule = new Rule();
/* Set the rule to the real rule string */
thisRule->setRule(nonEnglishRule);
/* Add the rule to the list of rules */
m_rules.append(thisRule);
/* Connect rule to our slot */
connect(thisRule, SIGNAL(sendAlert(QString)), this, SLOT(ruleHandler(QString)));
for (int v=0; v<sensorsInRule.size(); v++)
{
/* For each sensor in the rule string, check to ensure it not empty */
if (sensorsInRule.at(v).compare("") != 0)
/* If not empty, then add a pointer to the sensor to the rule */
thisRule->addSensor(m_kernel->getActiveSensorByCommand(sensorsInRule.at(v)));
}
/* Set the rule name to the english name */
thisRule->setRuleName(currentRuleEnglishName);
/* Activate the rule */
if (!thisRule->activate())
{
/* Rule could not be actived. Highlight the rule in red and reverse actions from before */
m_addedRulesList->item(i,0)->setForeground(QBrush(Qt::red));
emit changeStatus(tr("The selected rule had an error of some kind"));
/* Remove all the sensors */
m_kernel->removeAllActiveSensors();
/* Re enable all buttons */
m_startStopMonitoring->setEnabled(true);
m_addSensorButton->setEnabled(true);
m_removeSensorButton->setEnabled(true);
m_addRuleButton->setEnabled(true);
m_removeRuleButton->setEnabled(true);
m_ruleEditorButton->setEnabled(true);
return;
}
/* If we get here, the rule successfully added */
emit changeStatus(tr("Rule Added!"));
}
else
{
/* If in here, the current rule has sensors that are not present in the serial thread.
IE: We forgot to add a sensor needed by this rule
*/
/* Set the rule color to red to highlight which rule caused the error */
m_addedRulesList->item(i,0)->setForeground(QBrush(Qt::red));
emit changeStatus(tr("Rule could not be added. Sensor not in list!"));
/* Reverse all actions before, by removing the few sensors added to the serial thread */
m_kernel->removeAllActiveSensors();
/* Re enable all buttons */
m_startStopMonitoring->setEnabled(true);
m_addSensorButton->setEnabled(true);
m_removeSensorButton->setEnabled(true);
m_addRuleButton->setEnabled(true);
m_removeRuleButton->setEnabled(true);
m_ruleEditorButton->setEnabled(true);
return;
}
}
}
}
/* Now that sensors added, time to start monitoring! */
/* Attempt to start monitoring, ie: start the serial I/O thread */
if (!m_kernel->startMonitoring())
{
/* We should not get in here. */
emit changeStatus(tr("Failed to start serial thread. This is an exception! Restart the device."));
m_startStopMonitoring->setEnabled(true);
return;
}
/* Update the text on the start/stop monitoring button to stop now */
m_startStopMonitoring->setText(tr("Stop Monitoring"));
emit changeStatus(tr("Monitoring Started!"));
/* Only re enable the start/stop monitoring button so user can stop the monitoring */
m_startStopMonitoring->setEnabled(true);
/* Update this variable so we know next time we click, we are stopping the monitoring */
m_isMonitoring = true;
}
void MonitoringWidget::ruleHandler(QString ruleString)
{
/*
This slot is called when a rule is satisfied. We must notify the user by highlighting which rule
in the rules table
*/
/* Rule string is the rule that is satisfied. Set the background color of cell to blue */
for (int i = 0; i < m_addedRulesList->rowCount(); i++)
if (m_addedRulesList->item(i,0)->data(Qt::DisplayRole).toString().compare(ruleString) == 0)
{
m_addedRulesList->item(i,0)->setBackground(QBrush(QColor(136,167,47)));
break;
}
emit changeStatus(tr("Rule Satisfied. Highlighted in Green"));
}
void MonitoringWidget::displayRuleEditor()
{
/*
This slot is called by the rule editor button. It changes the stacked widget index to
the rule editor so we see that view
*/
emit changePanel(5);
}
void MonitoringWidget::refreshRules()
{
/*
This is a slot that is called by the rule editor widget. It ensures that if changes made
in the rule editor, ie: New rule added, or rule removed, that these changes are reflected
in the monitor widget so we see the new rules in the available rules combo box or they removed
if we removed
*/
/* Update the combo box */
populateRulesAvailableList();
/* Now in the table, clear any rules not in the combo */
for (int i = 0; i < m_addedRulesList->rowCount(); i++)
{
bool found = false;
for (int j =0; j < m_availableRulesList->count(); j++)
{
if (m_addedRulesList->item(i,0)->data(Qt::DisplayRole).toString().compare(m_availableRulesList->itemText(j)) == 0)
{
/* We found a rule in the table that is no longer in the available rules list */
found = true;
break;
}
}
if (!found)
{
/* So the rule we had before, that is now gone has being removed. So remove from list */
m_addedRulesList->removeRow(i);
}
}
}