4d8113652691f17f2d937c4d50a5e963ac93f33b
[jspeed] / src / odometer.cpp
1 /*
2  * This file is part of jSpeed.
3  *
4  * jSpeed is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * jSpeed is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with jSpeed.  If not, see <http://www.gnu.org/licenses/>.
16  *
17  */
18
19 #include <QtCore/QTime>
20 #include <QtCore/QDebug>
21 #include <QtCore/QTimer>
22 #include "odometer.h"
23 #include "settings.h"
24
25 namespace
26 {
27     QString const TOTAL_FIELD = "odometer_total";
28     QString const TOTALTIME_FIELD = "odometer_totaltime";
29     QString const TRIP_FIELD = "odometer_trip";
30     QString const TRIPTIME_FIELD = "odometer_triptime";
31     QString const MAXSPEED_FIELD = "odometer_maxspeed";
32     QString const KM_UNIT = "km";
33     QString const MILE_UNIT = "mi";
34     QString const KM_SPEEDUNIT = "km/h";
35     QString const MILE_SPEEDUNIT = "mph";
36     static const int FIX_TIMEOUT = 4000;
37     double const DEFAULT_SPEED_TRESHOLD = 8.0;
38     double const MIN_SPEED_TRESHOLD = 0.8;
39     double const SPEED_IGNORE_LEVEL = 0.01;
40     double const TRESHOLD_POINT1_EPS = 40.0;
41     double const TRESHOLD_POINT1_TRESHOLD = 10.0;
42     double const TRESHOLD_POINT2_EPS = 1.8;
43     double const TRESHOLD_POINT2_TRESHOLD = MIN_SPEED_TRESHOLD;
44     double const TRESHOLD_X = (TRESHOLD_POINT1_TRESHOLD - TRESHOLD_POINT2_TRESHOLD) / (TRESHOLD_POINT1_EPS - TRESHOLD_POINT2_EPS);
45     double const TRESHOLD_Y = TRESHOLD_POINT1_TRESHOLD - (TRESHOLD_POINT1_EPS * TRESHOLD_X);
46 }
47
48 Odometer::Odometer(): QObject(0), trip_(0), total_(0),
49 maxSpeed_(0), totalTime_(0), tripTime_(0), fixTimer_(0),
50 mainTimer_(0), emitUpdate_(true), location_(0), signalTimer_(0)
51 {
52     total_ = Settings::instance().value(TOTAL_FIELD, 0).toDouble();
53     totalTime_ = Settings::instance().value(TOTALTIME_FIELD, 0).toULongLong();
54     maxSpeed_ = Settings::instance().value(MAXSPEED_FIELD, 0).toDouble();
55     trip_ = Settings::instance().value(TRIP_FIELD, 0).toDouble();
56     tripTime_ = Settings::instance().value(TRIPTIME_FIELD, 0).toULongLong();
57     signalTimer_ = new QTimer(this);
58     signalTimer_->setSingleShot(false);
59     signalTimer_->setInterval(1000);
60     connect(signalTimer_, SIGNAL(timeout()), this, SIGNAL(timeUpdated()));
61     updateUnit();
62     timeoutTimer_ = new QTimer(this);
63     timeoutTimer_->setSingleShot(true);
64     connect(timeoutTimer_, SIGNAL(timeout()), this, SLOT(fixTimeout()));
65
66 }
67
68 Odometer::~Odometer()
69 {
70     store();
71     delete fixTimer_;
72     delete mainTimer_;
73     end();
74 }
75
76 Odometer& Odometer::instance()
77 {
78     static Odometer instance;
79     return instance;
80 }
81
82 void Odometer::start()
83 {
84     location_ = new Location;
85     connect(location_, SIGNAL(locationChanged(Location::Fix const&)),
86             this, SLOT(update(Location::Fix const&)));
87     location_->start();
88 }
89
90 void Odometer::end()
91 {
92     delete location_;
93     location_ = 0;
94 }
95
96 void Odometer::update(Location::Fix const& fix)
97 {
98     if(!fixTimer_)
99     {
100         fixTimer_ = new QTime();
101         fixTimer_->start();
102     }
103
104     int elapsed = fixTimer_->elapsed();
105
106     fixTimer_->restart();
107     timeoutTimer_->start(FIX_TIMEOUT);
108
109     if(fix.kmSpeed > SPEED_IGNORE_LEVEL)
110     {
111         double treshold = DEFAULT_SPEED_TRESHOLD;
112
113         if(fix.eps > 0.01)
114         {
115            treshold = fix.eps * TRESHOLD_X + TRESHOLD_Y;
116
117            if(treshold < MIN_SPEED_TRESHOLD)
118            {
119                treshold = MIN_SPEED_TRESHOLD;
120            }
121         }
122
123         if(fix.kmSpeed > treshold && fix.kmSpeed > maxSpeed_)
124         {
125             maxSpeed_ = fix.kmSpeed;
126         }
127
128         if(fix.kmSpeed > treshold && elapsed > 200 && elapsed < FIX_TIMEOUT)
129         {
130             double km = fix.kmSpeed * (static_cast<double>(elapsed) / (1000 * 3600));
131             trip_ += km;
132             total_ += km;
133
134             if(!mainTimer_)
135             {
136                 startTiming();
137             }
138         }
139         else
140         {
141             endTiming();
142         }
143
144         latestFix_ = fix;
145         emit dataUpdated();
146     }
147     else
148     {
149         fixTimeout();
150     }
151 }
152
153 void Odometer::fixTimeout()
154 {
155     if(latestFix_.kmSpeed > SPEED_IGNORE_LEVEL)
156     {
157         latestFix_ = Location::Fix();
158         emit dataUpdated();
159     }
160
161     endTiming();
162 }
163
164 double Odometer::getTrip() const
165 {
166     return trip_ * Location::getUnitMultiplier();
167 }
168
169 double Odometer::getAverageSpeed() const
170 {
171     int elapsed = getTripTime();
172
173     if(elapsed == 0)
174     {
175         return 0.0;
176     }
177
178     return (static_cast<double>(getTrip())) / (static_cast<double>(getTripTime()) / 3600.0);
179 }
180
181 double Odometer::getTotal() const
182 {
183     return total_ * Location::getUnitMultiplier();
184 }
185
186 double Odometer::getMaxSpeed() const
187 {
188     return maxSpeed_ * Location::getUnitMultiplier();
189 }
190
191 qulonglong Odometer::getTotalTime() const
192 {
193     return totalTime_ + timeAddition();
194 }
195
196 qulonglong Odometer::getTripTime() const
197 {
198     return tripTime_ + timeAddition();
199 }
200
201 void Odometer::resetTrip()
202 {
203     resetTiming();
204     trip_ = 0;
205     tripTime_ = 0;
206     maxSpeed_ = 0;
207
208     if(emitUpdate_)
209     {
210         emit timeUpdated();
211         emit dataUpdated();
212     }
213 }
214
215 void Odometer::resetTotal()
216 {
217     resetTiming();
218     total_ = 0;
219     totalTime_ = 0;
220
221     if(emitUpdate_)
222     {
223         emit timeUpdated();
224         emit dataUpdated();
225     }
226 }
227
228 void Odometer::resetAll()
229 {
230     emitUpdate_ = false;
231     resetTrip();
232     resetTotal();
233     emitUpdate_ = true;
234     emit timeUpdated();
235     emit dataUpdated();
236 }
237
238 void Odometer::store()
239 {
240     Settings::instance().setValue(TOTAL_FIELD, total_);
241     Settings::instance().setValue(TOTALTIME_FIELD, getTotalTime());
242     Settings::instance().setValue(TRIP_FIELD, trip_);
243     Settings::instance().setValue(TRIPTIME_FIELD, getTripTime());
244     Settings::instance().setValue(MAXSPEED_FIELD, maxSpeed_);
245     Settings::instance().sync();
246 }
247
248 Location::Fix const& Odometer::getLatestFix() const
249 {
250     return latestFix_;
251 }
252
253 double Odometer::getSignalStrength() const
254 {
255     if(!location_)
256     {
257         return 0.0;
258     }
259
260     return location_->getSignalStrength();
261 }
262
263 QString const& Odometer::getUnit()
264 {
265     if(Location::getUnit() == Location::KM)
266     {
267         return KM_UNIT;
268     }
269     else
270     {
271         return MILE_UNIT;
272     }
273 }
274
275 QString const& Odometer::getSpeedUnit()
276 {
277     if(Location::getUnit() == Location::KM)
278     {
279         return KM_SPEEDUNIT;
280     }
281     else
282     {
283         return MILE_SPEEDUNIT;
284     }
285 }
286
287 double Odometer::getUnitMultiplier()
288 {
289     return Location::getUnitMultiplier();
290 }
291
292 void Odometer::updateUnit()
293 {
294     QString unit = Settings::instance().value("unit", "km").toString();
295
296     if(unit == "km")
297     {
298         Location::setUnit(Location::KM);
299     }
300     else if(unit == "mile")
301     {
302         Location::setUnit(Location::MILE);
303     }
304     else
305     {
306         return;
307     }
308
309     emit unitChanged();
310 }
311
312 void Odometer::startTiming()
313 {
314     signalTimer_->start();
315
316     if(mainTimer_)
317     {
318         mainTimer_->restart();
319         return;
320     }
321
322     mainTimer_ = new QTime();
323     mainTimer_->start();
324     signalTimer_->start();
325 }
326
327 void Odometer::endTiming()
328 {
329     signalTimer_->stop();
330
331     if(!mainTimer_)
332     {
333         return;
334     }
335
336     int elapsed = mainTimer_->elapsed() / 1000;
337     totalTime_ += elapsed;
338     tripTime_ += elapsed;
339     delete mainTimer_;
340     mainTimer_ = 0;
341 }
342
343 void Odometer::resetTiming()
344 {
345     if(!mainTimer_)
346     {
347         return;
348     }
349
350     endTiming();
351     startTiming();
352 }
353
354 int Odometer::timeAddition() const
355 {
356     if(mainTimer_)
357     {
358         return mainTimer_->elapsed() / 1000;
359     }
360
361     return 0;
362 }