mirror of
https://github.com/GoldenCheetah/GoldenCheetah.git
synced 2026-02-13 08:08:42 +00:00
now also downloads from serial/usbserial devices and automatically chooses
between them and D2XX based on what's installed
This commit is contained in:
@@ -19,42 +19,48 @@
|
||||
#include "D2XX.h"
|
||||
#include <ctype.h>
|
||||
|
||||
Device::Device(const FT_DEVICE_LIST_INFO_NODE &info) :
|
||||
bool D2XXRegistered = Device::addListFunction(&D2XX::myListDevices);
|
||||
|
||||
D2XX::D2XX(const FT_DEVICE_LIST_INFO_NODE &info) :
|
||||
info(info), isOpen(false)
|
||||
{
|
||||
}
|
||||
|
||||
Device::~Device()
|
||||
D2XX::~D2XX()
|
||||
{
|
||||
if (isOpen)
|
||||
close();
|
||||
}
|
||||
|
||||
bool Device::open(QString &err)
|
||||
bool
|
||||
D2XX::open(QString &err)
|
||||
{
|
||||
assert(!isOpen);
|
||||
FT_STATUS ftStatus =
|
||||
FT_OpenEx(info.Description, FT_OPEN_BY_DESCRIPTION, &ftHandle);
|
||||
if (ftStatus == FT_OK)
|
||||
isOpen = true;
|
||||
else
|
||||
if (ftStatus != FT_OK) {
|
||||
err = QString("FT_Open: %1").arg(ftStatus);
|
||||
return false;
|
||||
}
|
||||
isOpen = true;
|
||||
ftStatus = FT_SetBaudRate(ftHandle, 9600);
|
||||
if (ftStatus != FT_OK) {
|
||||
err = QString("FT_SetBaudRate: %1").arg(ftStatus);
|
||||
close();
|
||||
}
|
||||
return isOpen;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Device::close()
|
||||
void
|
||||
D2XX::close()
|
||||
{
|
||||
assert(isOpen);
|
||||
FT_Close(ftHandle);
|
||||
isOpen = false;
|
||||
}
|
||||
|
||||
int Device::read(void *buf, size_t nbyte, QString &err)
|
||||
int
|
||||
D2XX::read(void *buf, size_t nbyte, QString &err)
|
||||
{
|
||||
assert(isOpen);
|
||||
DWORD rxbytes;
|
||||
@@ -77,7 +83,8 @@ int Device::read(void *buf, size_t nbyte, QString &err)
|
||||
return -1;
|
||||
}
|
||||
|
||||
int Device::write(void *buf, size_t nbyte, QString &err)
|
||||
int
|
||||
D2XX::write(void *buf, size_t nbyte, QString &err)
|
||||
{
|
||||
assert(isOpen);
|
||||
DWORD n;
|
||||
@@ -88,8 +95,14 @@ int Device::write(void *buf, size_t nbyte, QString &err)
|
||||
return -1;
|
||||
}
|
||||
|
||||
QString
|
||||
D2XX::name() const
|
||||
{
|
||||
return QString("D2XX: ") + info.Description;
|
||||
}
|
||||
|
||||
QVector<DevicePtr>
|
||||
Device::listDevices(QString &err)
|
||||
D2XX::myListDevices(QString &err)
|
||||
{
|
||||
QVector<DevicePtr> result;
|
||||
DWORD numDevs;
|
||||
@@ -104,10 +117,19 @@ Device::listDevices(QString &err)
|
||||
err = QString("FT_GetDeviceInfoList: %1").arg(ftStatus);
|
||||
else {
|
||||
for (DWORD i = 0; i < numDevs; i++)
|
||||
result.append(DevicePtr(new Device(devInfo[i])));
|
||||
result.append(DevicePtr(new D2XX(devInfo[i])));
|
||||
}
|
||||
delete [] devInfo;
|
||||
// If we can't open a D2XX device, it's usually because the VCP drivers
|
||||
// are installed, so it should also show up in the list of serial devices.
|
||||
for (int i = 0; i < result.size(); ++i) {
|
||||
DevicePtr dev = result[i];
|
||||
QString tmp;
|
||||
if (dev->open(tmp))
|
||||
dev->close();
|
||||
else
|
||||
result.remove(i--);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -16,31 +16,33 @@
|
||||
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <QtCore>
|
||||
#ifndef _GC_PT_D2XX_h
|
||||
#define _GC_PT_D2XX_h 1
|
||||
|
||||
#include "Device.h"
|
||||
#include <D2XX/ftd2xx.h>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
class Device;
|
||||
typedef boost::shared_ptr<Device> DevicePtr;
|
||||
|
||||
class Device
|
||||
class D2XX : public Device
|
||||
{
|
||||
Device(const Device &);
|
||||
Device& operator=(const Device &);
|
||||
D2XX(const D2XX &);
|
||||
D2XX& operator=(const D2XX &);
|
||||
|
||||
FT_DEVICE_LIST_INFO_NODE info;
|
||||
FT_HANDLE ftHandle;
|
||||
bool isOpen;
|
||||
Device(const FT_DEVICE_LIST_INFO_NODE &info);
|
||||
D2XX(const FT_DEVICE_LIST_INFO_NODE &info);
|
||||
|
||||
public:
|
||||
|
||||
static QVector<DevicePtr> listDevices(QString &err);
|
||||
~Device();
|
||||
bool open(QString &err);
|
||||
void close();
|
||||
int read(void *buf, size_t nbyte, QString &err);
|
||||
int write(void *buf, size_t nbyte, QString &err);
|
||||
static QVector<DevicePtr> myListDevices(QString &err);
|
||||
|
||||
virtual ~D2XX();
|
||||
virtual bool open(QString &err);
|
||||
virtual void close();
|
||||
virtual int read(void *buf, size_t nbyte, QString &err);
|
||||
virtual int write(void *buf, size_t nbyte, QString &err);
|
||||
virtual QString name() const;
|
||||
};
|
||||
|
||||
#endif // _GC_PT_D2XX_h
|
||||
|
||||
|
||||
45
src/pt/Device.cpp
Normal file
45
src/pt/Device.cpp
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2008 Sean C. Rhea (srhea@srhea.net)
|
||||
*
|
||||
* 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 "Device.h"
|
||||
#include "Serial.h"
|
||||
|
||||
QVector<Device::ListFunction> Device::listFunctions;
|
||||
|
||||
bool
|
||||
Device::addListFunction(ListFunction f)
|
||||
{
|
||||
listFunctions.append(f);
|
||||
return true;
|
||||
}
|
||||
|
||||
QVector<DevicePtr>
|
||||
Device::listDevices(QString &err)
|
||||
{
|
||||
err = "";
|
||||
QVector<DevicePtr> result;
|
||||
for (int i = 0; i < listFunctions.size(); ++i) {
|
||||
QVector<DevicePtr> tmp = listFunctions[i](err);
|
||||
if (err != "")
|
||||
return result;
|
||||
for (int j = 0; j < tmp.size(); ++j)
|
||||
result.append(tmp[j]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
48
src/pt/Device.h
Normal file
48
src/pt/Device.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) 2008 Sean C. Rhea (srhea@srhea.net)
|
||||
*
|
||||
* 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 _GC_PT_Device_h
|
||||
#define _GC_PT_Device_h 1
|
||||
|
||||
#include <QtCore>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
class Device;
|
||||
typedef boost::shared_ptr<Device> DevicePtr;
|
||||
|
||||
class Device
|
||||
{
|
||||
typedef QVector<DevicePtr> (*ListFunction)(QString &err);
|
||||
static QVector<ListFunction> listFunctions;
|
||||
|
||||
public:
|
||||
|
||||
static bool addListFunction(ListFunction f);
|
||||
static QVector<DevicePtr> listDevices(QString &err);
|
||||
|
||||
virtual ~Device() {}
|
||||
virtual bool open(QString &err) = 0;
|
||||
virtual void close() = 0;
|
||||
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;
|
||||
|
||||
};
|
||||
|
||||
#endif // _GC_PT_Device_h
|
||||
|
||||
@@ -16,11 +16,9 @@
|
||||
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "D2XX.h"
|
||||
#include "PowerTap.h"
|
||||
#include "../lib/pt.h"
|
||||
#include <math.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
static bool
|
||||
hasNewline(const char *buf, int len)
|
||||
@@ -58,20 +56,30 @@ cEscape(const char *buf, int len)
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
doWrite(DevicePtr dev, char c)
|
||||
static bool
|
||||
doWrite(DevicePtr dev, char c, bool hwecho, QString &err)
|
||||
{
|
||||
// printf("writing '%c' to device\n", c);
|
||||
QString err;
|
||||
int n = dev->write(&c, 1, err);
|
||||
if (n != 1) {
|
||||
if (n < 0)
|
||||
printf("ERROR: failed to write %c to device: %s\n",
|
||||
c, err.toAscii().constData());
|
||||
err = QString("failed to write %1 to device: %2").arg(c).arg(err);
|
||||
else
|
||||
printf("ERROR: timeout writing %c to device\n", c);
|
||||
exit(1);
|
||||
err = QString("timeout writing %1 to device").arg(c);
|
||||
return false;
|
||||
}
|
||||
if (hwecho) {
|
||||
char c;
|
||||
int n = dev->read(&c, 1, err);
|
||||
if (n != 1) {
|
||||
if (n < 0)
|
||||
err = QString("failed to read back hardware echo: %2").arg(err);
|
||||
else
|
||||
err = "timeout reading back hardware echo";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -95,40 +103,42 @@ readUntilNewline(DevicePtr dev, char *buf, int len)
|
||||
return sofar;
|
||||
}
|
||||
|
||||
typedef void (*StatusCallback)(QString status);
|
||||
|
||||
static bool
|
||||
download(DevicePtr dev, QString &version,
|
||||
QVector<unsigned char> &records,
|
||||
StatusCallback statusCallback, QString &err)
|
||||
bool
|
||||
PowerTap::download(DevicePtr dev, QByteArray &version,
|
||||
QVector<unsigned char> &records,
|
||||
StatusCallback statusCallback, QString &err)
|
||||
{
|
||||
if (!dev->open(err)) {
|
||||
err = "ERROR: open failed: " + err;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
printf("clearing read buffer\n");
|
||||
while (true) {
|
||||
QString err;
|
||||
char buf[256];
|
||||
if (dev->read(buf, sizeof(buf), err) < (int) sizeof(buf))
|
||||
break;
|
||||
}
|
||||
*/
|
||||
|
||||
doWrite(dev, 0x56); // 'V'
|
||||
if (!doWrite(dev, 0x56, false, err)) // 'V'
|
||||
return false;
|
||||
statusCallback("Reading version string...");
|
||||
char vbuf[256];
|
||||
int version_len = readUntilNewline(dev, vbuf, sizeof(vbuf));
|
||||
printf("read version \"%s\"\n",
|
||||
cEscape(vbuf, version_len).toAscii().constData());
|
||||
vbuf[version_len] = '\0';
|
||||
version = vbuf;
|
||||
version = QByteArray(vbuf, version_len);
|
||||
|
||||
// We expect the version string to be something like
|
||||
// "VER 02.21 PRO...", so if we see two V's, it's probably
|
||||
// because there's a hardware echo going on.
|
||||
|
||||
int veridx = version.indexOf("VER");
|
||||
if (veridx < 0) {
|
||||
err = QString("Unrecognized version \"%1\"")
|
||||
.arg(cEscape(vbuf, version_len));
|
||||
return false;
|
||||
}
|
||||
bool hwecho = version.indexOf('V') < veridx;
|
||||
printf("hwecho=%s\n", hwecho ? "true" : "false");
|
||||
|
||||
statusCallback("Reading header...");
|
||||
|
||||
doWrite(dev, 0x44); // 'D'
|
||||
if (!doWrite(dev, 0x44, hwecho, err)) // 'D'
|
||||
return false;
|
||||
unsigned char header[6];
|
||||
int header_len = dev->read(header, sizeof(header), err);
|
||||
if (header_len != 6) {
|
||||
@@ -203,80 +213,10 @@ download(DevicePtr dev, QString &version,
|
||||
int rem = (int) round(secs);
|
||||
int min = rem / 60;
|
||||
statusCallback(QString("%1 minutes downloaded...").arg(min));
|
||||
doWrite(dev, 0x71); // 'q'
|
||||
if (!doWrite(dev, 0x71, hwecho, err)) // 'q'
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
statusCallback(QString status)
|
||||
{
|
||||
printf("STATUS: %s\n", status.toAscii().constData());
|
||||
}
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
QString err;
|
||||
QVector<DevicePtr> devList = Device::listDevices(err);
|
||||
if (devList.empty()) {
|
||||
printf("ERROR: no devices\n");
|
||||
exit(1);
|
||||
}
|
||||
if (devList.size() > 1) {
|
||||
printf("ERROR: found %d devices\n", devList.size());
|
||||
exit(1);
|
||||
}
|
||||
printf("Opening device\n");
|
||||
DevicePtr dev = devList[0];
|
||||
QString version;
|
||||
QVector<unsigned char> records;
|
||||
if (!download(dev, version, records, &statusCallback, err)) {
|
||||
printf("%s\n", err.toAscii().constData());
|
||||
exit(1);
|
||||
}
|
||||
char tmpname[32];
|
||||
snprintf(tmpname, sizeof(tmpname), ".ptdl.XXXXXX");
|
||||
int fd = mkstemp(tmpname);
|
||||
if (fd == -1)
|
||||
assert(false);
|
||||
FILE *file = fdopen(fd, "w");
|
||||
if (file == NULL)
|
||||
assert(false);
|
||||
unsigned char *data = records.data();
|
||||
struct tm time;
|
||||
bool time_set = false;
|
||||
|
||||
for (int i = 0; i < records.size(); i += 6) {
|
||||
if (data[i] == 0)
|
||||
continue;
|
||||
fprintf(file, "%02x %02x %02x %02x %02x %02x\n",
|
||||
data[i], data[i+1], data[i+2],
|
||||
data[i+3], data[i+4], data[i+5]);
|
||||
if (!time_set && pt_is_time(data + i)) {
|
||||
pt_unpack_time(data + i, &time);
|
||||
time_set = true;
|
||||
}
|
||||
}
|
||||
fclose(file);
|
||||
assert(time_set);
|
||||
|
||||
if (chmod(tmpname, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) {
|
||||
perror("chmod");
|
||||
assert(false);
|
||||
}
|
||||
|
||||
char filename[64];
|
||||
sprintf(filename, "%04d_%02d_%02d_%02d_%02d_%02d.raw",
|
||||
time.tm_year + 1900, time.tm_mon + 1, time.tm_mday,
|
||||
time.tm_hour, time.tm_min, time.tm_sec);
|
||||
|
||||
if (rename(tmpname, filename) == -1) {
|
||||
perror("rename");
|
||||
assert(false);
|
||||
}
|
||||
|
||||
printf("Ride successfully downloaded to %s!\n", filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
34
src/pt/PowerTap.h
Normal file
34
src/pt/PowerTap.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2008 Sean C. Rhea (srhea@srhea.net)
|
||||
*
|
||||
* 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 _GC_PT_PowerTap_h
|
||||
#define _GC_PT_PowerTap_h 1
|
||||
|
||||
#include "Device.h"
|
||||
|
||||
struct PowerTap
|
||||
{
|
||||
typedef void (*StatusCallback)(QString status);
|
||||
|
||||
static bool download(DevicePtr dev, QByteArray &version,
|
||||
QVector<unsigned char> &records,
|
||||
StatusCallback statusCallback, QString &err);
|
||||
};
|
||||
|
||||
#endif // _GC_PT_PowerTap_h
|
||||
|
||||
127
src/pt/Serial.cpp
Normal file
127
src/pt/Serial.cpp
Normal file
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright (c) 2008 Sean C. Rhea (srhea@srhea.net)
|
||||
*
|
||||
* 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 "Serial.h"
|
||||
#include "../lib/pt.h"
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
bool SerialRegistered = Device::addListFunction(&Serial::myListDevices);
|
||||
|
||||
Serial::Serial(const QString &path) : path(path), fd(-1)
|
||||
{
|
||||
}
|
||||
|
||||
Serial::~Serial()
|
||||
{
|
||||
if (fd >= 0)
|
||||
close();
|
||||
}
|
||||
|
||||
bool
|
||||
Serial::open(QString &err)
|
||||
{
|
||||
assert(fd < 0);
|
||||
fd = ::open(path.toAscii().constData(), O_RDWR | O_NOCTTY | O_NONBLOCK);
|
||||
if (fd < 0) {
|
||||
err = QString("open: ") + strerror(errno);
|
||||
return false;
|
||||
}
|
||||
pt_make_async(fd);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
Serial::close()
|
||||
{
|
||||
assert(fd >= 0);
|
||||
::close(fd);
|
||||
fd = -1;
|
||||
}
|
||||
|
||||
int
|
||||
Serial::read(void *buf, size_t nbyte, QString &err)
|
||||
{
|
||||
fd_set fdset;
|
||||
FD_ZERO(&fdset);
|
||||
FD_SET(fd, &fdset);
|
||||
struct timeval tv;
|
||||
memset(&tv, 0, sizeof(tv));
|
||||
tv.tv_sec = 5;
|
||||
int n = select(fd + 1, &fdset, NULL, NULL, &tv);
|
||||
if (n == 0)
|
||||
return 0;
|
||||
if (n < 0) {
|
||||
err = QString("select: ") + strerror(errno);
|
||||
return -1;
|
||||
}
|
||||
int result = ::read(fd, buf, nbyte);
|
||||
if (result < 0)
|
||||
err = QString("read: ") + strerror(errno);
|
||||
return result;
|
||||
}
|
||||
|
||||
int
|
||||
Serial::write(void *buf, size_t nbyte, QString &err)
|
||||
{
|
||||
fd_set fdset;
|
||||
FD_ZERO(&fdset);
|
||||
FD_SET(fd, &fdset);
|
||||
struct timeval tv;
|
||||
memset(&tv, 0, sizeof(tv));
|
||||
tv.tv_sec = 5;
|
||||
int n = select(fd + 1, NULL, &fdset, NULL, &tv);
|
||||
if (n < 0) {
|
||||
err = QString("select: ") + strerror(errno);
|
||||
return -1;
|
||||
}
|
||||
if (n == 0) {
|
||||
err = "timeout";
|
||||
return 0;
|
||||
}
|
||||
int result = ::write(fd, buf, nbyte);
|
||||
if (result < 0)
|
||||
err = QString("write: ") + strerror(errno);
|
||||
return result;
|
||||
}
|
||||
|
||||
QString
|
||||
Serial::name() const
|
||||
{
|
||||
return QString("Serial: ") + path;
|
||||
}
|
||||
|
||||
QVector<DevicePtr>
|
||||
Serial::myListDevices(QString &err)
|
||||
{
|
||||
static const int MAX_DEVICES = 100;
|
||||
(void) err;
|
||||
QVector<DevicePtr> result;
|
||||
char *devices[MAX_DEVICES];
|
||||
int devcnt = pt_find_device(devices, MAX_DEVICES);
|
||||
for (int i = 0; i < devcnt; ++i) {
|
||||
result.append(DevicePtr(new Serial(devices[i])));
|
||||
free(devices[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
46
src/pt/Serial.h
Normal file
46
src/pt/Serial.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) 2008 Sean C. Rhea (srhea@srhea.net)
|
||||
*
|
||||
* 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 _GC_PT_Serial_h
|
||||
#define _GC_PT_Serial_h 1
|
||||
|
||||
#include "Device.h"
|
||||
|
||||
class Serial : public Device
|
||||
{
|
||||
Serial(const Serial &);
|
||||
Serial& operator=(const Serial &);
|
||||
|
||||
QString path;
|
||||
int fd;
|
||||
Serial(const QString &path);
|
||||
|
||||
public:
|
||||
|
||||
static QVector<DevicePtr> myListDevices(QString &err);
|
||||
|
||||
virtual ~Serial();
|
||||
virtual bool open(QString &err);
|
||||
virtual void close();
|
||||
virtual int read(void *buf, size_t nbyte, QString &err);
|
||||
virtual int write(void *buf, size_t nbyte, QString &err);
|
||||
virtual QString name() const;
|
||||
};
|
||||
|
||||
#endif // _GC_PT_Serial_h
|
||||
|
||||
100
src/pt/main.cpp
Normal file
100
src/pt/main.cpp
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (c) 2008 Sean C. Rhea (srhea@srhea.net)
|
||||
*
|
||||
* 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 "PowerTap.h"
|
||||
#include "../lib/pt.h"
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
static void
|
||||
statusCallback(QString status)
|
||||
{
|
||||
printf("STATUS: %s\n", status.toAscii().constData());
|
||||
}
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
QString err;
|
||||
QVector<DevicePtr> devList = Device::listDevices(err);
|
||||
if (devList.empty()) {
|
||||
printf("ERROR: no devices\n");
|
||||
exit(1);
|
||||
}
|
||||
printf("Available devices:\n");
|
||||
for (int i = 0; i < devList.size(); ++i) {
|
||||
DevicePtr dev = devList[i];
|
||||
printf(" %s\n", dev->name().toAscii().constData());
|
||||
}
|
||||
if (devList.size() > 1) {
|
||||
printf("ERROR: found %d devices\n", devList.size());
|
||||
exit(1);
|
||||
}
|
||||
DevicePtr dev = devList[0];
|
||||
printf("Downloading from device %s\n", dev->name().toAscii().constData());
|
||||
QByteArray version;
|
||||
QVector<unsigned char> records;
|
||||
if (!PowerTap::download(dev, version, records, &statusCallback, err)) {
|
||||
printf("%s\n", err.toAscii().constData());
|
||||
exit(1);
|
||||
}
|
||||
char tmpname[32];
|
||||
snprintf(tmpname, sizeof(tmpname), ".ptdl.XXXXXX");
|
||||
int fd = mkstemp(tmpname);
|
||||
if (fd == -1)
|
||||
assert(false);
|
||||
FILE *file = fdopen(fd, "w");
|
||||
if (file == NULL)
|
||||
assert(false);
|
||||
unsigned char *data = records.data();
|
||||
struct tm time;
|
||||
bool time_set = false;
|
||||
|
||||
for (int i = 0; i < records.size(); i += 6) {
|
||||
if (data[i] == 0)
|
||||
continue;
|
||||
fprintf(file, "%02x %02x %02x %02x %02x %02x\n",
|
||||
data[i], data[i+1], data[i+2],
|
||||
data[i+3], data[i+4], data[i+5]);
|
||||
if (!time_set && pt_is_time(data + i)) {
|
||||
pt_unpack_time(data + i, &time);
|
||||
time_set = true;
|
||||
}
|
||||
}
|
||||
fclose(file);
|
||||
assert(time_set);
|
||||
|
||||
if (chmod(tmpname, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) {
|
||||
perror("chmod");
|
||||
assert(false);
|
||||
}
|
||||
|
||||
char filename[64];
|
||||
sprintf(filename, "%04d_%02d_%02d_%02d_%02d_%02d.raw",
|
||||
time.tm_year + 1900, time.tm_mon + 1, time.tm_mday,
|
||||
time.tm_hour, time.tm_min, time.tm_sec);
|
||||
|
||||
if (rename(tmpname, filename) == -1) {
|
||||
perror("rename");
|
||||
assert(false);
|
||||
}
|
||||
|
||||
printf("Ride successfully downloaded to %s!\n", filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,6 @@ INCLUDEPATH += /sw/include
|
||||
LIBS += -lftd2xx ../lib/libgc.a
|
||||
|
||||
# Input
|
||||
HEADERS += D2XX.h
|
||||
SOURCES += D2XX.cpp PowerTap.cpp
|
||||
HEADERS += Device.h Serial.h D2XX.h PowerTap.h
|
||||
SOURCES += Device.cpp Serial.cpp D2XX.cpp PowerTap.cpp main.cpp
|
||||
|
||||
|
||||
Reference in New Issue
Block a user