mirror of
https://github.com/GoldenCheetah/GoldenCheetah.git
synced 2026-02-14 00:28:42 +00:00
.. New derived data series representing an estimate of core temperature on the basis of HR changes. * shown on AllPlot and RideSummary * 2 new metrics; max and avg core temperature .. This has been based upon "Estimation of human core temperature from sequential heart rate observations" Mark J Buller, William J Tharion, Samuel N Cheuvront, Scott J Montain, Robert W Kenefick, John Castellani, William A Latzka, Warren S Roberts, Mark Richter, Odest Chadwicke Jenkins and Reed W Hoyt. (2013). Physiological Measurement. IOP Publishing 34 (2013) 781–798.
661 lines
21 KiB
C++
661 lines
21 KiB
C++
/*
|
||
* Copyright (c) 2012 Damien Grauser (Damien.Grauser@pev-geneve.ch)
|
||
*
|
||
* This program 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 2 of the License, or (at your option)
|
||
* any later version.
|
||
*
|
||
* This program 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 this program; if not, write to the Free Software Foundation, Inc., 51
|
||
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||
*/
|
||
|
||
#include "Bin2RideFile.h"
|
||
#include <cmath>
|
||
|
||
#define START 0x210
|
||
#define UNIT_VERSION 0x2000
|
||
#define SYSTEM_INFO 0x2003
|
||
|
||
#define BIN2_DEBUG false // debug traces
|
||
|
||
static int bin2FileReaderRegistered =
|
||
RideFileFactory::instance().registerReader(
|
||
"bin2", "Joule GPS File", new Bin2FileReader());
|
||
|
||
|
||
struct Bin2FileReaderState
|
||
{
|
||
QFile &file;
|
||
QStringList &errors;
|
||
RideFile *rideFile;
|
||
int data_version;
|
||
|
||
double secs, km;
|
||
|
||
int interval;
|
||
double last_interval_secs;
|
||
|
||
bool jouleGPS;
|
||
bool stopped;
|
||
|
||
QString deviceInfo;
|
||
|
||
Bin2FileReaderState(QFile &file, QStringList &errors) :
|
||
file(file), errors(errors), rideFile(NULL), secs(0), km(0),
|
||
interval(0), last_interval_secs(0.0), jouleGPS(true), stopped(true)
|
||
{
|
||
|
||
}
|
||
|
||
struct TruncatedRead {};
|
||
|
||
int bcd2Int(char c)
|
||
{
|
||
return (0xff & c) - (((0xff & c)/16)*6);
|
||
}
|
||
|
||
double read_bytes(int len, int *count = NULL, int *sum = NULL)
|
||
{
|
||
char c;
|
||
double res = 0;
|
||
for (int i = 0; i < len; ++i) {
|
||
if (file.read(&c, 1) != 1)
|
||
throw TruncatedRead();
|
||
if (sum)
|
||
*sum += (0xff & c);
|
||
if (count)
|
||
*count += 1;
|
||
|
||
res += pow(256,i) * (0xff & (unsigned) c) ;
|
||
}
|
||
return res;
|
||
}
|
||
|
||
QString read_text(int len, int *count = NULL, int *sum = NULL)
|
||
{
|
||
char c;
|
||
QString res = "";
|
||
for (int i = 0; i < len; ++i) {
|
||
if (file.read(&c, 1) != 1)
|
||
throw TruncatedRead();
|
||
if (sum)
|
||
*sum += (0xff & c);
|
||
if (count)
|
||
*count += 1;
|
||
|
||
if (c != 0)
|
||
res += c;
|
||
}
|
||
return res;
|
||
}
|
||
|
||
QDateTime read_date(int *bytes_read = NULL, int *sum = NULL)
|
||
{
|
||
int sec = bcd2Int(read_bytes(1, bytes_read, sum));
|
||
int min = bcd2Int(read_bytes(1, bytes_read, sum));
|
||
int hour = bcd2Int(read_bytes(1, bytes_read, sum));
|
||
int day = bcd2Int(read_bytes(1, bytes_read, sum));
|
||
int month = bcd2Int(read_bytes(1, bytes_read, sum));
|
||
int year = bcd2Int(read_bytes(1, bytes_read, sum));
|
||
|
||
return QDateTime(QDate(2000+year,month,day), QTime(hour,min,sec));
|
||
}
|
||
|
||
QDateTime read_RTC_mark(double *secs, int *bytes_read = NULL, int *sum = NULL)
|
||
{
|
||
QDateTime date = read_date(bytes_read, sum);
|
||
|
||
if (jouleGPS) {
|
||
read_bytes(1, bytes_read, sum); // dummy
|
||
read_bytes(4, bytes_read, sum); // time_moving
|
||
|
||
// time
|
||
double newsecs = double(read_bytes(4, bytes_read, sum));
|
||
if (BIN2_DEBUG)
|
||
qDebug() << "read_RTC_mark new ridetime" << newsecs << "secs (old" << *secs <<"secs)";
|
||
|
||
*secs = newsecs;
|
||
read_bytes(16, bytes_read, sum); // dummy
|
||
} else {
|
||
read_bytes(13, bytes_read, sum); // dummy
|
||
}
|
||
|
||
return date;
|
||
}
|
||
|
||
int read_interval_mark(double *secs, int *bytes_read = NULL, int *sum = NULL)
|
||
{
|
||
int intervalNumber = read_bytes(1, bytes_read, sum);
|
||
|
||
read_bytes(2, bytes_read, sum); // dummy
|
||
double rideTime = double(read_bytes(4, bytes_read, sum));
|
||
if (BIN2_DEBUG)
|
||
qDebug() << "read_interval_mark" << rideTime << "at" << *secs <<"secs";
|
||
|
||
if (jouleGPS)
|
||
read_bytes(24, bytes_read, sum); // dummy
|
||
else
|
||
read_bytes(12, bytes_read, sum); // dummy
|
||
|
||
return intervalNumber;
|
||
}
|
||
|
||
void read_detail_record(double *secs, int *bytes_read = NULL, int *sum = NULL)
|
||
{
|
||
int cad = 0;
|
||
int lrbal = 0;
|
||
int hr = 0;
|
||
int watts = 0;
|
||
int nm = 0;
|
||
double kph = 0.0;
|
||
int alt = 0;
|
||
double temp = RideFile::NoTemp;
|
||
double lat = 0.0;
|
||
double lng = 0.0;
|
||
double km = 0.0;
|
||
|
||
if (jouleGPS) {
|
||
cad = read_bytes(1, bytes_read, sum);
|
||
|
||
read_bytes(1, bytes_read, sum); // pedal_smoothness
|
||
|
||
lrbal = read_bytes(1, bytes_read, sum);
|
||
hr = read_bytes(1, bytes_read, sum);
|
||
|
||
read_bytes(1, bytes_read, sum); // dummy
|
||
|
||
watts = read_bytes(2, bytes_read, sum);
|
||
nm = read_bytes(2, bytes_read, sum);
|
||
kph = read_bytes(2, bytes_read, sum);
|
||
alt = read_bytes(2, bytes_read, sum); // todo this value is signed
|
||
temp = read_bytes(2, bytes_read, sum); // °C × 10 todo this value is signed
|
||
lat = read_bytes(4, bytes_read, sum); // todo this value is signed
|
||
lng = read_bytes(4, bytes_read, sum); // todo this value is signed
|
||
km = read_bytes(8, bytes_read, sum)/1000.0/1000.0;
|
||
} else {
|
||
read_bytes(1, bytes_read, sum); // dropout flag
|
||
|
||
cad = read_bytes(1, bytes_read, sum);
|
||
hr = read_bytes(1, bytes_read, sum);
|
||
kph = read_bytes(2, bytes_read, sum);
|
||
watts = read_bytes(2, bytes_read, sum);
|
||
nm = read_bytes(2, bytes_read, sum);
|
||
alt = read_bytes(2, bytes_read, sum); // todo this value is signed
|
||
temp = read_bytes(2, bytes_read, sum); // °C × 10 todo this value is signed
|
||
|
||
read_bytes(2, bytes_read, sum); // dummy
|
||
|
||
km = read_bytes(4, bytes_read, sum)/1000.0/1000.0;
|
||
}
|
||
|
||
// Validations
|
||
if (lrbal == 0xFF)
|
||
lrbal = 0;
|
||
else if ((lrbal & 0x200) == 0x200)
|
||
lrbal = 100-(lrbal & 0x3F);
|
||
else
|
||
lrbal = lrbal & 0x3F;
|
||
|
||
if (cad == 0xFF)
|
||
cad = 0;
|
||
|
||
if (hr == 0xFF)
|
||
hr = 0;
|
||
|
||
if (watts == 0xFFFF) // 65535
|
||
watts = 0;
|
||
|
||
if (kph == 0xFFFF) // 65535
|
||
kph = 0;
|
||
else
|
||
kph = kph/10.0;
|
||
|
||
if (temp == 0x8000) //0x8000 = invalid
|
||
temp = RideFile::NoTemp;
|
||
else if (temp > 0x7FFF) // Negative
|
||
temp = (temp-0xFFFF)/10.0;
|
||
else
|
||
temp = temp/10.0;
|
||
|
||
if (alt == 0x8000)
|
||
alt = 0;
|
||
else if (alt > 0x7FFF) // Negative
|
||
alt = (alt-0xFFFF);
|
||
|
||
if (lat == 0x80000000) //0x80000000 = invalid
|
||
lat = 0;
|
||
else if (lat > 0x7FFFFFFF) // Negative
|
||
lat = (lat-0xFFFFFFFF)/10000000.0;
|
||
else
|
||
lat = lat/10000000.0;
|
||
|
||
if (lng == 0x80000000) //0x80000000 = invalid
|
||
lng = 0;
|
||
else if (lng > 0x7FFFFFFF) // Negative
|
||
lng = (lng-0xFFFFFFFF)/10000000.0;
|
||
else
|
||
lng = lng/10000000.0;
|
||
|
||
// 0.0 values at end are for garmin vector torque efficiency/pedal smoothness which are not available
|
||
rideFile->appendPoint(*secs, cad, hr, km, kph, nm, watts, alt, lng, lat, 0.0, 0, temp, lrbal, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, interval);
|
||
(*secs)++;
|
||
}
|
||
|
||
void read_header(uint16_t &header, uint16_t &command, uint16_t &length, int *bytes_read = NULL, int *sum = NULL)
|
||
{
|
||
header = read_bytes(2, bytes_read, sum);
|
||
command = read_bytes(2, bytes_read, sum);
|
||
length = read_bytes(2, bytes_read, sum);
|
||
}
|
||
|
||
void read_ride_summary(int *bytes_read = NULL, int *sum = NULL)
|
||
{
|
||
data_version = read_bytes(1, bytes_read, sum); // data_version
|
||
read_bytes(1, bytes_read, sum); // firmware_minor_version
|
||
|
||
QDateTime t = read_date(bytes_read, sum);
|
||
|
||
rideFile->setStartTime(t);
|
||
|
||
if (jouleGPS)
|
||
{
|
||
read_bytes(148, bytes_read, sum);
|
||
|
||
if (data_version >= 4)
|
||
read_bytes(8, bytes_read, sum);
|
||
|
||
if (data_version >= 6)
|
||
read_bytes(8, bytes_read, sum);
|
||
} else
|
||
{
|
||
read_bytes(84, bytes_read, sum);
|
||
}
|
||
}
|
||
|
||
void read_interval_summary(int *bytes_read = NULL, int *sum = NULL)
|
||
{
|
||
int interval_summary_size = 32;
|
||
if (data_version>=4)
|
||
interval_summary_size = 36;
|
||
read_bytes(interval_summary_size*100, bytes_read, sum);
|
||
}
|
||
|
||
void read_username(int *bytes_read = NULL, int *sum = NULL)
|
||
{
|
||
QString name = read_text(20, bytes_read, sum);
|
||
//deviceInfo += QString("User : %1\n").arg(name);
|
||
}
|
||
|
||
void read_user_info_record(int *bytes_read = NULL, int *sum = NULL)
|
||
{
|
||
read_bytes(64, bytes_read, sum);
|
||
|
||
int smartbelt_A = read_bytes(2, bytes_read, sum);
|
||
int smartbelt_B = read_bytes(2, bytes_read, sum);
|
||
int smartbelt_C = read_bytes(2, bytes_read, sum);
|
||
deviceInfo += QString("Smartbelt %1-%2-%3\n").arg(smartbelt_A).arg(smartbelt_B).arg(smartbelt_C);
|
||
|
||
read_bytes(42, bytes_read, sum);
|
||
|
||
if (data_version>=6)
|
||
read_bytes(4, bytes_read, sum);
|
||
|
||
if (data_version>=8)
|
||
read_bytes(20, bytes_read, sum);
|
||
}
|
||
|
||
void read_ant_info_record(int *bytes_read = NULL, int *sum = NULL)
|
||
{
|
||
for (int i = 0; i < 6; i++) {
|
||
int device_type = read_bytes(1, bytes_read, sum);
|
||
if (device_type < 255) {
|
||
QString text = read_text(20, bytes_read, sum);
|
||
|
||
for(int i=0; i < text.length(); i++)
|
||
{
|
||
if (text.at(i) == QChar(0))
|
||
text = text.left(i);
|
||
}
|
||
|
||
//while (text.endsWith( QChar(0) )) text.chop(1);
|
||
|
||
read_bytes(1, bytes_read, sum); // flag
|
||
uint16_t id = read_bytes(2, bytes_read, sum);
|
||
read_bytes(2, bytes_read, sum);
|
||
read_bytes(2, bytes_read, sum);
|
||
QString device_type_str;
|
||
if (device_type == 11)
|
||
device_type_str = "Primary Power Id";
|
||
else if (device_type == 120)
|
||
device_type_str = "Chest strap Id";
|
||
else
|
||
device_type_str = QString("ANT %1 Id").arg(device_type);
|
||
|
||
deviceInfo += QString("%1 %2 %3\n").arg(device_type_str).arg(id).arg(text);
|
||
}
|
||
}
|
||
}
|
||
|
||
// pages
|
||
int read_summary_page()
|
||
{
|
||
int sum = 0;
|
||
int bytes_read = 0;
|
||
|
||
char header1 = read_bytes(1, &bytes_read, &sum); // Always 0x10
|
||
char header2 = read_bytes(1, &bytes_read, &sum); // Always 0x02
|
||
uint16_t command = read_bytes(2, &bytes_read, &sum);
|
||
|
||
|
||
if (header1 == 0x10 && header2 == 0x02 && command == 0x2022)
|
||
{
|
||
uint16_t length = read_bytes(2, &bytes_read, &sum);
|
||
uint16_t page_number = read_bytes(2, &bytes_read, &sum); // Page #
|
||
|
||
if (page_number == 0) {
|
||
// Page #0
|
||
if (jouleGPS) {
|
||
read_ride_summary(&bytes_read, &sum);
|
||
read_interval_summary(&bytes_read, &sum);
|
||
read_username(&bytes_read, &sum);
|
||
read_user_info_record(&bytes_read, &sum);
|
||
read_ant_info_record(&bytes_read, &sum);
|
||
} else {
|
||
read_ride_summary(&bytes_read, &sum);
|
||
// page still contains 47 interval_summary
|
||
}
|
||
|
||
|
||
int finish = length+6-bytes_read;
|
||
|
||
for (int i = 0; i < finish; i++) {
|
||
read_bytes(1, &bytes_read, &sum); // to finish
|
||
}
|
||
|
||
read_bytes(1, &bytes_read, &sum); // checksum
|
||
|
||
} else {
|
||
if (page_number == 1 && !jouleGPS) {
|
||
//page still contains 48 interval_summary
|
||
int finish = length+6-bytes_read;
|
||
|
||
for (int i = 0; i < finish; i++) {
|
||
read_bytes(1, &bytes_read, &sum); // to finish
|
||
}
|
||
|
||
read_bytes(1, &bytes_read, &sum); // checksum
|
||
}
|
||
// not a summary page !
|
||
}
|
||
|
||
|
||
}
|
||
|
||
return bytes_read;
|
||
}
|
||
|
||
int read_detail_page()
|
||
{
|
||
int sum = 0;
|
||
int bytes_read = 0;
|
||
|
||
char header1 = read_bytes(1, &bytes_read, &sum); // Always 0x10
|
||
char header2 = read_bytes(1, &bytes_read, &sum); // Always 0x02
|
||
uint16_t command = read_bytes(2, &bytes_read, &sum);
|
||
|
||
if (header1 == 0x10 && header2 == 0x02 && command == 0x2022)
|
||
{
|
||
read_bytes(2, &bytes_read, &sum); // length
|
||
uint16_t page_number = read_bytes(2, &bytes_read, &sum); // Page #
|
||
|
||
if (page_number == 2 && !jouleGPS) {
|
||
//page still contains 5 interval_summary in 2 blocks of 256k
|
||
read_bytes(512, &bytes_read, &sum);
|
||
|
||
}
|
||
|
||
if (page_number > 0) {
|
||
if (BIN2_DEBUG)
|
||
qDebug() << "page_number" << page_number;
|
||
int nb_record = 128;
|
||
|
||
// Page # >0
|
||
// Joule GPS : 128 x record (32k)
|
||
|
||
if (!jouleGPS) {
|
||
// Page # = 2
|
||
// Joule : 168 x record (20k)
|
||
// Page # > 1
|
||
// Joule : 192 x record (20k)
|
||
|
||
if (page_number == 2)
|
||
nb_record = 168;
|
||
else
|
||
nb_record = 192;
|
||
}
|
||
|
||
QDateTime t;
|
||
|
||
|
||
for (int i = 0; i < nb_record; i++) {
|
||
int flag = read_bytes(1, &bytes_read, &sum);
|
||
//b0..b1: "00" Detail Record
|
||
//b0..b1: "01" RTC Mark Record
|
||
//b0..b1: "10" Session Mark (Joule GPS)
|
||
//b0..b1: "10" Interval Record (Joule 1.0)
|
||
//b0..b1: "11" Interval Record (Joule GPS)
|
||
//b0..b1: "11" Invalid ( 0xFF)
|
||
|
||
|
||
//b3: Power was calculated
|
||
//b4: HR packet missing
|
||
//b5: CAD packet missing
|
||
//b6: PWR packet missing
|
||
//b7: Power data = old (No new power calculated)
|
||
|
||
if (BIN2_DEBUG && (flag & 0x03) != 0) {
|
||
qDebug() << "flag B0..B1" << (flag & 0x03) << "flag" << flag;
|
||
if (flag == 0xff) {
|
||
qDebug() << "Invalid record";
|
||
}
|
||
else {
|
||
if ((flag & 0x08) == 0x08) {
|
||
qDebug() << "Power was calculated";
|
||
}
|
||
if ((flag & 0x10) == 0x10) {
|
||
qDebug() << "HPR packet missing";
|
||
}
|
||
if ((flag & 0x20) == 0x20) {
|
||
qDebug() << "CAD packet missing";
|
||
}
|
||
if ((flag & 0x40) == 0x40) {
|
||
qDebug() << "PWR packet missing";
|
||
}
|
||
if ((flag & 0x80) == 0x80) {
|
||
qDebug() << "Power data = old";
|
||
}
|
||
}
|
||
}
|
||
|
||
if (flag == 0xff) {
|
||
// means invalid entry
|
||
if (BIN2_DEBUG)
|
||
qDebug() << "invalid at" << secs << "secs";
|
||
if (jouleGPS)
|
||
read_bytes(31, &bytes_read, &sum); // dummy
|
||
else
|
||
read_bytes(19, &bytes_read, &sum); // dummy
|
||
//increase seconds
|
||
(secs)++;
|
||
}
|
||
else if ((flag & 0x03) == 0x01){
|
||
// The RTC Mark is written when there is a gap in the ride data,
|
||
// or when the internal Real Time Clock is adjusted.
|
||
t= read_RTC_mark(&secs, &bytes_read, &sum);
|
||
}
|
||
else if ((jouleGPS && (flag & 0x03) == 0x03) || (!jouleGPS && (flag & 0x03) == 0x02)) {
|
||
// The Interval Mark immediately precedes a Detail Record at the same RTC time.
|
||
int t = read_interval_mark(&secs, &bytes_read, &sum);
|
||
interval = t;
|
||
}
|
||
else if ((flag & 0x03) == 0x00 ){
|
||
// The detail record contains current telemetry data.
|
||
read_detail_record(&secs, &bytes_read, &sum);
|
||
} else {
|
||
if (BIN2_DEBUG)
|
||
qDebug() << "UNKNOW: flag" << flag << "at" << secs << "secs";
|
||
|
||
if (jouleGPS)
|
||
read_bytes(31, &bytes_read, &sum); // dummy
|
||
else
|
||
read_bytes(19, &bytes_read, &sum); // dummy
|
||
}
|
||
|
||
if (!jouleGPS && (i+1)%12 == 0)
|
||
read_bytes(16, &bytes_read, &sum); // unused
|
||
|
||
}
|
||
read_bytes(1, &bytes_read, &sum); // checksum
|
||
|
||
}
|
||
|
||
|
||
}
|
||
|
||
return bytes_read;
|
||
}
|
||
|
||
int read_version()
|
||
{
|
||
int sum = 0;
|
||
int bytes_read = 0;
|
||
|
||
uint16_t header = read_bytes(2, &bytes_read, &sum); // Always 0x210 (0x10-0x02)
|
||
uint16_t command = read_bytes(2, &bytes_read, &sum);
|
||
|
||
if (header == START && command == UNIT_VERSION)
|
||
{
|
||
read_bytes(2, &bytes_read, &sum); // length
|
||
|
||
int major_version = read_bytes(1, &bytes_read, &sum);
|
||
int minor_version = read_bytes(2, &bytes_read, &sum);
|
||
|
||
int data_version = 1;
|
||
|
||
if (major_version == 18)
|
||
{
|
||
jouleGPS = false;
|
||
} else
|
||
{
|
||
jouleGPS = true;
|
||
}
|
||
|
||
|
||
if (jouleGPS)
|
||
data_version = read_bytes(2, &bytes_read, &sum);
|
||
|
||
QString version = QString(minor_version<100?"%1.0%2 (%3)":"%1.%2 (%3)").arg(major_version).arg(minor_version).arg(data_version);
|
||
if (jouleGPS)
|
||
deviceInfo += "Joule GPS";
|
||
else
|
||
deviceInfo += "Joule";
|
||
|
||
deviceInfo += QString(" Version %1\n").arg(version);
|
||
|
||
|
||
|
||
|
||
read_bytes(1, &bytes_read, &sum); // checksum
|
||
}
|
||
return bytes_read;
|
||
}
|
||
|
||
int read_system_info()
|
||
{
|
||
int sum = 0;
|
||
int bytes_read = 0;
|
||
|
||
uint16_t header = read_bytes(2, &bytes_read, &sum); // Always (0x10-0x02)
|
||
uint16_t command = read_bytes(2, &bytes_read, &sum);
|
||
|
||
|
||
if (header == START && command == SYSTEM_INFO)
|
||
{
|
||
read_bytes(2, &bytes_read, &sum); // length
|
||
|
||
if (jouleGPS)
|
||
read_bytes(52, &bytes_read, &sum);
|
||
else
|
||
read_bytes(50, &bytes_read, &sum);
|
||
|
||
uint16_t odometer = read_bytes(8, &bytes_read, &sum);
|
||
deviceInfo += QString("Odometer %1km\n").arg(odometer/1000.0);
|
||
|
||
if (!jouleGPS)
|
||
read_bytes(34, &bytes_read, &sum);
|
||
|
||
read_bytes(1, &bytes_read, &sum); // checksum
|
||
}
|
||
return bytes_read;
|
||
}
|
||
|
||
|
||
|
||
RideFile * run() {
|
||
errors.clear();
|
||
rideFile = new RideFile;
|
||
rideFile->setFileFormat("CycleOps Joule (bin2)");
|
||
rideFile->setRecIntSecs(1);
|
||
|
||
if (!file.open(QIODevice::ReadOnly)) {
|
||
delete rideFile;
|
||
return NULL;
|
||
}
|
||
bool stop = false;
|
||
|
||
int data_size = file.size();
|
||
int bytes_read = 0;
|
||
|
||
bytes_read += read_version();
|
||
|
||
if (jouleGPS)
|
||
rideFile->setDeviceType("Joule GPS");
|
||
else
|
||
rideFile->setDeviceType("Joule");
|
||
|
||
bytes_read += read_system_info();
|
||
bytes_read += read_summary_page();
|
||
if (!jouleGPS)
|
||
bytes_read += read_summary_page();
|
||
|
||
while (!stop && (bytes_read < data_size)) {
|
||
bytes_read += read_detail_page(); // read_page(stop, errors);
|
||
}
|
||
|
||
rideFile->setTag("Device Info", deviceInfo);
|
||
|
||
if (stop) {
|
||
file.close();
|
||
delete rideFile;
|
||
return NULL;
|
||
|
||
} else {
|
||
file.close();
|
||
return rideFile;
|
||
}
|
||
}
|
||
};
|
||
|
||
RideFile *Bin2FileReader::openRideFile(QFile &file, QStringList &errors, QList<RideFile*>*) const
|
||
{
|
||
QSharedPointer<Bin2FileReaderState> state(new Bin2FileReaderState(file, errors));
|
||
return state->run();
|
||
}
|