Major changes to Accelerometer handling
[speedfreak] / Client / carmainwindow.cpp
1 /*
2  * CarMainWindow main class
3  *
4  * @author     Toni Jussila <toni.jussila@fudeco.com>
5  * @author     Janne Änäkkälä <janne.anakkala@fudeco.com>
6  * @author     Tiina Kivilinna-Korhola <tiina.kivilinna-korhola@fudeco.com>
7  * @author     Olavi Pulkkinen <olavi.pulkkinen@fudeco.com>
8  * @author     Rikhard Kuutti <rikhard.kuutti@fudeco.com>
9  * @author     Kai Rasilainen <kai.rasilainen@fudeco.com>
10  * @copyright  (c) 2010 Speed Freak team
11  * @license    http://opensource.org/licenses/gpl-license.php GNU Public License
12  */
13
14 #include "carmainwindow.h"
15 #include "math.h"
16
17 #define kAccelerometerSampleRate    50
18 #define kFilteringFactor            0.2
19 #define kSecondsInHour              3600
20
21 /**
22   *Constructor of this class.
23   *@param QWidget pointer to parent object. By default the value is NULL.
24   */
25 CarMainWindow::CarMainWindow(QWidget *parent):QMainWindow(parent), ui(new Ui::CarMainWindow)
26 {
27     ui->setupUi(this);
28     ui->tabWidget->setCurrentWidget(this->ui->StartTab);
29     result = new ResultDialog();
30     //measure = new MeasureDialog();
31     welcomeDialog = new WelcomeDialog();
32     welcomeDialog->show();
33
34     initComboBoxStartTabUnits();
35     initListViewStartTabAccelerationCategories();
36
37     myLogin = new LoginWindow(this);
38     categorylist = new CategoryList();
39     myHttpClient = new HttpClient(this);
40     myRegistration = new Registration(this);
41     connect(myRegistration,SIGNAL(sendregistration()),this,SLOT(regUserToServer()));
42     connect(myLogin,SIGNAL(userNameChanged()),this,SLOT(userLogin()));
43     myRoute = new RouteDialog( this);
44
45     time = 0;
46     speed = 0;
47     timer = new QTimer();
48
49     // Accelerometer
50     accelerometer = new Accelerometer();
51     accelerometer->setSampleRate(100);
52
53     reverseAccelerationFlag = false;
54     vehicleStartedMoving = false;
55     isNewRun = true;
56     isSetup = false;
57     stopTime = 0;
58     accelerationStartThreshold = 0.02;
59
60     QTimer *accelerometerTimer = new QTimer(this);
61     connect(accelerometerTimer, SIGNAL(timeout()), this, SLOT(readAccelerometerData()));
62     accelerometerTimer->start(kAccelerometerSampleRate);
63
64     // Calculate
65     calculate = new Calculate();
66     //connect(calculate, SIGNAL(checkPointReached()), this, SLOT(handleCheckPoint()));
67
68     resetAccelerometerMeasurements();
69
70     measures = new Measures();
71     this->initializeMeasures();
72
73     timer->setInterval(300);
74
75     connect(this->timer, SIGNAL(timeout()), this, SLOT(after_timeout()));
76     connect(myLogin, SIGNAL( userNameChanged()), this, SLOT(updateUserName()));
77
78     ui->labelMeasureTabResult->hide();
79
80     this->setWindowTitle("Speed Freak");
81
82 }
83
84 /**
85   *Destructor of this class. Should be used to release all allocated resources.
86   */
87 CarMainWindow::~CarMainWindow()
88 {
89     delete ui;
90     //delete result;
91     //delete measure;
92     delete categorylist;
93     delete welcomeDialog;
94     delete myRoute;
95 }
96
97 /**
98   *This function is used to .
99   *@param
100   */
101 void CarMainWindow::changeEvent(QEvent *e)
102 {
103     QMainWindow::changeEvent(e);
104     switch (e->type()) {
105     case QEvent::LanguageChange:
106         ui->retranslateUi(this);
107         break;
108     default:
109         break;
110     }
111 }
112
113 /**
114   *This slot function is called when ever list view is update. Start-tab view.
115   */
116 void CarMainWindow::on_listViewStartTabAccelerationCategories_clicked(QModelIndex index)
117 {
118     QString str = index.data().toString();
119     QStringList list = str.split("-");
120     QStringList list2 = list[1].split(" ");
121
122     ui->lineEditStartTabMin->setText(list[0]);
123     ui->lineEditStartTabMax->setText(list2[0]);
124     updateComboBoxStartTabUnits(list2[1]);
125 }
126
127 /**
128   *This slot function is called when ever auto start button clicked. Start-tab view.
129   */
130 void CarMainWindow::on_autoStartButton_clicked()
131 {
132     choice = ui->listViewStartTabAccelerationCategories->currentIndex();
133     choiceInt = choice.row();
134     qDebug() << choiceInt;
135     if (choiceInt == 0)
136     {
137         ui->labelMeasureTabHeader->setText("Accelerate to 40 km/h");
138         result->setDiagramGapStem(75);
139     }
140
141     else if (choiceInt == 1)
142     {
143         ui->labelMeasureTabHeader->setText("Accelerate to 100 km/h");
144         result->setDiagramGapStem(30);
145     }
146
147     else
148     {
149         ui->labelMeasureTabHeader->setText("Accelerate to 80 km/h");
150         result->setDiagramGapStem(37.5);
151     }
152     ui->labelMeasureTabResult->setText("");
153     //delete measure;
154     //measure = NULL;
155     //measure = new MeasureDialog();
156    // connect(measure, SIGNAL(speedAchieved()), this, SLOT(openResultView()));
157     accelerometer->start();
158     timer->start();
159     // Show measure dialog.
160     //measure->show();
161
162     // TODO: Move next if else to the function which is called when target speed
163     // has reached.
164     if (choiceInt == 0)
165     {
166         if (floor(this->measures->getTime40kmh()) <= 5)
167         {
168             result->setDiagramGapHorizontal(80);
169         }
170
171         else if (floor(this->measures->getTime40kmh()) <= 10)
172         {
173             result->setDiagramGapHorizontal(40);
174         }
175
176         else
177         {
178             result->setDiagramGapHorizontal(20);
179         }
180     }
181
182     else
183     {
184         if (floor(this->measures->getTime40kmh()) <= 5)
185         {
186             result->setDiagramGapHorizontal(80);
187         }
188
189         else if (floor(this->measures->getTime40kmh()) <= 10)
190         {
191             result->setDiagramGapHorizontal(40);
192         }
193
194         else
195         {
196             result->setDiagramGapHorizontal(20);
197         }
198     }
199
200     ui->tabWidget->setCurrentWidget(this->ui->tabMeasureResult);
201 }
202
203 /**
204   *This slot function is called when ever list view is update. Start-tab view.
205   *@param QString unit.
206   */
207 void CarMainWindow::updateComboBoxStartTabUnits(QString unit)
208 {
209     ui->comboBoxStartTabUnits->setCurrentIndex(ui->comboBoxStartTabUnits->findText(unit, Qt::MatchExactly));
210 }
211
212 /**
213   *This function is used to init unit combobox. Start-tab view.
214   */
215 void CarMainWindow::initComboBoxStartTabUnits()
216 {
217     units << "km/h" << "km" << "h" << "m" << "min" << "Mile" << "Mph" << "in" << "ft" << "yrd";
218     ui->comboBoxStartTabUnits->addItems(units);
219 }
220
221 /**
222   *This function is used to set items to unit combobox. Start-tab view.
223   *@param QStringlist units
224   */
225 void CarMainWindow::setComboBoxStartTabUnits(QStringList units)
226 {
227     ui->comboBoxStartTabUnits->addItems(units);
228 }
229
230 /**
231   *This function is used to init listViewStartTabAccelerationCategories. Start-tab view.
232   */
233 void CarMainWindow::initListViewStartTabAccelerationCategories()
234 {
235     accelerationCategoriesStartTab << "0-40 km/h" << "0-100 km/h"; //<< "0-1/4 Mile" << "0-1/8 Mile" << "0-50 km" << "50-100 Mile" << "0-60 Mph" << "0-100 m" << "0-50 ft" << "0-50 yrd" << "0-500 in";
236     QAbstractItemModel *model = new StringListModel(accelerationCategoriesStartTab);
237     ui->listViewStartTabAccelerationCategories->setModel(model);
238 }
239
240 /**
241   *This function is used to set items to listViewStartTabAccelerationCategories. Start-tab view.
242   *@param QStringlist accelerationCategoriesStartTab
243   */
244 void CarMainWindow::setListViewStartTabAccelerationCategories(QStringList accelerationCategoriesStartTab)
245 {
246     QAbstractItemModel *model = new StringListModel(accelerationCategoriesStartTab);
247     ui->listViewStartTabAccelerationCategories->setModel(model);
248 }
249
250 /**
251   *This function is used to set items to category combobox. Top-tab view.
252   *@param
253   */
254 void CarMainWindow::setCategoryCompoBox()
255 {
256     ui->comboBoxTopCategory->addItems(categorylist->getCategoryList());
257 }
258
259 /**
260   *This function is used to set items to labelTopList. Top-tab view.
261   *@param QString category
262   */
263 void CarMainWindow::setListViewTopList(QString category, int size)
264 {
265     QString topList;
266     topList.append( categorylist->getTopList(category, size));
267     ui->labelTopList->setText(topList);
268 }
269
270 /**
271   *This slot function is called when speed is achieved in measure dialog. Opens result dialog.
272   */
273 void CarMainWindow::openResultView()
274 {
275     //result->saveMeasuresToArray(measure->measures);
276     // Show result dialog.
277     //result->show();
278     ui->pushButtonSendResult->setEnabled(true);
279     QString timeInteger;
280     if (choiceInt == 0)
281     {
282         if (floor(this->measures->getTime40kmh()) <= 5)
283         {
284             result->setDiagramGapHorizontal(80);
285         }
286
287         else if (floor(this->measures->getTime40kmh()) <= 10)
288         {
289             result->setDiagramGapHorizontal(40);
290         }
291
292         else
293         {
294             result->setDiagramGapHorizontal(20);
295         }
296     }
297
298     else
299     {
300         if (floor(this->measures->getTime40kmh()) <= 5)
301         {
302             result->setDiagramGapHorizontal(80);
303         }
304
305         else if (floor(this->measures->getTime40kmh()) <= 10)
306         {
307             result->setDiagramGapHorizontal(40);
308         }
309
310         else
311         {
312             result->setDiagramGapHorizontal(20);
313         }
314     }
315     timeInteger.setNum(this->measures->getTime40kmh());
316     //time = "0 - 40 km/h: ";
317     //time.append(timeInteger);
318     //ui->labelResult40kmh->setText(time);
319     ui->labelMeasureTabResult->show();
320     ui->labelMeasureTabResult->setText(timeInteger);
321     //ui->tabWidget->setCurrentWidget(this->ui->tabMeasureResult);
322 }
323
324 /**
325   *This slot function is called when registrate button is clicked.
326   */
327 void CarMainWindow::on_registratePushButton_clicked()
328 {
329     myRegistration->show();
330 }
331
332 /**
333   *This slot function is called when ever refresh button clicked. Top-tab view.
334   */
335 void CarMainWindow::on_buttonTopRefresh_clicked()
336 {
337     myHttpClient->requestCategories();
338     setCategoryCompoBox();
339 }
340
341 /**
342   *This slot function is called when ever category combobox current index changed. Top-tab view.
343   *@param QString category
344   *@todo Check where limitNr is taken.
345   */
346 void CarMainWindow::on_comboBoxTopCategory_currentIndexChanged(QString category)
347 {
348     int limitNr = 5;                    //replace with real value?
349     QString limit = QString::number(limitNr);
350     category = "acceleration-0-100";    //replace with real value from category list/top window
351     myHttpClient->requestTopList(category, limit);
352     setListViewTopList(category,10);
353 }
354
355 /**
356   *This slot function is called when ever category combobox activated. Top-tab view.
357   *@param QString category
358   */
359 void CarMainWindow::on_comboBoxTopCategory_activated(QString category)
360 {
361     setListViewTopList(category,10);
362 }
363
364 /**
365   *This slot function is called when set/change user button is clicked.
366   */
367 void CarMainWindow::on_setUserPushButton_clicked()
368 {
369     myLogin->show();
370 }
371
372 /**
373   *@brief Just for development, for the real button is not shown until
374   *measurin started and there are results.
375   *@todo Implement with real code and yet leave sendXml in the bottom in use.
376   */
377 void CarMainWindow::on_manualStartButton_clicked()
378 {
379
380 }
381
382 /**
383   * This slot function is called when timer gives timeout signal. Checks current speed
384   * and stores times in measure class.
385   */
386 void CarMainWindow::after_timeout()
387 {
388     QString timeString, speedString;
389     //time++;
390     time = accelerometer->getTotalTime();
391     speed = accelerometer->getCurrentSpeed();
392     //speed = speed +10;
393
394     if (floor(speed) == 10)
395     {
396         measures->setTime10kmh(time);
397     }
398
399     else if (floor(speed) == 20)
400     {
401         measures->setTime20kmh(time);
402     }
403
404     else if (floor(speed) == 30)
405     {
406         measures->setTime30kmh(time);
407     }
408
409     else if (floor(speed) == 40)
410     {
411         measures->setTime40kmh(time);
412     }
413
414     else if (floor(speed) == 50)
415     {
416         measures->setTime50kmh(time);
417     }
418
419     else if (floor(speed) == 60)
420     {
421         measures->setTime60kmh(time);
422     }
423
424     else if (floor(speed) == 70)
425     {
426         measures->setTime70kmh(time);
427     }
428
429     else if (floor(speed) == 80)
430     {
431         measures->setTime80kmh(time);
432     }
433
434     else if (floor(speed) == 90)
435     {
436         measures->setTime90kmh(time);
437     }
438
439     else if (floor(speed) == 100)
440     {
441         measures->setTime100kmh(time);
442     }
443
444     else
445     {
446
447     }
448
449     // If speed is over 40 km/h emits speedAchieved() signal and close this dialog.
450     if (speed >= 40.0)
451     {
452         timer->stop();
453         accelerometer->stop();
454         time = 0;
455         speed = 0;
456         //emit this->speedAchieved();
457         this->openResultView();
458         //this->close();
459
460     }
461
462     // Updates speed and time.
463     else
464     {
465         timeString.setNum(time);
466         speedString.setNum(speed);
467         ui->labelMeasureTabTime->setText(timeString);
468         ui->labelMeasureTabSpeed->setText(speedString);
469
470         timer->start();
471     }
472
473 }
474
475 /**
476   * Initializes measures class's member variables.
477   */
478 void CarMainWindow::initializeMeasures()
479 {
480     measures->setTime10kmh(0);
481     measures->setTime20kmh(0);
482     measures->setTime30kmh(0);
483     measures->setTime40kmh(0);
484     measures->setTime50kmh(0);
485     measures->setTime60kmh(0);
486     measures->setTime70kmh(0);
487     measures->setTime80kmh(0);
488     measures->setTime90kmh(0);
489     measures->setTime100kmh(0);
490 }
491
492 /**
493   * This slot function is called when Abort button is clicked.
494   */
495 void CarMainWindow::on_pushButtonMeasureTabAbort_clicked()
496 {
497     measures->setTime10kmh(0);
498     measures->setTime20kmh(0);
499     measures->setTime30kmh(0);
500     measures->setTime40kmh(0);
501     measures->setTime50kmh(0);
502     measures->setTime60kmh(0);
503     measures->setTime70kmh(0);
504     measures->setTime80kmh(0);
505     measures->setTime90kmh(0);
506     measures->setTime100kmh(0);
507     timer->stop();
508     accelerometer->stop();
509     time = 0;
510     speed = 0;
511     ui->tabWidget->setCurrentWidget(this->ui->StartTab);
512     //this->close();
513 }
514
515 void CarMainWindow::on_pushButtonSendResult_clicked()
516 {
517     myHttpClient->sendResultXml();
518     ui->pushButtonSendResult->setEnabled(false);
519 }
520
521 void CarMainWindow::updateUserName()
522 {
523     QString newUserName;
524
525     newUserName = myLogin->getUserName();
526     ui->userNameLabel->setText( "User: " + newUserName);
527
528     if (newUserName.length())
529     {
530        ui->setUserPushButton->setText( "Change User");
531        this->setWindowTitle("Speed freak - " + newUserName);
532     }
533     else
534     {
535         ui->setUserPushButton->setText( "Set User");
536         this->setWindowTitle("Speed freak");
537     }
538 }
539
540 void CarMainWindow::regUserToServer()
541 {
542     myHttpClient->requestRegistration();
543 }
544
545
546 void CarMainWindow::on_drawRoutePushButton_clicked()
547 {
548     myRoute->show();
549 }
550
551 /**
552   * Opens result dialog when show result button is clicked.
553   * Sends measures as parameter to the resultdialogs saveMeasuresToArray-function.
554   */
555 void CarMainWindow::on_pushButtonShowResultDialog_clicked()
556 {
557     Measures meas;
558     meas.setTime10kmh(1.3);
559     meas.setTime20kmh(2.5);
560     meas.setTime30kmh(3.6);
561     meas.setTime40kmh(6.7);
562     meas.setTime50kmh(7.3);
563     meas.setTime60kmh(7.5);
564     meas.setTime70kmh(8.6);
565     meas.setTime80kmh(8.7);
566     meas.setTime90kmh(9.6);
567     meas.setTime100kmh(9.9);
568     result->setDiagramGapHorizontal(40);
569     result->saveMeasuresToArray(&meas);
570     this->result->show();
571 }
572
573 void CarMainWindow::userLogin()
574 {
575     myHttpClient->checkLogin();
576 }
577
578 /**
579   * Resets Accelerometer measurement variables
580   */
581 void CarMainWindow::resetAccelerometerMeasurements()
582 {
583     currentAcceleration = 0;
584     currentAccelerationString = "";
585     currentSpeed = "";
586     currentTime = 0;
587     distanceTraveled = "";
588     firstAcceleration = 0;
589     //horsepower = null;
590     isNewRun = true;
591     //lastScreenUpdateInSeconds = 0;
592     previousTime = 0;
593     reverseAccelerationFlag = false;
594     stopWatch.setHMS(0, 0, 0, 0);
595     //accelerometer->stop();
596     totalTime = "";
597     vehicleStartedMoving = false;
598     calculate->reset();
599 }
600
601 /**
602   * This function is called to handle checkpoints
603   *@param totalTime total time elapsed since starting measurements
604   *@param currentSpeed current speed of the device
605   */
606 void CarMainWindow::handleCheckPoint(double totalTime, double currentSpeed)
607 {
608     // TODO
609     //totalTime;
610     //currentSpeed;
611     return;
612 }
613
614 /**
615   *This function is called to read (and process) data from the accelerometer
616   */
617 void CarMainWindow::readAccelerometerData()
618 {
619     QString s;
620     double changeInAcceleration = 0;
621     qreal x, y, z;
622
623     accelerometer->getAcceleration(x, y, z);
624     accelerometer->smoothData(x, y, z);
625
626     // Apply calibration
627     x -= accelerometer->getCalibrationX();
628     y -= accelerometer->getCalibrationY();
629     z -= accelerometer->getCalibrationZ();
630
631     QString str = QString("acc x: " + QString::number(x) + "\n" +
632                           "acc y: " + QString::number(y) + "\n" +
633                           "acc z: " + QString::number(z) + "\n");
634
635     if (!vehicleStartedMoving)
636     {
637         if (isNewRun)
638         {
639             firstAcceleration = sqrt(x*x + y*y + z*z);
640             //firstAcceleration = y; // first read
641             isNewRun = false;
642         }
643     }
644
645     currentAcceleration = sqrt(x*x + y*y + z*z);
646     changeInAcceleration = (currentAcceleration - firstAcceleration); // firstAcceleration only gets set once
647
648     if (((abs(changeInAcceleration) <= accelerationStartThreshold)
649                 && !vehicleStartedMoving))
650     {
651         return;
652     }
653
654     if (reverseAccelerationFlag)
655     {
656         // will be false until after 1st calculation
657         if ((changeInAcceleration <= 0))
658         {
659             // actually increasing here...
660             changeInAcceleration = abs(changeInAcceleration);
661         }
662         else
663         {
664             // actually decreasing here...
665             changeInAcceleration = (changeInAcceleration * -1);
666         }
667     }
668     if (!vehicleStartedMoving)
669     {
670         if ((changeInAcceleration < 0))
671         {
672             // we started to move backwards first time through
673             reverseAccelerationFlag = true;
674             changeInAcceleration = abs(changeInAcceleration);
675         }
676         vehicleStartedMoving = true;
677
678         stopWatch.setHMS(0, 0, 0, 0);
679         stopWatch.start();
680     }
681     //  keep the following line as close to the SetKinematicsProperties method as possible
682     currentTime = stopWatch.elapsed();
683     calculate->calculateParameters(changeInAcceleration, (currentTime - previousTime)/1000);
684     previousTime = currentTime;
685
686     s.sprintf("%.2f", changeInAcceleration);
687     currentAccelerationString = s;
688
689     double speed = 0.0;
690     speed = calculate->getCurrentSpeed();
691     speed = ((speed*1000)/kSecondsInHour);
692     s.sprintf("%.2f", speed);
693     currentSpeed = s;
694
695     s.sprintf("%.2f", calculate->getDistanceTraveled());
696     distanceTraveled = s;
697
698     // TODO
699     //distanceTraveled;
700     //horsepower;
701     //totalTime;
702
703     s.sprintf("%.2f", calculate->getTotalTime());
704     totalTime = s;
705
706     str.append("ca: " + currentAccelerationString + " G\n" );
707     str.append("cspeed: " + currentSpeed + " km/h \n" );
708     str.append("dist: " + distanceTraveled + " m \n" );
709     str.append("time: " + totalTime + " s \n" );
710
711     if ((stopTime > 0) && (previousTime >= stopTime))
712     {
713         // we want to end at a stopping point that the user chose
714         // output results
715         resetAccelerometerMeasurements();
716     }
717 }
718
719 /**
720   *This function is used to calibrate accelerometer
721   */
722 void CarMainWindow::calibrateAccelerometer()
723 {
724     resetAccelerometerMeasurements();
725     accelerometer->calibrate();
726 }