mirror of
https://github.com/GoldenCheetah/GoldenCheetah.git
synced 2026-04-15 05:32:21 +00:00
Joule GPS Support
This is BETA support for downloading ride files from the new Cyclops Powertap Joule GPS.
This commit is contained in:
committed by
Mark Liversedge
parent
07c2bafb08
commit
6e6b36f2af
417
src/Bin2RideFile.cpp
Normal file
417
src/Bin2RideFile.cpp
Normal file
@@ -0,0 +1,417 @@
|
||||
/*
|
||||
* 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 <math.h>
|
||||
|
||||
#define START 0x210
|
||||
#define UNIT_VERSION 0x2000
|
||||
#define SYSTEM_INFO 0x2003
|
||||
|
||||
static int bin2FileReaderRegistered =
|
||||
RideFileFactory::instance().registerReader(
|
||||
"bin2", "Joule GPS File", new Bin2FileReader());
|
||||
|
||||
|
||||
struct Bin2FileReaderState
|
||||
{
|
||||
QFile &file;
|
||||
QStringList &errors;
|
||||
RideFile *rideFile;
|
||||
|
||||
double secs, km;
|
||||
|
||||
int interval;
|
||||
double last_interval_secs;
|
||||
|
||||
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), stopped(true)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
struct TruncatedRead {};
|
||||
|
||||
int bcd2Int(char c)
|
||||
{
|
||||
return (0xff & c) - (((0xff & c)/16)*6);
|
||||
}
|
||||
|
||||
int read_bytes(int len, int *count = NULL, int *sum = NULL)
|
||||
{
|
||||
char c;
|
||||
int 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;
|
||||
|
||||
res += c;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
QDateTime read_date(double *secs, 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(secs, bytes_read, sum);
|
||||
|
||||
int dummy1 = read_bytes(1, bytes_read, sum);
|
||||
int time_moving = read_bytes(4, bytes_read, sum);
|
||||
int secs2 = read_bytes(4, bytes_read, sum);
|
||||
int dummy2 = read_bytes(16, bytes_read, sum);
|
||||
|
||||
return date;
|
||||
}
|
||||
|
||||
void read_detail_record(double *secs, int *bytes_read = NULL, int *sum = NULL)
|
||||
{
|
||||
int cad = read_bytes(1, bytes_read, sum);
|
||||
int pedal_smoothness = read_bytes(1, bytes_read, sum);
|
||||
int lrbal = read_bytes(1, bytes_read, sum);
|
||||
int hr = read_bytes(1, bytes_read, sum);
|
||||
int dummy = read_bytes(1, bytes_read, sum);
|
||||
int watts = read_bytes(2, bytes_read, sum);
|
||||
int nm = read_bytes(2, bytes_read, sum);
|
||||
double kph = read_bytes(2, bytes_read, sum);
|
||||
int alt = read_bytes(2, bytes_read, sum);
|
||||
double temp = read_bytes(2, bytes_read, sum)/10.0;
|
||||
double lat = read_bytes(4, bytes_read, sum);
|
||||
double lng = read_bytes(4, bytes_read, sum);
|
||||
double km = read_bytes(8, bytes_read, sum)/1000.0/1000.0;
|
||||
|
||||
// Validations
|
||||
if (lrbal == 0xFF)
|
||||
lrbal = 0;
|
||||
else if ((lrbal & 0x200) == 0x200)
|
||||
lrbal = 100-lrbal;
|
||||
|
||||
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)
|
||||
temp = 0;
|
||||
|
||||
if (alt == 0x8000)
|
||||
alt = 0;
|
||||
|
||||
if (lat == -2147483648) //2147483648
|
||||
lat = 0;
|
||||
else
|
||||
lat = lat/10000000.0;
|
||||
|
||||
if (lng == -2147483648) //0x80000000
|
||||
lng = 0;
|
||||
else
|
||||
lng = lng/10000000.0;
|
||||
|
||||
rideFile->appendPoint(*secs, cad, hr, km, kph, nm, watts, alt, lng, lat, 0.0, 0, temp, lrbal, interval);
|
||||
(*secs)++;
|
||||
}
|
||||
|
||||
void read_header(uint16_t &header, uint16_t &command, u_int16_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)
|
||||
{
|
||||
char data_version = read_bytes(1, bytes_read, sum);
|
||||
char firmware_minor_version = read_bytes(1, bytes_read, sum);
|
||||
|
||||
double *sec;
|
||||
QDateTime t = read_date(sec, bytes_read, sum);
|
||||
|
||||
rideFile->setStartTime(t);
|
||||
|
||||
read_bytes(148, bytes_read, sum);
|
||||
}
|
||||
|
||||
void read_interval_summary(int *bytes_read = NULL, int *sum = NULL)
|
||||
{
|
||||
read_bytes(3200, 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);
|
||||
}
|
||||
|
||||
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);
|
||||
while(text.endsWith( QChar(0) )) text.chop(1);
|
||||
QChar *chr = text.end();
|
||||
int i = chr->toAscii();
|
||||
|
||||
int flag = read_bytes(1, bytes_read, sum);
|
||||
u_int16_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); // Always 0x10
|
||||
|
||||
|
||||
if (header1 == 0x10 && header2 == 0x02 && command == 0x2022)
|
||||
{
|
||||
u_int16_t length = read_bytes(2, &bytes_read, &sum); // Always 4098 for Joule GPS
|
||||
u_int16_t page_number = read_bytes(2, &bytes_read, &sum); // Page #
|
||||
|
||||
if (page_number == 0) {
|
||||
// Page #0
|
||||
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);
|
||||
|
||||
int finish = length+6-bytes_read;
|
||||
|
||||
for (int i = 0; i < finish; i++) {
|
||||
read_bytes(1, &bytes_read, &sum); // to finish
|
||||
}
|
||||
|
||||
char checksum = read_bytes(1, &bytes_read, &sum); // Always 0x10
|
||||
|
||||
} else {
|
||||
// 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); // Always 0x10
|
||||
|
||||
|
||||
if (header1 == 0x10 && header2 == 0x02 && command == 0x2022)
|
||||
{
|
||||
u_int16_t length = read_bytes(2, &bytes_read, &sum); // Always 4098
|
||||
u_int16_t page_number = read_bytes(2, &bytes_read, &sum); // Page #
|
||||
|
||||
if (page_number > 0) {
|
||||
// Page # >0
|
||||
// 128 x 32k
|
||||
QDateTime t;
|
||||
|
||||
|
||||
for (int i = 0; i < 128; i++) {
|
||||
int flag = read_bytes(1, &bytes_read, &sum);
|
||||
|
||||
if ((flag & 0x03) == 0x01 || (flag & 0x03) == 0x03){
|
||||
t= read_RTC_mark(&secs, &bytes_read, &sum);
|
||||
if ((flag & 0x03) == 0x03)
|
||||
interval++;
|
||||
}
|
||||
else if ((flag & 0x03) == 0x00 ){
|
||||
read_detail_record(&secs, &bytes_read, &sum);
|
||||
}
|
||||
|
||||
}
|
||||
char checksum = read_bytes(1, &bytes_read, &sum); // Always 0x10
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
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); // Always 0x10
|
||||
|
||||
if (header == START && command == UNIT_VERSION)
|
||||
{
|
||||
u_int16_t length = read_bytes(2, &bytes_read, &sum); // Always 4098 for Joule GPS
|
||||
|
||||
int major_version = read_bytes(1, &bytes_read, &sum);
|
||||
int minor_version = read_bytes(2, &bytes_read, &sum);
|
||||
int 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);
|
||||
deviceInfo += rideFile->deviceType()+QString(" Version %1\n").arg(version);
|
||||
|
||||
char checksum = read_bytes(1, &bytes_read, &sum); // Always 4098 for Joule GPS
|
||||
}
|
||||
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); // Always 0x10
|
||||
|
||||
|
||||
if (header == START && command == SYSTEM_INFO)
|
||||
{
|
||||
u_int16_t length = read_bytes(2, &bytes_read, &sum); // Always 4098 for Joule GPS
|
||||
|
||||
read_bytes(52, &bytes_read, &sum);
|
||||
u_int16_t odometer = read_bytes(8, &bytes_read, &sum); // Always 4098 for Joule GPS
|
||||
deviceInfo += QString("Odometer %1km\n").arg(odometer/1000.0);
|
||||
|
||||
char checksum = read_bytes(1, &bytes_read, &sum); // Always 4098 for Joule GPS
|
||||
}
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
|
||||
|
||||
RideFile * run() {
|
||||
errors.clear();
|
||||
rideFile = new RideFile;
|
||||
rideFile->setDeviceType("Joule GPS");
|
||||
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();
|
||||
bytes_read += read_system_info();
|
||||
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) {
|
||||
delete rideFile;
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
return rideFile;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
RideFile *Bin2FileReader::openRideFile(QFile &file, QStringList &errors, QList<RideFile*>*) const
|
||||
{
|
||||
QSharedPointer<Bin2FileReaderState> state(new Bin2FileReaderState(file, errors));
|
||||
return state->run();
|
||||
}
|
||||
30
src/Bin2RideFile.h
Normal file
30
src/Bin2RideFile.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef _Bin2RideFile_h
|
||||
#define _Bin2RideFile_h
|
||||
#include "GoldenCheetah.h"
|
||||
|
||||
#include "RideFile.h"
|
||||
|
||||
struct Bin2FileReader : public RideFileReader {
|
||||
virtual RideFile *openRideFile(QFile &file, QStringList &errors, QList<RideFile*>* = 0) const;
|
||||
bool hasWrite() const { return false; }
|
||||
};
|
||||
|
||||
#endif // _Bin2RideFile_h
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2007 Sean C. Rhea (srhea@srhea.net)
|
||||
* 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
|
||||
|
||||
@@ -42,6 +42,8 @@ class CommPort
|
||||
virtual int read(void *buf, size_t nbyte, QString &err) = 0;
|
||||
virtual int write(void *buf, size_t nbyte, QString &err) = 0;
|
||||
virtual QString name() const = 0;
|
||||
virtual bool setBaudRate(int speed, QString &err) = 0;
|
||||
|
||||
QString type( void ) const;
|
||||
QString id( void ) const;
|
||||
|
||||
|
||||
13
src/D2XX.cpp
13
src/D2XX.cpp
@@ -195,6 +195,19 @@ D2XX::name() const
|
||||
return info.Description;
|
||||
}
|
||||
|
||||
bool
|
||||
D2XX::setBaudRate(int speed, QString &err)
|
||||
{
|
||||
assert(_isOpen);
|
||||
FT_STATUS ftStatus = lib->set_baud_rate(ftHandle, speed);
|
||||
if (ftStatus != FT_OK) {
|
||||
err = QString("FT_SetBaudRate: %1").arg(ftStatus);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QVector<CommPortPtr>
|
||||
D2XX::myListCommPorts(QString &err)
|
||||
{
|
||||
|
||||
@@ -47,6 +47,7 @@ class D2XX : public CommPort
|
||||
virtual int read(void *buf, size_t nbyte, QString &err);
|
||||
virtual int write(void *buf, size_t nbyte, QString &err);
|
||||
virtual QString name() const;
|
||||
virtual bool setBaudRate(int speed, QString &err);
|
||||
};
|
||||
|
||||
#endif // _GC_PT_D2XX_h
|
||||
|
||||
@@ -30,6 +30,12 @@ struct DeviceDownloadFile
|
||||
QString extension;
|
||||
};
|
||||
|
||||
struct DeviceStoredRideItem
|
||||
{
|
||||
int id;
|
||||
QDateTime startTime;
|
||||
};
|
||||
|
||||
struct DeviceRideItem
|
||||
{
|
||||
bool wanted;
|
||||
|
||||
590
src/JouleDevice.cpp
Normal file
590
src/JouleDevice.cpp
Normal file
@@ -0,0 +1,590 @@
|
||||
/*
|
||||
* 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 "JouleDevice.h"
|
||||
#include "DownloadRideDialog.h"
|
||||
#include "PowerTapUtil.h"
|
||||
#include "Device.h"
|
||||
#include <math.h>
|
||||
#include <errno.h>
|
||||
#include <termios.h>
|
||||
|
||||
#define JOULE_DEBUG false // debug traces
|
||||
|
||||
// Start pattern
|
||||
#define START_1 0x10
|
||||
#define START_2 0x02
|
||||
|
||||
// Commands send from PC to Joule
|
||||
#define READ_UNIT_VERSION 0x2000
|
||||
#define GET_FREE_SPACE 0x2002
|
||||
#define READ_SYSTEM_INFO 0x2003
|
||||
#define READ_RIDE_SUMMARY 0x2020
|
||||
#define READ_RIDE_DETAIL 0x2021
|
||||
#define PAGE_RIDE_DETAIL 0x2022
|
||||
#define ERASE_RIDE_DETAIL 0x2024
|
||||
|
||||
static bool jouleRegistered =
|
||||
Devices::addType("Joule GPS (BETA)", DevicesPtr(new JouleDevices()) );
|
||||
|
||||
QString
|
||||
JouleDevices::downloadInstructions() const
|
||||
{
|
||||
return ("Make sure the Joule GPS unit is turned ON\n");
|
||||
}
|
||||
|
||||
DevicePtr
|
||||
JouleDevices::newDevice( CommPortPtr dev, Device::StatusCallback cb )
|
||||
{
|
||||
return DevicePtr( new JouleDevice( dev, cb ));
|
||||
}
|
||||
|
||||
static QString
|
||||
cEscape(char *buf, int len)
|
||||
{
|
||||
char *result = new char[4 * len + 1];
|
||||
char *tmp = result;
|
||||
for (int i = 0; i < len; ++i) {
|
||||
if (buf[i] == '"')
|
||||
tmp += sprintf(tmp, "\\\"");
|
||||
else if (isprint(buf[i]))
|
||||
*(tmp++) = buf[i];
|
||||
else
|
||||
tmp += sprintf(tmp, "\\x%02x", 0xff & (unsigned) buf[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static int
|
||||
bcd2Int(char c)
|
||||
{
|
||||
return (0xff & c) - (((0xff & c)/16)*6);
|
||||
}
|
||||
|
||||
static int
|
||||
qByteArray2Int(QByteArray array)
|
||||
{
|
||||
int result = 0;
|
||||
for (int i = 0; i < array.size(); i++)
|
||||
{
|
||||
result += pow(256,i)*(0xff & array.at(i));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static int
|
||||
readOneByOne(CommPortPtr dev, void *buf, size_t nbyte, QString &err)
|
||||
{
|
||||
char * data = ((char *)buf);
|
||||
int rtn=0;
|
||||
|
||||
for (int i = 0; i < nbyte; i++)
|
||||
{
|
||||
int n = dev->read(data + i, 1, err);
|
||||
if (n <= 0) {
|
||||
return rtn;
|
||||
}
|
||||
if (data[i] == START_1){
|
||||
int n = dev->read(data + i, 1, err);
|
||||
if (n <= 0) {
|
||||
return rtn;
|
||||
}
|
||||
}
|
||||
rtn++;
|
||||
}
|
||||
return rtn;
|
||||
}
|
||||
|
||||
bool
|
||||
JouleDevice::download( const QDir &tmpdir,
|
||||
QList<DeviceDownloadFile> &files,
|
||||
CancelCallback cancelCallback,
|
||||
ProgressCallback progressCallback,
|
||||
QString &err)
|
||||
{
|
||||
if (JOULE_DEBUG) printf("download Joule GPS");
|
||||
|
||||
if (!dev->open(err)) {
|
||||
err = "ERROR: open failed: " + err;
|
||||
return false;
|
||||
}
|
||||
|
||||
dev->setBaudRate(57600, err);
|
||||
|
||||
QString version = QString("");
|
||||
QString serial = QString("");
|
||||
QByteArray versionArray;
|
||||
QByteArray systemInfoArray;
|
||||
|
||||
getUnitVersion(version, versionArray, err);
|
||||
statusCallback("Version"+version);
|
||||
|
||||
getSystemInfo(serial, systemInfoArray, err);
|
||||
|
||||
QList<DeviceStoredRideItem> trainings;
|
||||
getDownloadableRides(trainings, err);
|
||||
|
||||
for (int i=0; i<trainings.count(); i++) {
|
||||
statusCallback(QString("Read ride detail for ride %1/%2").arg(i+1).arg(trainings.count()));
|
||||
JoulePacket request(READ_RIDE_DETAIL);
|
||||
int id1 = (trainings.at(i).id>255?trainings.at(i).id-255:trainings.at(i).id);
|
||||
int id2 = (trainings.at(i).id>255?trainings.at(i).id%255:0);
|
||||
request.addToPayload((char)id1);
|
||||
request.addToPayload((char)id2);
|
||||
request.addToPayload((uint16_t)0xFFFF); // Total Ride#
|
||||
request.addToPayload((uint16_t)0x0000); // Start Page#
|
||||
|
||||
if (!request.write(dev, err)) return false;
|
||||
|
||||
if (cancelCallback())
|
||||
{
|
||||
err = "download cancelled";
|
||||
return false;
|
||||
}
|
||||
|
||||
JoulePacket response = JoulePacket(PAGE_RIDE_DETAIL);
|
||||
if (response.read(dev, err)) {
|
||||
|
||||
if (response.payload.size() < 4096)
|
||||
{
|
||||
err = "no data";
|
||||
return false;
|
||||
}
|
||||
|
||||
int page = qByteArray2Int(response.payload.left(2));
|
||||
int data_version = qByteArray2Int(response.payload.mid(2,1));
|
||||
int firmware = qByteArray2Int(response.payload.mid(3,1));
|
||||
|
||||
QString data = QString("%1 %2-%3").arg(page).arg(data_version).arg(firmware);
|
||||
qDebug() << data;
|
||||
|
||||
if (page < 65535) {
|
||||
// create temporary file
|
||||
QString tmpl = tmpdir.absoluteFilePath(".joule.XXXXXX"); //".joulegps.XXXXXX"
|
||||
QTemporaryFile tmp(tmpl);
|
||||
tmp.setAutoRemove(false);
|
||||
|
||||
if (!tmp.open()) {
|
||||
err = "Failed to create temporary file "
|
||||
+ tmpl + ": " + tmp.error();
|
||||
return false;
|
||||
}
|
||||
|
||||
// timestamp from the first training
|
||||
struct tm start;
|
||||
start.tm_sec = bcd2Int(response.payload.at(4));
|
||||
start.tm_min = bcd2Int(response.payload.at(5));
|
||||
start.tm_hour = bcd2Int(response.payload.at(6));
|
||||
start.tm_mday = bcd2Int(response.payload.at(7));
|
||||
start.tm_mon = bcd2Int(response.payload.at(8))-1;
|
||||
start.tm_year = 2000 + bcd2Int(response.payload.at(9))-1900;
|
||||
start.tm_isdst = -1;
|
||||
|
||||
DeviceDownloadFile file;
|
||||
file.extension = "bin2";
|
||||
file.name = tmp.fileName();
|
||||
file.startTime.setTime_t( mktime( &start ));
|
||||
files.append(file);
|
||||
|
||||
QTextStream os(&tmp);
|
||||
os << hex;
|
||||
|
||||
qDebug() << tmp.fileName() << "-" << tmpl;
|
||||
tmp.write(versionArray);
|
||||
tmp.write(systemInfoArray);
|
||||
tmp.write(response.dataArray());
|
||||
|
||||
int _try = 1;
|
||||
while (page < 65535) {
|
||||
qDebug() << "page"<<page;
|
||||
if (JOULE_DEBUG) printf("Acknowledge\n");
|
||||
|
||||
request = JoulePacket(PAGE_RIDE_DETAIL);
|
||||
request.addToPayload(response.payload.left(2).data(),2);
|
||||
|
||||
if (!request.write(dev, err))
|
||||
return false;
|
||||
|
||||
response = JoulePacket(PAGE_RIDE_DETAIL);
|
||||
|
||||
bool success = false;
|
||||
while (!success) {
|
||||
if (response.read(dev, err)) {
|
||||
page = qByteArray2Int(response.payload.left(2));
|
||||
|
||||
tmp.write(response.dataArray());
|
||||
success = true;
|
||||
} else {
|
||||
if (_try == 3)
|
||||
return false;
|
||||
else {
|
||||
JoulePacket request(READ_RIDE_DETAIL);
|
||||
//request.addToPayload((uint16_t)0x0200); // Ride#
|
||||
request.addToPayload((char)i);
|
||||
request.addToPayload((char)0x00);
|
||||
request.addToPayload((uint16_t)0xFFFF); // Total Ride#
|
||||
request.addToPayload((uint16_t)page); // Start Page#
|
||||
|
||||
if (!request.write(dev, err)) return false;
|
||||
|
||||
response = JoulePacket(PAGE_RIDE_DETAIL);
|
||||
_try ++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
tmp.close();
|
||||
}
|
||||
qDebug() << "end page" << page;
|
||||
|
||||
if (JOULE_DEBUG) printf("Acknowledge\n");
|
||||
request = JoulePacket(PAGE_RIDE_DETAIL);
|
||||
request.addToPayload(response.payload.left(2).data(),2);
|
||||
|
||||
if (!request.write(dev, err)) return false;
|
||||
|
||||
|
||||
} else
|
||||
i=99;
|
||||
}
|
||||
|
||||
dev->close();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
JouleDevice::getUnitVersion(QString &version, QByteArray &array, QString &err)
|
||||
{
|
||||
statusCallback("Get Unit Software Version...");
|
||||
if (JOULE_DEBUG) printf("Get Unit Software Version\n");
|
||||
|
||||
JoulePacket request(READ_UNIT_VERSION);
|
||||
|
||||
if (!request.write(dev, err)) return false;
|
||||
|
||||
JoulePacket response = JoulePacket(READ_UNIT_VERSION);
|
||||
if (response.read(dev, err)) {
|
||||
|
||||
if (response.payload.length()>4) {
|
||||
array = response.dataArray();
|
||||
int major_version = qByteArray2Int(response.payload.left(1));
|
||||
int minor_version = qByteArray2Int(response.payload.mid(1,2));
|
||||
int data_version = qByteArray2Int(response.payload.right(2));
|
||||
|
||||
version = QString(minor_version<100?"%1.0%2 (%3)":"%1.%2 (%3)").arg(major_version).arg(minor_version).arg(data_version);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
JouleDevice::getUnitFreeSpace(QString &memory, QString &err)
|
||||
{
|
||||
statusCallback("Get Unit Free Space...");
|
||||
if (JOULE_DEBUG) printf("Get Unit Free Space\n");
|
||||
|
||||
JoulePacket request1(GET_FREE_SPACE);
|
||||
|
||||
if (!request1.write(dev, err)) return false;
|
||||
|
||||
JoulePacket response1 = JoulePacket(GET_FREE_SPACE);
|
||||
if (response1.read(dev, err)) {
|
||||
|
||||
if (response1.payload.length()>3) {
|
||||
int empty = qByteArray2Int(response1.payload.left(2));
|
||||
int total = qByteArray2Int(response1.payload.right(2));
|
||||
int percentage = 100 * empty / total;
|
||||
memory = QString("%1/%2 (%3%)").arg(empty).arg(total).arg(percentage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
JouleDevice::getSystemInfo(QString &system, QByteArray &array, QString &err)
|
||||
{
|
||||
statusCallback("Get System info...");
|
||||
if (JOULE_DEBUG) printf("Get System info\n");
|
||||
|
||||
JoulePacket request(READ_SYSTEM_INFO);
|
||||
|
||||
if (!request.write(dev, err)) return false;
|
||||
|
||||
JoulePacket response = JoulePacket(READ_SYSTEM_INFO);
|
||||
if (response.read(dev, err)) {
|
||||
|
||||
if (response.payload.length()>3) {
|
||||
array = response.dataArray();
|
||||
int serial = qByteArray2Int(response.payload.left(4));
|
||||
system = QString("%1").arg(serial);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
JouleDevice::getDownloadableRides(QList<DeviceStoredRideItem> &rides, QString &err)
|
||||
{
|
||||
statusCallback("Read ride summary...");
|
||||
if (JOULE_DEBUG) printf("Get Unit Software Version\n");
|
||||
|
||||
JoulePacket request(READ_RIDE_SUMMARY);
|
||||
|
||||
if (!request.write(dev, err)) return false;
|
||||
|
||||
JoulePacket response = JoulePacket(READ_RIDE_SUMMARY);
|
||||
if (response.read(dev, err)) {
|
||||
int count = response.payload.length()/20;
|
||||
|
||||
for (int i=0; i<count; i++) {
|
||||
int j = i*20;
|
||||
int sec = bcd2Int(response.payload.at(j));
|
||||
int min = bcd2Int(response.payload.at(j+1));
|
||||
int hour = bcd2Int(response.payload.at(j+2));
|
||||
int day = bcd2Int(response.payload.at(j+3));
|
||||
int month = bcd2Int(response.payload.at(j+4))-1;
|
||||
int year = 2000 + bcd2Int(response.payload.at(j+5));
|
||||
|
||||
QDateTime date = QDateTime(QDate(year,month,day), QTime(hour,min,sec));
|
||||
|
||||
int total = qByteArray2Int(response.payload.mid(j+18,2));
|
||||
|
||||
if (total > 0) {
|
||||
DeviceStoredRideItem ride;
|
||||
ride.id = i;
|
||||
ride.startTime = date;
|
||||
rides.append(ride);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
JouleDevice::cleanup( QString &err ) {
|
||||
if (JOULE_DEBUG) printf("Erase all records on computer\n");
|
||||
|
||||
if (!dev->open(err)) {
|
||||
err = "ERROR: open failed: " + err;
|
||||
}
|
||||
|
||||
QList<DeviceStoredRideItem> trainings;
|
||||
getDownloadableRides(trainings, err);
|
||||
|
||||
for (int i=0; i<trainings.count(); i++) {
|
||||
statusCallback(QString("Delete ride detail for ride %1/%2").arg(i+1).arg(trainings.count()));
|
||||
JoulePacket request(ERASE_RIDE_DETAIL);
|
||||
int id1 = (trainings.at(i).id>255?trainings.at(i).id-255:trainings.at(i).id);
|
||||
int id2 = (trainings.at(i).id>255?trainings.at(i).id%255:0);
|
||||
request.addToPayload((char)id1);
|
||||
request.addToPayload((char)id2);
|
||||
request.addToPayload((char)id1);
|
||||
request.addToPayload((char)id2);
|
||||
|
||||
if (!request.write(dev, err)) return false;
|
||||
|
||||
JoulePacket response = JoulePacket(READ_SYSTEM_INFO);
|
||||
if (!response.read(dev, err))
|
||||
return false;
|
||||
}
|
||||
|
||||
dev->close();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// --------------------------------------
|
||||
// JoulePacket
|
||||
// --------------------------------------
|
||||
|
||||
JoulePacket::JoulePacket() : command(0)
|
||||
{
|
||||
checksum = 0;
|
||||
payload.clear();
|
||||
}
|
||||
|
||||
JoulePacket::JoulePacket(uint16_t command) : command(command), checksum(command)
|
||||
{
|
||||
//checksum = 0;
|
||||
checksum += (uint8_t)((command & 0xFF00) >> 8);
|
||||
//checksum += (uint8_t)(command & 0x00FF);
|
||||
payload.clear();
|
||||
}
|
||||
|
||||
void
|
||||
JoulePacket::addToPayload(char byte)
|
||||
{
|
||||
checksum += byte;
|
||||
payload.append(byte);
|
||||
}
|
||||
|
||||
void
|
||||
JoulePacket::addToPayload(uint16_t bytes)
|
||||
{
|
||||
payload.append(bytes >> 8);
|
||||
payload.append(bytes & 0x00FF);
|
||||
checksum += (uint8_t)(bytes >> 8);
|
||||
checksum += (uint8_t)(bytes & 0x00FF);
|
||||
}
|
||||
|
||||
void
|
||||
JoulePacket::addToPayload(char *bytes, int len)
|
||||
{
|
||||
for (int i = 0; i < len; ++i) {
|
||||
char byte = bytes[i];
|
||||
checksum += byte;
|
||||
payload.append(byte);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
JoulePacket::verifyCheckSum(CommPortPtr dev, QString &err)
|
||||
{
|
||||
char _checksum;
|
||||
if (JOULE_DEBUG) printf("reading checksum from device\n");
|
||||
int n = dev->read(&_checksum, 1, err);
|
||||
if (n <= 0) {
|
||||
err = (n < 0) ? ("read checksum error: " + err) : "read timeout";
|
||||
return false;
|
||||
}
|
||||
if (JOULE_DEBUG) printf("CheckSum1 %d CheckSum2 %d", (0xff & (unsigned) checksum) , (0xff & (unsigned) _checksum));
|
||||
|
||||
return checksum == _checksum;
|
||||
}
|
||||
|
||||
QByteArray
|
||||
JoulePacket::dataArray()
|
||||
{
|
||||
QByteArray result;
|
||||
result.append(char(START_1));
|
||||
result.append(char(START_2));
|
||||
|
||||
result.append((char)(command & 0x00FF));
|
||||
result.append((char)((command & 0xFF00) >> 8));
|
||||
|
||||
char lenght1 = (char)(payload.length() & 0x00FF);
|
||||
char lenght2 = (char)((payload.length() & 0xFF00) >> 8);
|
||||
result.append(lenght1);
|
||||
result.append(lenght2);
|
||||
|
||||
result.append(payload);
|
||||
|
||||
result.append(checksum+lenght1+lenght2);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
QByteArray
|
||||
JoulePacket::dataArrayForUnit()
|
||||
{
|
||||
QByteArray result = dataArray();
|
||||
|
||||
for (int i = 2; i < result.size(); i++)
|
||||
{
|
||||
if (result.at(i) == START_1) {
|
||||
result.insert(i, START_1);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
JoulePacket::write(CommPortPtr dev, QString &err)
|
||||
{
|
||||
QByteArray bytes = dataArrayForUnit();
|
||||
const char *msg = cEscape(bytes.data(), bytes.count()).toAscii().constData();
|
||||
|
||||
if (JOULE_DEBUG) printf("writing '%s' to device\n", msg);
|
||||
|
||||
int n = dev->write(bytes.data(), bytes.count() , err); //
|
||||
if (n != bytes.count()) {
|
||||
if (n < 0) {
|
||||
if (JOULE_DEBUG) printf("failed to write %s to device: %s\n", msg, err.toAscii().constData());
|
||||
err = QString("failed to write to device: %1").arg(err);
|
||||
}
|
||||
else {
|
||||
if (JOULE_DEBUG) printf("timeout writing %s to device\n", msg);
|
||||
err = QString("timeout writing to device");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (JOULE_DEBUG) printf("writing to device ok\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool
|
||||
JoulePacket::read(CommPortPtr dev, QString &err)
|
||||
{
|
||||
if (JOULE_DEBUG) printf("reading from device\n");
|
||||
int n = dev->read(&startpattern, 2, err);
|
||||
if (n <= 0) {
|
||||
err = (n < 0) ? ("read header error: " + err) : "read timeout";
|
||||
return false;
|
||||
}
|
||||
|
||||
uint16_t _command = 0;
|
||||
n = readOneByOne(dev, &_command, 2, err);
|
||||
if (n <= 0) {
|
||||
err = (n < 0) ? ("read command error: " + err) : "read timeout";
|
||||
return false;
|
||||
} else if (_command != command) {
|
||||
err = "wrong response";
|
||||
return false;
|
||||
}
|
||||
//if (JOULE_DEBUG) printf("command %s\n" , command);
|
||||
// command already in checksum
|
||||
|
||||
n = readOneByOne(dev, &length, 2, err);
|
||||
if (n <= 0) {
|
||||
err = (n < 0) ? ("read length error: " + err) : "read timeout";
|
||||
return false;
|
||||
}
|
||||
if (JOULE_DEBUG) printf("length %d\n" ,length);
|
||||
checksum += (uint8_t)(length >> 8);
|
||||
checksum += (uint8_t)(length & 0x00FF);
|
||||
|
||||
|
||||
char buf[length];
|
||||
n = readOneByOne(dev, &buf, length, err);
|
||||
|
||||
if (n <= 0) {
|
||||
err = (n < 0) ? ("read error: " + err) : "read timeout";
|
||||
return false;
|
||||
} else if (n < length) {
|
||||
err += QString(", read only %1 bytes insteed of: %2")
|
||||
.arg(n).arg(length);
|
||||
return false;
|
||||
}
|
||||
|
||||
//if (JOULE_DEBUG) printf("payload %s\n" ,cEscape(buf,n).toAscii().constData());
|
||||
addToPayload(buf,n);
|
||||
|
||||
char _checksum;
|
||||
n = readOneByOne(dev, &_checksum, 1, err);
|
||||
if (n <= 0) {
|
||||
err = (n < 0) ? ("read checksum error: " + err) : "read timeout";
|
||||
return false;
|
||||
} else if (_checksum != checksum) {
|
||||
err = "wrong _checksum";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
62
src/JouleDevice.h
Normal file
62
src/JouleDevice.h
Normal file
@@ -0,0 +1,62 @@
|
||||
#ifndef JOULEDEVICE_H
|
||||
#define JOULEDEVICE_H
|
||||
|
||||
#include "CommPort.h"
|
||||
#include "Device.h"
|
||||
|
||||
class DeviceFileInfo;
|
||||
|
||||
struct JouleDevices : public Devices
|
||||
{
|
||||
virtual DevicePtr newDevice( CommPortPtr dev, Device::StatusCallback cb );
|
||||
virtual QString downloadInstructions() const;
|
||||
virtual bool canCleanup( void ) {return true; };
|
||||
};
|
||||
|
||||
struct JouleDevice : public Device
|
||||
{
|
||||
JouleDevice( CommPortPtr dev, StatusCallback cb ) :
|
||||
Device( dev, cb ) {};
|
||||
|
||||
virtual bool download( const QDir &tmpdir,
|
||||
QList<DeviceDownloadFile> &files,
|
||||
CancelCallback cancelCallback,
|
||||
ProgressCallback progressCallback,
|
||||
QString &err);
|
||||
|
||||
virtual bool cleanup( QString &err );
|
||||
|
||||
bool getUnitVersion(QString &version, QByteArray &array, QString &err);
|
||||
bool getUnitFreeSpace(QString &version, QString &err);
|
||||
bool getSystemInfo(QString &version, QByteArray &array, QString &err);
|
||||
bool getDownloadableRides(QList<DeviceStoredRideItem> &rides, QString &err);
|
||||
|
||||
};
|
||||
|
||||
class JoulePacket
|
||||
{
|
||||
public:
|
||||
JoulePacket();
|
||||
JoulePacket(uint16_t command);
|
||||
void addToPayload(char bites);
|
||||
void addToPayload(uint16_t bytes);
|
||||
void addToPayload(char *bytes, int len);
|
||||
bool verifyCheckSum(CommPortPtr dev, QString &err);
|
||||
bool write(CommPortPtr dev, QString &err);
|
||||
bool read(CommPortPtr dev, QString &err);
|
||||
|
||||
//char* data();
|
||||
QByteArray dataArray();
|
||||
QByteArray dataArrayForUnit();
|
||||
|
||||
uint16_t startpattern;
|
||||
uint16_t command;
|
||||
uint16_t length;
|
||||
|
||||
QByteArray payload;
|
||||
char checksum;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
#endif // JOULEDEVICE_H
|
||||
@@ -317,6 +317,19 @@ Serial::name() const
|
||||
return path;
|
||||
}
|
||||
|
||||
bool
|
||||
Serial::setBaudRate(int speed, QString &err)
|
||||
{
|
||||
/* not yet implemented
|
||||
|
||||
struct termios tty;
|
||||
if (cfsetspeed(&tty, speed) == -1) {
|
||||
perror("cfsetspeed");
|
||||
assert(0);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
#ifndef Q_OS_WIN32
|
||||
//
|
||||
// Linux and Mac device enumerator matches wildcards in /dev
|
||||
@@ -345,7 +358,7 @@ find_devices(char *result[], int capacity)
|
||||
// /dev/ttyMI* - MOXA PCI cards
|
||||
// /dev/rfcomm* - Bluetooth devices
|
||||
if (regcomp(®,
|
||||
"^(cu\\.(PL2303-[0-9A-F]+|ANTUSBStick.slabvcp|SLAB_USBtoUART|usbmodem[0-9A-F]+|usbserial-[0-9A-F]+|KeySerial[0-9])|ttyUSB[0-9]|ttyS[0-2]|ttyACM*|ttyMI*|rfcomm*)$",
|
||||
"^(cu\\.(PL2303-[0-9A-F]+|ANTUSBStick.slabvcp|SLAB_USBtoUART|usbmodem[0-9A-F]+|usbserial-[0-9A-G]+|KeySerial[0-9])|ttyUSB[0-9]|ttyS[0-2]|ttyACM*|ttyMI*|rfcomm*)$",
|
||||
REG_EXTENDED|REG_NOSUB)) {
|
||||
assert(0);
|
||||
}
|
||||
|
||||
@@ -53,6 +53,7 @@ class Serial : public CommPort
|
||||
virtual int read(void *buf, size_t nbyte, QString &err);
|
||||
virtual int write(void *buf, size_t nbyte, QString &err);
|
||||
virtual QString name() const;
|
||||
virtual bool setBaudRate(int speed, QString &err);
|
||||
};
|
||||
|
||||
#endif // _GC_PT_Serial_h
|
||||
|
||||
@@ -177,7 +177,7 @@ SOURCES += ../qxt/src/qxtspanslider.cpp \
|
||||
../qxt/src/qxtscheduleheaderwidget.cpp \
|
||||
../qxt/src/qxtscheduleviewheadermodel_p.cpp \
|
||||
../qxt/src/qxtscheduleitemdelegate.cpp \
|
||||
../qxt/src/qxtstyleoptionscheduleviewitem.cpp
|
||||
../qxt/src/qxtstyleoptionscheduleviewitem.cpp \
|
||||
|
||||
isEmpty( QTSOAP_INSTALL ) {
|
||||
include( ../qtsolutions/soap/qtsoap.pri )
|
||||
@@ -215,6 +215,7 @@ HEADERS += \
|
||||
BatchExportDialog.h \
|
||||
BestIntervalDialog.h \
|
||||
BinRideFile.h \
|
||||
Bin2RideFile.h \
|
||||
BingMap.h \
|
||||
CalendarDownload.h \
|
||||
ChooseCyclistDialog.h \
|
||||
@@ -266,6 +267,7 @@ HEADERS += \
|
||||
IntervalItem.h \
|
||||
IntervalSummaryWindow.h \
|
||||
IntervalTreeView.h \
|
||||
JouleDevice.h \
|
||||
JsonRideFile.h \
|
||||
LogTimeScaleDraw.h \
|
||||
LogTimeScaleEngine.h \
|
||||
@@ -396,6 +398,7 @@ SOURCES += \
|
||||
BestIntervalDialog.cpp \
|
||||
BikeScore.cpp \
|
||||
BinRideFile.cpp \
|
||||
Bin2RideFile.cpp \
|
||||
BingMap.cpp \
|
||||
CalendarDownload.cpp \
|
||||
ChooseCyclistDialog.cpp \
|
||||
@@ -452,6 +455,7 @@ SOURCES += \
|
||||
IntervalItem.cpp \
|
||||
IntervalSummaryWindow.cpp \
|
||||
IntervalTreeView.cpp \
|
||||
JouleDevice.cpp \
|
||||
LeftRightBalance.cpp \
|
||||
LogTimeScaleDraw.cpp \
|
||||
LogTimeScaleEngine.cpp \
|
||||
|
||||
Reference in New Issue
Block a user