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