...
[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     QString const METER_UNIT = "m";
37     QString const FEET_UNIT = "ft";
38     static const int FIX_TIMEOUT = 4000;
39     double const DEFAULT_SPEED_TRESHOLD = 8.0;
40     double const MIN_SPEED_TRESHOLD = 0.8;
41     double const SPEED_IGNORE_LEVEL = 0.01;
42     double const TRESHOLD_POINT1_EPS = 40.0;
43     double const TRESHOLD_POINT1_TRESHOLD = 10.0;
44     double const TRESHOLD_POINT2_EPS = 1.8;
45     double const TRESHOLD_POINT2_TRESHOLD = MIN_SPEED_TRESHOLD;
46     double const TRESHOLD_X = (TRESHOLD_POINT1_TRESHOLD - TRESHOLD_POINT2_TRESHOLD) / (TRESHOLD_POINT1_EPS - TRESHOLD_POINT2_EPS);
47     double const TRESHOLD_Y = TRESHOLD_POINT1_TRESHOLD - (TRESHOLD_POINT1_EPS * TRESHOLD_X);
48 }
49
50 Odometer::Odometer(): QObject(0), trip_(0), total_(0),
51 maxSpeed_(0), totalTime_(0), tripTime_(0), fixTimer_(0),
52 mainTimer_(0), emitUpdate_(true), location_(0), signalTimer_(0)
53 {
54     total_ = Settings::instance().value(TOTAL_FIELD, 0).toDouble();
55     totalTime_ = Settings::instance().value(TOTALTIME_FIELD, 0).toULongLong();
56     maxSpeed_ = Settings::instance().value(MAXSPEED_FIELD, 0).toDouble();
57     trip_ = Settings::instance().value(TRIP_FIELD, 0).toDouble();
58     tripTime_ = Settings::instance().value(TRIPTIME_FIELD, 0).toULongLong();
59     signalTimer_ = new QTimer(this);
60     signalTimer_->setSingleShot(false);
61     signalTimer_->setInterval(1000);
62     connect(signalTimer_, SIGNAL(timeout()), this, SIGNAL(timeUpdated()));
63     updateUnit();
64     timeoutTimer_ = new QTimer(this);
65     timeoutTimer_->setSingleShot(true);
66     connect(timeoutTimer_, SIGNAL(timeout()), this, SLOT(fixTimeout()));
67
68 }
69
70 Odometer::~Odometer()
71 {
72     store();
73     delete fixTimer_;
74     delete mainTimer_;
75     end();
76 }
77
78 Odometer& Odometer::instance()
79 {
80     static Odometer instance;
81     return instance;
82 }
83
84 void Odometer::start()
85 {
86     location_ = new Location;
87     connect(location_, SIGNAL(locationChanged(Location::Fix const&)),
88             this, SLOT(update(Location::Fix const&)));
89     location_->start();
90 }
91
92 void Odometer::end()
93 {
94     delete location_;
95     location_ = 0;
96 }
97
98 void Odometer::update(Location::Fix const& fix)
99 {
100     if(!fixTimer_)
101     {
102         fixTimer_ = new QTime();
103         fixTimer_->start();
104     }
105
106     int elapsed = fixTimer_->elapsed();
107
108     fixTimer_->restart();
109     timeoutTimer_->start(FIX_TIMEOUT);
110
111     if(fix.kmSpeed > SPEED_IGNORE_LEVEL)
112     {
113         double treshold = DEFAULT_SPEED_TRESHOLD;
114
115         if(fix.eps > 0.01)
116         {
117            treshold = fix.eps * TRESHOLD_X + TRESHOLD_Y;
118
119            if(treshold < MIN_SPEED_TRESHOLD)
120            {
121                treshold = MIN_SPEED_TRESHOLD;
122            }
123         }
124
125         if(fix.kmSpeed > treshold && fix.kmSpeed > maxSpeed_)
126         {
127             maxSpeed_ = fix.kmSpeed;
128         }
129
130         if(fix.kmSpeed > treshold && elapsed > 200 && elapsed < FIX_TIMEOUT)
131         {
132             double km = fix.kmSpeed * (static_cast<double>(elapsed) / (1000 * 3600));
133             trip_ += km;
134             total_ += km;
135
136             if(!mainTimer_)
137             {
138                 startTiming();
139             }
140         }
141         else
142         {
143             endTiming();
144         }
145
146         latestFix_ = fix;
147         emit dataUpdated();
148     }
149     else
150     {
151         fixTimeout();
152     }
153 }
154
155 void Odometer::fixTimeout()
156 {
157     if(latestFix_.kmSpeed > SPEED_IGNORE_LEVEL)
158     {
159         latestFix_ = Location::Fix();
160         emit dataUpdated();
161     }
162
163     endTiming();
164 }
165
166 double Odometer::getTrip() const
167 {
168     return trip_ * Location::getUnitMultiplier();
169 }
170
171 double Odometer::getAverageSpeed() const
172 {
173     int elapsed = getTripTime();
174
175     if(elapsed == 0)
176     {
177         return 0.0;
178     }
179
180     return (static_cast<double>(getTrip())) / (static_cast<double>(getTripTime()) / 3600.0);
181 }
182
183 double Odometer::getTotal() const
184 {
185     return total_ * Location::getUnitMultiplier();
186 }
187
188 double Odometer::getMaxSpeed() const
189 {
190     return maxSpeed_ * Location::getUnitMultiplier();
191 }
192
193 qulonglong Odometer::getTotalTime() const
194 {
195     return totalTime_ + timeAddition();
196 }
197
198 qulonglong Odometer::getTripTime() const
199 {
200     return tripTime_ + timeAddition();
201 }
202
203 void Odometer::resetTrip()
204 {
205     resetTiming();
206     trip_ = 0;
207     tripTime_ = 0;
208     maxSpeed_ = 0;
209
210     if(emitUpdate_)
211     {
212         emit timeUpdated();
213         emit dataUpdated();
214     }
215 }
216
217 void Odometer::resetTotal()
218 {
219     resetTiming();
220     total_ = 0;
221     totalTime_ = 0;
222
223     if(emitUpdate_)
224     {
225         emit timeUpdated();
226         emit dataUpdated();
227     }
228 }
229
230 void Odometer::resetAll()
231 {
232     emitUpdate_ = false;
233     resetTrip();
234     resetTotal();
235     emitUpdate_ = true;
236     emit timeUpdated();
237     emit dataUpdated();
238 }
239
240 void Odometer::store()
241 {
242     Settings::instance().setValue(TOTAL_FIELD, total_);
243     Settings::instance().setValue(TOTALTIME_FIELD, getTotalTime());
244     Settings::instance().setValue(TRIP_FIELD, trip_);
245     Settings::instance().setValue(TRIPTIME_FIELD, getTripTime());
246     Settings::instance().setValue(MAXSPEED_FIELD, maxSpeed_);
247     Settings::instance().sync();
248 }
249
250 Location::Fix const& Odometer::getLatestFix() const
251 {
252     return latestFix_;
253 }
254
255 double Odometer::getSignalStrength() const
256 {
257     if(!location_)
258     {
259         return 0.0;
260     }
261
262     return location_->getSignalStrength();
263 }
264
265 QString const& Odometer::getUnit()
266 {
267     if(Location::getUnit() == Location::KM)
268     {
269         return KM_UNIT;
270     }
271     else
272     {
273         return MILE_UNIT;
274     }
275 }
276
277 QString const& Odometer::getSpeedUnit()
278 {
279     if(Location::getUnit() == Location::KM)
280     {
281         return KM_SPEEDUNIT;
282     }
283     else
284     {
285         return MILE_SPEEDUNIT;
286     }
287 }
288
289 double Odometer::getUnitMultiplier()
290 {
291     return Location::getUnitMultiplier();
292 }
293
294 double Odometer::getMeterMultiplier()
295 {
296     return Location::getMeterMultiplier();
297 }
298
299 QString Odometer::getMeterUnit()
300 {
301     if(Location::getUnit() == Location::KM)
302     {
303         return METER_UNIT;
304     }
305     else
306     {
307         return FEET_UNIT;
308     }
309 }
310
311 void Odometer::updateUnit()
312 {
313     QString unit = Settings::instance().value("unit", "km").toString();
314
315     if(unit == "km")
316     {
317         Location::setUnit(Location::KM);
318     }
319     else if(unit == "mile")
320     {
321         Location::setUnit(Location::MILE);
322     }
323     else
324     {
325         return;
326     }
327
328     emit unitChanged();
329 }
330
331 void Odometer::startTiming()
332 {
333     signalTimer_->start();
334
335     if(mainTimer_)
336     {
337         mainTimer_->restart();
338         return;
339     }
340
341     mainTimer_ = new QTime();
342     mainTimer_->start();
343     signalTimer_->start();
344 }
345
346 void Odometer::endTiming()
347 {
348     signalTimer_->stop();
349
350     if(!mainTimer_)
351     {
352         return;
353     }
354
355     int elapsed = mainTimer_->elapsed() / 1000;
356     totalTime_ += elapsed;
357     tripTime_ += elapsed;
358     delete mainTimer_;
359     mainTimer_ = 0;
360 }
361
362 void Odometer::resetTiming()
363 {
364     if(!mainTimer_)
365     {
366         return;
367     }
368
369     endTiming();
370     startTiming();
371 }
372
373 int Odometer::timeAddition() const
374 {
375     if(mainTimer_)
376     {
377         return mainTimer_->elapsed() / 1000;
378     }
379
380     return 0;
381 }