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