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