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