/*
* This file is part of jSpeed.
*
* jSpeed is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* jSpeed is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with jSpeed. If not, see .
*
*/
#include
#include
#include
#include "odometer.h"
#include "settings.h"
namespace
{
QString const TOTAL_FIELD = "odometer_total";
QString const TOTALTIME_FIELD = "odometer_totaltime";
QString const TRIP_FIELD = "odometer_trip";
QString const TRIPTIME_FIELD = "odometer_triptime";
QString const MAXSPEED_FIELD = "odometer_maxspeed";
QString const KM_UNIT = "km";
QString const MILE_UNIT = "mi";
QString const KM_SPEEDUNIT = "km/h";
QString const MILE_SPEEDUNIT = "mph";
QString const METER_UNIT = "m";
QString const FEET_UNIT = "ft";
static const int FIX_TIMEOUT = 4000;
double const DEFAULT_SPEED_TRESHOLD = 8.0;
double const MIN_SPEED_TRESHOLD = 0.8;
double const SPEED_IGNORE_LEVEL = 0.01;
double const TRESHOLD_POINT1_EPS = 40.0;
double const TRESHOLD_POINT1_TRESHOLD = 10.0;
double const TRESHOLD_POINT2_EPS = 1.8;
double const TRESHOLD_POINT2_TRESHOLD = MIN_SPEED_TRESHOLD;
double const TRESHOLD_X = (TRESHOLD_POINT1_TRESHOLD - TRESHOLD_POINT2_TRESHOLD) / (TRESHOLD_POINT1_EPS - TRESHOLD_POINT2_EPS);
double const TRESHOLD_Y = TRESHOLD_POINT1_TRESHOLD - (TRESHOLD_POINT1_EPS * TRESHOLD_X);
}
Odometer::Odometer(): QObject(0), trip_(0), total_(0),
maxSpeed_(0), totalTime_(0), tripTime_(0), fixTimer_(0),
mainTimer_(0), emitUpdate_(true), location_(0), signalTimer_(0)
{
total_ = Settings::instance().value(TOTAL_FIELD, 0).toDouble();
totalTime_ = Settings::instance().value(TOTALTIME_FIELD, 0).toULongLong();
maxSpeed_ = Settings::instance().value(MAXSPEED_FIELD, 0).toDouble();
trip_ = Settings::instance().value(TRIP_FIELD, 0).toDouble();
tripTime_ = Settings::instance().value(TRIPTIME_FIELD, 0).toULongLong();
signalTimer_ = new QTimer(this);
signalTimer_->setSingleShot(false);
signalTimer_->setInterval(1000);
connect(signalTimer_, SIGNAL(timeout()), this, SIGNAL(timeUpdated()));
updateUnit();
timeoutTimer_ = new QTimer(this);
timeoutTimer_->setSingleShot(true);
connect(timeoutTimer_, SIGNAL(timeout()), this, SLOT(fixTimeout()));
}
Odometer::~Odometer()
{
store();
delete fixTimer_;
delete mainTimer_;
end();
}
Odometer& Odometer::instance()
{
static Odometer instance;
return instance;
}
void Odometer::start()
{
location_ = new Location;
connect(location_, SIGNAL(locationChanged(Location::Fix const&)),
this, SLOT(update(Location::Fix const&)));
location_->start();
}
void Odometer::end()
{
delete location_;
location_ = 0;
}
void Odometer::update(Location::Fix const& fix)
{
if(!fixTimer_)
{
fixTimer_ = new QTime();
fixTimer_->start();
}
int elapsed = fixTimer_->elapsed();
fixTimer_->restart();
timeoutTimer_->start(FIX_TIMEOUT);
if(fix.kmSpeed > SPEED_IGNORE_LEVEL)
{
double treshold = DEFAULT_SPEED_TRESHOLD;
if(fix.eps > 0.01)
{
treshold = fix.eps * TRESHOLD_X + TRESHOLD_Y;
if(treshold < MIN_SPEED_TRESHOLD)
{
treshold = MIN_SPEED_TRESHOLD;
}
}
if(fix.kmSpeed > treshold && fix.kmSpeed > maxSpeed_)
{
maxSpeed_ = fix.kmSpeed;
}
if(fix.kmSpeed > treshold && elapsed > 200 && elapsed < FIX_TIMEOUT)
{
double km = fix.kmSpeed * (static_cast(elapsed) / (1000 * 3600));
trip_ += km;
total_ += km;
if(!mainTimer_)
{
startTiming();
}
}
else
{
endTiming();
}
latestFix_ = fix;
emit dataUpdated();
}
else
{
fixTimeout();
}
}
void Odometer::fixTimeout()
{
if(latestFix_.kmSpeed > SPEED_IGNORE_LEVEL)
{
latestFix_ = Location::Fix();
emit dataUpdated();
}
endTiming();
}
double Odometer::getTrip() const
{
return trip_ * Location::getUnitMultiplier();
}
double Odometer::getAverageSpeed() const
{
int elapsed = getTripTime();
if(elapsed == 0)
{
return 0.0;
}
return (static_cast(getTrip())) / (static_cast(getTripTime()) / 3600.0);
}
double Odometer::getTotal() const
{
return total_ * Location::getUnitMultiplier();
}
double Odometer::getMaxSpeed() const
{
return maxSpeed_ * Location::getUnitMultiplier();
}
qulonglong Odometer::getTotalTime() const
{
return totalTime_ + timeAddition();
}
qulonglong Odometer::getTripTime() const
{
return tripTime_ + timeAddition();
}
void Odometer::resetTrip()
{
resetTiming();
trip_ = 0;
tripTime_ = 0;
maxSpeed_ = 0;
if(emitUpdate_)
{
emit timeUpdated();
emit dataUpdated();
}
}
void Odometer::resetTotal()
{
resetTiming();
total_ = 0;
totalTime_ = 0;
if(emitUpdate_)
{
emit timeUpdated();
emit dataUpdated();
}
}
void Odometer::resetAll()
{
emitUpdate_ = false;
resetTrip();
resetTotal();
emitUpdate_ = true;
emit timeUpdated();
emit dataUpdated();
}
void Odometer::store()
{
Settings::instance().setValue(TOTAL_FIELD, total_);
Settings::instance().setValue(TOTALTIME_FIELD, getTotalTime());
Settings::instance().setValue(TRIP_FIELD, trip_);
Settings::instance().setValue(TRIPTIME_FIELD, getTripTime());
Settings::instance().setValue(MAXSPEED_FIELD, maxSpeed_);
Settings::instance().sync();
}
Location::Fix const& Odometer::getLatestFix() const
{
return latestFix_;
}
double Odometer::getSignalStrength() const
{
if(!location_)
{
return 0.0;
}
return location_->getSignalStrength();
}
QString const& Odometer::getUnit()
{
if(Location::getUnit() == Location::KM)
{
return KM_UNIT;
}
else
{
return MILE_UNIT;
}
}
QString const& Odometer::getSpeedUnit()
{
if(Location::getUnit() == Location::KM)
{
return KM_SPEEDUNIT;
}
else
{
return MILE_SPEEDUNIT;
}
}
double Odometer::getUnitMultiplier()
{
return Location::getUnitMultiplier();
}
double Odometer::getMeterMultiplier()
{
return Location::getMeterMultiplier();
}
QString Odometer::getMeterUnit()
{
if(Location::getUnit() == Location::KM)
{
return METER_UNIT;
}
else
{
return FEET_UNIT;
}
}
void Odometer::updateUnit()
{
QString unit = Settings::instance().value("unit", "km").toString();
if(unit == "km")
{
Location::setUnit(Location::KM);
}
else if(unit == "mile")
{
Location::setUnit(Location::MILE);
}
else
{
return;
}
emit unitChanged();
}
void Odometer::startTiming()
{
signalTimer_->start();
if(mainTimer_)
{
mainTimer_->restart();
return;
}
mainTimer_ = new QTime();
mainTimer_->start();
signalTimer_->start();
}
void Odometer::endTiming()
{
signalTimer_->stop();
if(!mainTimer_)
{
return;
}
int elapsed = mainTimer_->elapsed() / 1000;
totalTime_ += elapsed;
tripTime_ += elapsed;
delete mainTimer_;
mainTimer_ = 0;
}
void Odometer::resetTiming()
{
if(!mainTimer_)
{
return;
}
endTiming();
startTiming();
}
int Odometer::timeAddition() const
{
if(mainTimer_)
{
return mainTimer_->elapsed() / 1000;
}
return 0;
}