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