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