mirror of
https://github.com/GoldenCheetah/GoldenCheetah.git
synced 2026-02-14 08:38:45 +00:00
.. the code assumes the kickr connection will always work, even when no BTLE hardware is present. If no BTLE hardware is available then connections fail immediately and so do attempts to find devices. If BTLE hardware is available but the kickr connection cannot be established in 30 seconds in train view then it returns an error. Also added better device descriptions to check the device subtype so we can identify stages, inride and kickr separately.
1190 lines
40 KiB
C++
1190 lines
40 KiB
C++
/*
|
|
* Copyright (c) 2012 Mark Liversedge (liversedge@gmail.com)
|
|
*
|
|
* 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 "AddDeviceWizard.h"
|
|
|
|
// WIZARD FLOW
|
|
//
|
|
// 10. Select Device Type
|
|
// 20. Scan for Device / select Serial
|
|
// 30. Firmware for Fortius
|
|
// 50. Pair for ANT
|
|
// 55. Pair for BTLE
|
|
// 60. Finalise
|
|
//
|
|
|
|
// Main wizard
|
|
AddDeviceWizard::AddDeviceWizard(MainWindow *main) : QWizard(main), main(main)
|
|
{
|
|
#ifdef Q_OS_MAC
|
|
setWizardStyle(QWizard::ModernStyle);
|
|
#endif
|
|
|
|
// delete when done
|
|
setWindowModality(Qt::NonModal); // avoid blocking WFAPI calls for kickr
|
|
setAttribute(Qt::WA_DeleteOnClose);
|
|
|
|
setFixedHeight(530);
|
|
setFixedWidth(550);
|
|
|
|
// title
|
|
setWindowTitle(tr("Add Device Wizard"));
|
|
scanner = new DeviceScanner(this);
|
|
|
|
setPage(10, new AddType(this)); // done
|
|
setPage(20, new AddSearch(this)); // done
|
|
setPage(30, new AddFirmware(this)); // done
|
|
setPage(50, new AddPair(this)); // done
|
|
setPage(55, new AddPairBTLE(this)); // done
|
|
setPage(60, new AddFinal(this)); // todo -- including virtual power
|
|
|
|
done = false;
|
|
|
|
type = -1;
|
|
current = 0;
|
|
controller = NULL;
|
|
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
* Wizard Pages
|
|
*--------------------------------------------------------------------*/
|
|
|
|
//Select device type
|
|
AddType::AddType(AddDeviceWizard *parent) : QWizardPage(parent), wizard(parent)
|
|
{
|
|
setTitle(tr("Select Device"));
|
|
setSubTitle(tr("What kind of device to add"));
|
|
|
|
QVBoxLayout *layout = new QVBoxLayout;
|
|
setLayout(layout);
|
|
|
|
mapper = new QSignalMapper(this);
|
|
connect(mapper, SIGNAL(mapped(QString)), this, SLOT(clicked(QString)));
|
|
|
|
foreach(DeviceType t, wizard->deviceTypes.Supported) {
|
|
if (t.type) {
|
|
QCommandLinkButton *p = new QCommandLinkButton(t.name, t.description, this);
|
|
connect(p, SIGNAL(clicked()), mapper, SLOT(map()));
|
|
mapper->setMapping(p, QString("%1").arg(t.type));
|
|
layout->addWidget(p);
|
|
}
|
|
}
|
|
label = new QLabel("", this);
|
|
layout->addWidget(label);
|
|
|
|
next = 20;
|
|
setFinalPage(false);
|
|
}
|
|
|
|
void
|
|
AddType::initializePage()
|
|
{
|
|
// reset any device search info
|
|
wizard->portSpec = "";
|
|
wizard->found = false;
|
|
wizard->current = 0;
|
|
if (wizard->controller) {
|
|
delete wizard->controller;
|
|
wizard->controller = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
AddType::clicked(QString p)
|
|
{
|
|
// reset -- particularly since we might get here from
|
|
// other pages hitting 'Back'
|
|
initializePage();
|
|
wizard->type = p.toInt();
|
|
|
|
// what are we scanning for?
|
|
int i=0;
|
|
foreach(DeviceType t, wizard->deviceTypes.Supported) {
|
|
if (t.type == wizard->type) wizard->current = i;
|
|
i++;
|
|
}
|
|
|
|
// we don't do a quick scan for a kickr since it takes 15 seconds
|
|
// to timeout and we don't want to get stuck on the front page for
|
|
// that long -- it will seem like it has not worked / crashed
|
|
if (wizard->deviceTypes.Supported[wizard->current].connector != DEV_BTLE)
|
|
wizard->found = wizard->scanner->quickScan(false); // do a quick scan
|
|
else
|
|
wizard->found = false;
|
|
|
|
// Still no dice. Go to the not found dialog
|
|
if (wizard->found == false) next =20;
|
|
else {
|
|
switch(wizard->deviceTypes.Supported[wizard->current].type) {
|
|
case DEV_BT40 : next = 55; break;
|
|
case DEV_ANTLOCAL : next = 50; break; // pair
|
|
default:
|
|
case DEV_KICKR :
|
|
case DEV_CT : next = 60; break; // confirm and add
|
|
case DEV_FORTIUS : next = 30; break; // confirm and add
|
|
}
|
|
}
|
|
wizard->next();
|
|
}
|
|
|
|
DeviceScanner::DeviceScanner(AddDeviceWizard *wizard) : wizard(wizard) {}
|
|
|
|
void
|
|
DeviceScanner::run()
|
|
{
|
|
active = true;
|
|
bool result = false;
|
|
|
|
#ifdef GC_HAVE_WFAPI
|
|
void *pool;
|
|
// get an autorelease pool for this thread!
|
|
if (wizard->deviceTypes.Supported[wizard->current].connector == DEV_BTLE) pool = WFApi::getInstance()->getPool();
|
|
#endif
|
|
|
|
for (int i=0; active && !result && i<10; i++) { // search for longer
|
|
|
|
// better to wait a while, esp. if its just a USB device
|
|
#ifdef WIN32
|
|
Sleep(1000);
|
|
#else
|
|
sleep(1);
|
|
#endif
|
|
result = quickScan(false);
|
|
}
|
|
if (active) emit finished(result); // only signal if we weren't aborted!
|
|
|
|
#ifdef GC_HAVE_WFAPI
|
|
WFApi::getInstance()->freePool(pool);
|
|
#endif
|
|
}
|
|
|
|
void
|
|
DeviceScanner::stop()
|
|
{
|
|
active = false;
|
|
}
|
|
|
|
|
|
bool
|
|
DeviceScanner::quickScan(bool deep) // scan quickly or if true scan forever, as deep as possible
|
|
// for now deep just means try 3 time before giving up, but we
|
|
// may want to change that to include scanning more devices?
|
|
{
|
|
|
|
// get controller
|
|
if (wizard->controller) {
|
|
delete wizard->controller;
|
|
wizard->controller=NULL;
|
|
}
|
|
|
|
switch (wizard->deviceTypes.Supported[wizard->current].type) {
|
|
|
|
// we will need a factory for this soon..
|
|
case DEV_ANTPLUS : wizard->controller = new ANTplusController(NULL, NULL); break;
|
|
case DEV_CT : wizard->controller = new ComputrainerController(NULL, NULL); break;
|
|
#ifdef GC_HAVE_LIBUSB
|
|
case DEV_FORTIUS : wizard->controller = new FortiusController(NULL, NULL); break;
|
|
#endif
|
|
case DEV_NULL : wizard->controller = new NullController(NULL, NULL); break;
|
|
case DEV_ANTLOCAL : wizard->controller = new ANTlocalController(NULL, NULL); break;
|
|
#ifdef GC_HAVE_WFAPI
|
|
case DEV_KICKR : wizard->controller = new KickrController(NULL, NULL); break;
|
|
case DEV_BT40 : wizard->controller = new BT40Controller(NULL, NULL); break;
|
|
#endif
|
|
|
|
default: wizard->controller = NULL; break;
|
|
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// Search for USB devices
|
|
//----------------------------------------------------------------------
|
|
|
|
bool isfound = false;
|
|
int count=0;
|
|
do {
|
|
|
|
// can we find it automatically?
|
|
isfound = wizard->controller->find();
|
|
|
|
if (isfound == false && (wizard->deviceTypes.Supported[wizard->current].connector == DEV_LIBUSB ||
|
|
wizard->deviceTypes.Supported[wizard->current].connector == DEV_USB)) {
|
|
|
|
// Go to next page where we do not found, rescan and manual override
|
|
if (!deep) return false;
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
// Search serial ports
|
|
//----------------------------------------------------------------------
|
|
|
|
if (isfound == false && wizard->deviceTypes.Supported[wizard->current].connector == DEV_SERIAL) {
|
|
|
|
// automatically discover a serial port ...
|
|
QString error;
|
|
foreach (CommPortPtr port, Serial::myListCommPorts(error)) {
|
|
|
|
// check if controller still exists. gets deleted when scan cancelled
|
|
if (wizard->controller && wizard->controller->discover(port->name()) == true) {
|
|
isfound = true;
|
|
wizard->portSpec = port->name();
|
|
break;
|
|
}
|
|
}
|
|
|
|
// if we still didn't find it then we need to fall back to the user
|
|
// specifying the device on the next page
|
|
}
|
|
|
|
} while (!isfound && deep && count++ < 2);
|
|
|
|
#ifdef GC_HAVE_WFAPI
|
|
// save away the device UUID, so we can choose it when connecting.
|
|
if (isfound && wizard->deviceTypes.Supported[wizard->current].connector == DEV_BTLE)
|
|
wizard->portSpec = ((KickrController*)(wizard->controller))->id();
|
|
#endif
|
|
|
|
return isfound;
|
|
|
|
}
|
|
|
|
// Scan for device port / usb etc
|
|
AddSearch::AddSearch(AddDeviceWizard *parent) : QWizardPage(parent), wizard(parent)
|
|
{
|
|
setSubTitle(tr("Scan for connected devices"));
|
|
|
|
QVBoxLayout *layout = new QVBoxLayout;
|
|
setLayout(layout);
|
|
|
|
isSearching = false;
|
|
active = false;
|
|
|
|
|
|
label = new QLabel("Please make sure your device is connected, switched on and working. "
|
|
"We will scan for the device type you have selected at known ports.\n\n");
|
|
label->setWordWrap(true);
|
|
layout->addWidget(label);
|
|
|
|
bar = new QProgressBar(this);
|
|
bar->setMaximum(100);
|
|
bar->setMinimum(0);
|
|
bar->setValue(0);
|
|
//bar->setText("Searching...");
|
|
layout->addWidget(bar);
|
|
|
|
QHBoxLayout *hlayout2 = new QHBoxLayout;
|
|
stop = new QPushButton("Search", this);
|
|
hlayout2->addStretch();
|
|
hlayout2->addWidget(stop);
|
|
layout->addLayout(hlayout2);
|
|
|
|
label1 = new QLabel("If your device is not found you can select the device port "
|
|
"manually by using the selection box below.");
|
|
label1->setWordWrap(true);
|
|
layout->addWidget(label1);
|
|
|
|
label2 = new QLabel("\nDevice found.\nClick Next to Continue\n");
|
|
label2->hide();
|
|
label2->setWordWrap(true);
|
|
layout->addWidget(label2);
|
|
|
|
QHBoxLayout *hlayout = new QHBoxLayout;
|
|
manual = new QComboBox(this);
|
|
hlayout->addStretch();
|
|
hlayout->addWidget(manual);
|
|
layout->addLayout(hlayout);
|
|
|
|
layout->addStretch();
|
|
|
|
connect(stop, SIGNAL(clicked()), this, SLOT(doScan()));
|
|
connect(manual, SIGNAL(currentIndexChanged(int)), this, SLOT(chooseCOMPort()));
|
|
connect(wizard->scanner, SIGNAL(finished(bool)), this, SLOT(scanFinished(bool)));
|
|
|
|
}
|
|
|
|
void
|
|
AddSearch::chooseCOMPort()
|
|
{
|
|
if (active) return;
|
|
|
|
if (manual->currentIndex() <= 0) { // we unselected or something.
|
|
wizard->found = false;
|
|
wizard->portSpec = "";
|
|
return;
|
|
}
|
|
|
|
// stop any scan that may be in process?
|
|
if (isSearching == true) {
|
|
doScan(); // remember doScan toggles with the stop/search again button
|
|
}
|
|
|
|
// let the user select the port
|
|
wizard->portSpec = manual->itemText(manual->currentIndex());
|
|
|
|
// carry on then
|
|
wizard->found = true; // ugh
|
|
}
|
|
|
|
void
|
|
AddSearch::initializePage()
|
|
{
|
|
setTitle(QString(tr("%1 Search")).arg(wizard->deviceTypes.Supported[wizard->current].name));
|
|
|
|
// we only ask for the device file if it is a serial device
|
|
if (wizard->deviceTypes.Supported[wizard->current].connector == DEV_SERIAL) {
|
|
|
|
// wipe away whatever items it has now
|
|
for (int i=manual->count(); i > 0; i--) manual->removeItem(0);
|
|
|
|
// add in the items we have..
|
|
manual->addItem("Select COM port");
|
|
QString error;
|
|
foreach (CommPortPtr port, Serial::myListCommPorts(error)) manual->addItem(port->name());
|
|
manual->show();
|
|
label1->show();
|
|
|
|
|
|
} else {
|
|
label1->hide();
|
|
manual->hide();
|
|
}
|
|
|
|
bar->show();
|
|
stop->show();
|
|
label->show();
|
|
label2->hide();
|
|
active = false;
|
|
doScan();
|
|
}
|
|
|
|
void
|
|
AddSearch::scanFinished(bool result)
|
|
{
|
|
isSearching = false;
|
|
wizard->found = result;
|
|
bar->setMaximum(100);
|
|
bar->setMinimum(0);
|
|
bar->setValue(0);
|
|
stop->setText("Search Again");
|
|
|
|
if (result == true) { // woohoo we found one
|
|
|
|
if (wizard->deviceTypes.Supported[wizard->current].type == DEV_BT40) {
|
|
// ok we've started finding devices, lets go straight into the
|
|
// pair screen since we now want to see the data etc.
|
|
wizard->next();
|
|
} else {
|
|
|
|
bar->hide();
|
|
stop->hide();
|
|
manual->hide();
|
|
label->hide();
|
|
label1->hide();
|
|
if (wizard->portSpec != "")
|
|
label2->setText(QString("\nDevice found (%1).\nPress Next to Continue\n").arg(wizard->portSpec));
|
|
else
|
|
label2->setText("\nDevice found.\nPress Next to Continue\n");
|
|
label2->show();
|
|
}
|
|
}
|
|
QApplication::processEvents();
|
|
emit completeChanged();
|
|
}
|
|
|
|
void
|
|
AddSearch::doScan()
|
|
{
|
|
if (isSearching == false) { // start a scan
|
|
|
|
// make bar bouncy...
|
|
bar->setMaximum(0);
|
|
bar->setMinimum(0);
|
|
bar->setValue(0);
|
|
stop->setText("Stop Searching");
|
|
isSearching = true;
|
|
manual->setCurrentIndex(0); //deselect any chosen port
|
|
wizard->found = false;
|
|
wizard->portSpec = "";
|
|
|
|
wizard->scanner->start();
|
|
|
|
} else { // stop a scan
|
|
|
|
isSearching = false;
|
|
// make bar stationary...
|
|
bar->setMaximum(100);
|
|
bar->setMinimum(0);
|
|
bar->setValue(0);
|
|
stop->setText("Search again");
|
|
|
|
wizard->scanner->stop();
|
|
}
|
|
}
|
|
|
|
int
|
|
AddSearch::nextId() const
|
|
{
|
|
// Still no dice. Go to the not found dialog
|
|
if (wizard->found == false) return 60;
|
|
else {
|
|
switch(wizard->deviceTypes.Supported[wizard->current].type) {
|
|
case DEV_ANTLOCAL : return 50; break; // pair
|
|
case DEV_BT40 : return 55; break; // pair BT devices
|
|
default:
|
|
case DEV_KICKR :
|
|
case DEV_CT : return 60; break; // confirm and add
|
|
case DEV_FORTIUS : return 30; break; // confirm and add
|
|
}
|
|
}
|
|
}
|
|
|
|
bool
|
|
AddSearch::validatePage()
|
|
{
|
|
return wizard->found;
|
|
}
|
|
|
|
void
|
|
AddSearch::cleanupPage()
|
|
{
|
|
wizard->scanner->stop();
|
|
if (isSearching) {
|
|
// give it time to stop...
|
|
#ifdef WIN32
|
|
Sleep(2000);
|
|
#else
|
|
sleep(2);
|
|
#endif
|
|
}
|
|
isSearching=false;
|
|
if (wizard->controller) {
|
|
delete wizard->controller;
|
|
wizard->controller = NULL;
|
|
}
|
|
}
|
|
|
|
// Fortius Firmware
|
|
AddFirmware::AddFirmware(AddDeviceWizard *parent) : QWizardPage(parent), wizard(parent)
|
|
{
|
|
setTitle(tr("Select Firmware"));
|
|
setSubTitle(tr("Select Firmware for Tacx Fortius"));
|
|
|
|
// create widgets
|
|
browse = new QPushButton("Browse", this);
|
|
copy = new QCheckBox("Copy to Library");
|
|
copy->setChecked(true);
|
|
|
|
help = new QLabel(this);
|
|
help->setWordWrap(true);
|
|
help->setText("Tacx Fortius trainers require a firmware file "
|
|
"which is provided by Tacx BV. This file is a "
|
|
"copyrighted file and cannot be distributed with "
|
|
"GoldenCheetah.\n\n"
|
|
"On windows it is typically installed in C:\\Windows\\system32 "
|
|
"and is called 'FortiusSWPID1942Renum.hex'.\n\n"
|
|
#if defined Q_OS_LINUX || defined Q_OS_MAC
|
|
"On Linux and Apple computers you will need to "
|
|
"extract it from the VR Software CD."
|
|
"The file we need is within the 'data2.cab' file, "
|
|
"which is an InstallShield file that can be read "
|
|
"with the 'unshield' tool\n\n"
|
|
#endif
|
|
"Please take care to ensure that the file is the latest version "
|
|
"of the Firmware file.\n\n"
|
|
"If you choose to copy to library the file will be copied into the "
|
|
"GoldenCheetah library, otherwise we will reference it. ");
|
|
|
|
file = new QLabel("File:", this);
|
|
|
|
name= new QLineEdit(this);
|
|
name->setEnabled(false);
|
|
|
|
QString fortiusFirmware = appsettings->value(this, FORTIUS_FIRMWARE, "").toString();
|
|
name->setText(fortiusFirmware);
|
|
|
|
// Layout widgets
|
|
QHBoxLayout *buttons = new QHBoxLayout;
|
|
QHBoxLayout *filedetails = new QHBoxLayout;
|
|
filedetails->addWidget(file);
|
|
filedetails->addWidget(name);
|
|
filedetails->addWidget(browse);
|
|
filedetails->addStretch();
|
|
|
|
buttons->addWidget(copy);
|
|
buttons->addStretch();
|
|
|
|
QVBoxLayout *mainLayout = new QVBoxLayout(this);
|
|
mainLayout->addLayout(filedetails);
|
|
mainLayout->addWidget(help);
|
|
mainLayout->addStretch();
|
|
mainLayout->addLayout(buttons);
|
|
|
|
// connect widgets
|
|
connect(browse, SIGNAL(clicked()), this, SLOT(browseClicked()));
|
|
}
|
|
|
|
bool
|
|
AddFirmware::validatePage()
|
|
{
|
|
QString filePath = name->text();
|
|
if (filePath == "" || !QFile(filePath).exists()) return false;
|
|
|
|
// either copy it, or reference it!
|
|
if (copy->isChecked()) {
|
|
|
|
QString fileName = QFileInfo(filePath).fileName();
|
|
QString targetFileName = QFileInfo(mainWindow->home.absolutePath() + "/../").absolutePath() + "/" + fileName;
|
|
|
|
// check not the same thing!
|
|
if(QFileInfo(fileName).absolutePath() != QFileInfo(targetFileName).absolutePath()) {
|
|
// if the current file exists, wipe it
|
|
if (QFile(targetFileName).exists()) QFile(targetFileName).remove();
|
|
QFile(filePath).copy(targetFileName);
|
|
}
|
|
name->setText(targetFileName);
|
|
}
|
|
appsettings->setValue(FORTIUS_FIRMWARE, name->text());
|
|
return true;
|
|
}
|
|
|
|
void
|
|
AddFirmware::browseClicked()
|
|
{
|
|
QString file = QFileDialog::getOpenFileName(this, tr("Open File"), "", tr("Intel Firmware File (*.hex)"));
|
|
if (file != "") name->setText(file);
|
|
}
|
|
|
|
// Pair devices
|
|
AddPair::AddPair(AddDeviceWizard *parent) : QWizardPage(parent), wizard(parent)
|
|
{
|
|
setTitle(tr("Pair Devices"));
|
|
setSubTitle(tr("Search for and pair ANT+ devices"));
|
|
|
|
signalMapper = NULL;
|
|
|
|
QVBoxLayout *layout = new QVBoxLayout;
|
|
setLayout(layout);
|
|
|
|
channelWidget = new QTreeWidget(this);
|
|
layout->addWidget(channelWidget);
|
|
}
|
|
|
|
static void
|
|
addSensorTypes(ANT *ant, QComboBox *p)
|
|
{
|
|
for (int i=0; ant->ant_sensor_types[i].suffix != '\0'; i++) {
|
|
if (*ant->ant_sensor_types[i].iconname != '\0') {
|
|
p->addItem(QIcon(ant->ant_sensor_types[i].iconname), ant->ant_sensor_types[i].descriptive_name, ant->ant_sensor_types[i].type);
|
|
} else {
|
|
p->addItem(ant->ant_sensor_types[i].descriptive_name, ant->ant_sensor_types[i].type);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
AddPair::cleanupPage()
|
|
{
|
|
updateValues.stop();
|
|
if (wizard->controller) {
|
|
wizard->controller->stop();
|
|
#ifdef WIN32
|
|
Sleep(1000);
|
|
#else
|
|
sleep(1);
|
|
#endif
|
|
delete wizard->controller;
|
|
wizard->controller = NULL;
|
|
}
|
|
}
|
|
|
|
static void enableDisable(QTreeWidget *tree)
|
|
{
|
|
// enable disable widgets based upon sensor selection
|
|
for (int i=0; i< tree->invisibleRootItem()->childCount(); i++) {
|
|
QTreeWidgetItem *item = tree->invisibleRootItem()->child(i);
|
|
|
|
// is it selected or not?
|
|
bool enable = (dynamic_cast<QComboBox*>(tree->itemWidget(item,0))->currentIndex() != 0);
|
|
|
|
// enable all thos widgetry
|
|
tree->itemWidget(item,2)->setEnabled(enable); // value
|
|
tree->itemWidget(item,3)->setEnabled(enable); // status
|
|
}
|
|
}
|
|
|
|
void
|
|
AddPair::initializePage()
|
|
{
|
|
// setup the controller and start it off so we can
|
|
// manipulate it
|
|
if (wizard->controller) delete wizard->controller;
|
|
if (signalMapper) delete signalMapper;
|
|
wizard->controller = new ANTlocalController(NULL,NULL);
|
|
dynamic_cast<ANTlocalController*>(wizard->controller)->setDevice(wizard->portSpec);
|
|
dynamic_cast<ANTlocalController*>(wizard->controller)->myANTlocal->setConfigurationMode(true); //XXX
|
|
wizard->controller->start();
|
|
wizard->profile=""; // clear any thing thats there now
|
|
signalMapper = new QSignalMapper(this);
|
|
|
|
// Channel 0, look for any (0 devicenumber) speed and distance device
|
|
|
|
// wait for it to start
|
|
#ifdef WIN32
|
|
Sleep(1000);
|
|
#else
|
|
sleep(1);
|
|
#endif
|
|
int channels = dynamic_cast<ANTlocalController*>(wizard->controller)->channels();
|
|
|
|
// Tree Widget of the channel controls
|
|
channelWidget->clear();
|
|
channelWidget->headerItem()->setText(0, tr("Sensor"));
|
|
channelWidget->headerItem()->setText(1, tr("ANT+ Id"));
|
|
channelWidget->headerItem()->setText(2, tr("Value"));
|
|
channelWidget->headerItem()->setText(3, tr("Status"));
|
|
channelWidget->setColumnCount(4);
|
|
channelWidget->setSelectionMode(QAbstractItemView::NoSelection);
|
|
//channelWidget->setEditTriggers(QAbstractItemView::SelectedClicked); // allow edit
|
|
channelWidget->setUniformRowHeights(true);
|
|
channelWidget->setIndentation(0);
|
|
|
|
channelWidget->header()->resizeSection(0,175); // type
|
|
channelWidget->header()->resizeSection(1,75); // id
|
|
channelWidget->header()->resizeSection(2,120); // value
|
|
channelWidget->header()->resizeSection(3,110); // status
|
|
|
|
// defaults
|
|
static const int index4[4] = { 1,2,3,5 };
|
|
static const int index8[8] = { 1,2,3,4,5,0,0,0 };
|
|
const int *index = channels == 4 ? index4 : index8;
|
|
|
|
// how many devices we got then?
|
|
for (int i=0; i< channels; i++) {
|
|
|
|
QTreeWidgetItem *add = new QTreeWidgetItem(channelWidget->invisibleRootItem());
|
|
add->setFlags(add->flags() | Qt::ItemIsEditable);
|
|
|
|
// sensor type
|
|
QComboBox *sensorSelector = new QComboBox(this);
|
|
addSensorTypes(dynamic_cast<ANTlocalController*>(wizard->controller)->myANTlocal, sensorSelector);
|
|
sensorSelector->setCurrentIndex(index[i]);
|
|
channelWidget->setItemWidget(add, 0, sensorSelector);
|
|
|
|
// sensor id
|
|
QLineEdit *sensorId = new QLineEdit(this);
|
|
sensorId->setEnabled(false);
|
|
sensorId->setText("none");
|
|
channelWidget->setItemWidget(add, 1, sensorId);
|
|
|
|
// value
|
|
QLabel *value = new QLabel(this);
|
|
QFont bigger;
|
|
bigger.setPointSize(25);
|
|
value->setFont(bigger);
|
|
value->setAlignment(Qt::AlignCenter | Qt::AlignVCenter);
|
|
value->setText("0");
|
|
channelWidget->setItemWidget(add, 2, value);
|
|
|
|
// status
|
|
QLabel *status = new QLabel(this);
|
|
status->setText("Un-Paired");
|
|
channelWidget->setItemWidget(add, 3, status);
|
|
|
|
//channelWidget->verticalHeader()->resizeSection(i,40)
|
|
connect(sensorSelector, SIGNAL(currentIndexChanged(int)), signalMapper, SLOT(map()));
|
|
signalMapper->setMapping(sensorSelector, i);
|
|
}
|
|
channelWidget->setCurrentItem(channelWidget->invisibleRootItem()->child(0));
|
|
enableDisable(channelWidget);
|
|
|
|
updateValues.start(200); // 5hz
|
|
connect(signalMapper, SIGNAL(mapped(int)), this, SLOT(sensorChanged(int)));
|
|
connect(&updateValues, SIGNAL(timeout()), this, SLOT(getChannelValues()));
|
|
connect(wizard->controller, SIGNAL(foundDevice(int,int,int)), this, SLOT(channelInfo(int,int,int)));
|
|
connect(wizard->controller, SIGNAL(searchTimeout(int)), this, SLOT(searchTimeout(int)));
|
|
//connect(wizard->controller, SIGNAL(lostDevice(int)), this, SLOT(searchTimeout(int)));
|
|
|
|
// now we're ready to get notifications - set channels
|
|
for (int i=0; i<channels; i++) sensorChanged(i);
|
|
|
|
}
|
|
|
|
void
|
|
AddPair::sensorChanged(int channel)
|
|
{
|
|
QTreeWidgetItem *item = channelWidget->invisibleRootItem()->child(channel);
|
|
enableDisable(channelWidget);
|
|
|
|
// first off lets unassign this channel
|
|
dynamic_cast<ANTlocalController*>(wizard->controller)->myANTlocal->setChannel(channel, -1, 0);
|
|
dynamic_cast<QLineEdit*>(channelWidget->itemWidget(item,1))->setText("none");
|
|
dynamic_cast<QLabel*>(channelWidget->itemWidget(item,2))->setText(0);
|
|
|
|
// what is it then? unused or restart scan?
|
|
QComboBox *p = dynamic_cast<QComboBox *>(channelWidget->itemWidget(item,0));
|
|
int channel_type = p->itemData(p->currentIndex()).toInt();
|
|
if (channel_type == ANTChannel::CHANNEL_TYPE_UNUSED) {
|
|
dynamic_cast<QLabel*>(channelWidget->itemWidget(item,3))->setText("Unused");
|
|
} else {
|
|
dynamic_cast<QLabel*>(channelWidget->itemWidget(item,3))->setText("Searching...");
|
|
dynamic_cast<ANTlocalController*>(wizard->controller)->myANTlocal->setChannel(channel, 0, channel_type);
|
|
}
|
|
}
|
|
|
|
void
|
|
AddPair::channelInfo(int channel, int device_number, int device_id)
|
|
{
|
|
Q_UNUSED(device_id);
|
|
QTreeWidgetItem *item = channelWidget->invisibleRootItem()->child(channel);
|
|
dynamic_cast<QLineEdit *>(channelWidget->itemWidget(item,1))->setText(QString("%1").arg(device_number));
|
|
dynamic_cast<QLabel *>(channelWidget->itemWidget(item,3))->setText(QString("Paired"));
|
|
}
|
|
|
|
void
|
|
AddPair::searchTimeout(int channel)
|
|
{
|
|
// Kick if off again, just mimic user reselecting the same sensor type
|
|
sensorChanged(channel);
|
|
}
|
|
|
|
|
|
void
|
|
AddPair::getChannelValues()
|
|
{
|
|
if (wizard->controller == NULL) return;
|
|
|
|
// enable disable widgets based upon sensor selection
|
|
for (int i=0; i< channelWidget->invisibleRootItem()->childCount(); i++) {
|
|
QTreeWidgetItem *item = channelWidget->invisibleRootItem()->child(i);
|
|
|
|
// is it selected or not?
|
|
bool enable = (dynamic_cast<QComboBox*>(channelWidget->itemWidget(item,0))->currentIndex() != 0);
|
|
|
|
if (enable) {
|
|
QComboBox *p =dynamic_cast<QComboBox*>(channelWidget->itemWidget(item,0));
|
|
|
|
// speed+cadence is two values!
|
|
if (p->itemData(p->currentIndex()) == ANTChannel::CHANNEL_TYPE_SandC) {
|
|
dynamic_cast<QLabel *>(channelWidget->itemWidget(item,2))->setText(QString("%1 %2")
|
|
.arg((int)dynamic_cast<ANTlocalController*>(wizard->controller)->myANTlocal->channelValue2(i) //speed
|
|
* (appsettings->value(NULL, GC_WHEELSIZE, 2100).toInt()/1000) * 60 / 1000)
|
|
.arg((int)dynamic_cast<ANTlocalController*>(wizard->controller)->myANTlocal->channelValue(i))); // cad
|
|
} else {
|
|
dynamic_cast<QLabel *>(channelWidget->itemWidget(item,2))->setText(QString("%1")
|
|
.arg((int)dynamic_cast<ANTlocalController*>(wizard->controller)->myANTlocal->channelValue(i)));
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
bool
|
|
AddPair::validatePage()
|
|
{
|
|
// when next is clicked we need to get the paired values
|
|
// and create a profile, a blank profile will be created if
|
|
// no devices have been paired. This means devices will be
|
|
// automatically paired at runtime
|
|
wizard->profile="";
|
|
for (int i=0; i< channelWidget->invisibleRootItem()->childCount(); i++) {
|
|
QTreeWidgetItem *item = channelWidget->invisibleRootItem()->child(i);
|
|
|
|
// what is it then? unused or restart scan?
|
|
QComboBox *p = dynamic_cast<QComboBox *>(channelWidget->itemWidget(item,0));
|
|
int channel_type = p->itemData(p->currentIndex()).toInt();
|
|
|
|
if (channel_type == ANTChannel::CHANNEL_TYPE_UNUSED) continue; // not paired
|
|
|
|
int device_number = dynamic_cast<QLineEdit*>(channelWidget->itemWidget(item,1))->text().toInt();
|
|
|
|
if (device_number)
|
|
wizard->profile += QString(wizard->profile != "" ? ", %1%2" : "%1%2")
|
|
.arg(device_number)
|
|
.arg(ANT::deviceIdCode(channel_type));
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// Pair devices
|
|
AddPairBTLE::AddPairBTLE(AddDeviceWizard *parent) : QWizardPage(parent), wizard(parent)
|
|
{
|
|
setTitle(tr("Pair Devices"));
|
|
setSubTitle(tr("Search for and pair Bluetooth 4.0 devices"));
|
|
|
|
signalMapper = NULL;
|
|
|
|
QVBoxLayout *layout = new QVBoxLayout;
|
|
setLayout(layout);
|
|
|
|
channelWidget = new QTreeWidget(this);
|
|
layout->addWidget(channelWidget);
|
|
}
|
|
|
|
void
|
|
AddPairBTLE::cleanupPage()
|
|
{
|
|
updateValues.stop();
|
|
if (wizard->controller) {
|
|
wizard->controller->stop();
|
|
#ifdef WIN32
|
|
Sleep(1000);
|
|
#else
|
|
sleep(1);
|
|
#endif
|
|
delete wizard->controller;
|
|
wizard->controller = NULL;
|
|
}
|
|
}
|
|
|
|
void
|
|
AddPairBTLE::initializePage()
|
|
{
|
|
#ifdef GC_HAVE_WFAPI
|
|
qDebug()<<"found this many devices:"<<WFApi::getInstance()->deviceCount();
|
|
#endif
|
|
|
|
// setup the controller and start it off so we can
|
|
// manipulate it
|
|
if (wizard->controller) delete wizard->controller;
|
|
if (signalMapper) delete signalMapper;
|
|
wizard->controller = new ANTlocalController(NULL,NULL);
|
|
dynamic_cast<ANTlocalController*>(wizard->controller)->setDevice(wizard->portSpec);
|
|
dynamic_cast<ANTlocalController*>(wizard->controller)->myANTlocal->setConfigurationMode(true); //XXX
|
|
wizard->controller->start();
|
|
wizard->profile=""; // clear any thing thats there now
|
|
signalMapper = new QSignalMapper(this);
|
|
|
|
// Channel 0, look for any (0 devicenumber) speed and distance device
|
|
|
|
// wait for it to start
|
|
#ifdef WIN32
|
|
Sleep(1000);
|
|
#else
|
|
sleep(1);
|
|
#endif
|
|
int channels = dynamic_cast<ANTlocalController*>(wizard->controller)->channels();
|
|
|
|
// Tree Widget of the channel controls
|
|
channelWidget->clear();
|
|
channelWidget->headerItem()->setText(0, tr("Sensor"));
|
|
channelWidget->headerItem()->setText(1, tr("ANT+ Id"));
|
|
channelWidget->headerItem()->setText(2, tr("Value"));
|
|
channelWidget->headerItem()->setText(3, tr("Status"));
|
|
channelWidget->setColumnCount(4);
|
|
channelWidget->setSelectionMode(QAbstractItemView::NoSelection);
|
|
//channelWidget->setEditTriggers(QAbstractItemView::SelectedClicked); // allow edit
|
|
channelWidget->setUniformRowHeights(true);
|
|
channelWidget->setIndentation(0);
|
|
|
|
channelWidget->header()->resizeSection(0,175); // type
|
|
channelWidget->header()->resizeSection(1,75); // id
|
|
channelWidget->header()->resizeSection(2,120); // value
|
|
channelWidget->header()->resizeSection(3,110); // status
|
|
|
|
// defaults
|
|
static const int index4[4] = { 1,2,3,5 };
|
|
static const int index8[8] = { 1,2,3,4,5,0,0,0 };
|
|
const int *index = channels == 4 ? index4 : index8;
|
|
|
|
// how many devices we got then?
|
|
for (int i=0; i< channels; i++) {
|
|
|
|
QTreeWidgetItem *add = new QTreeWidgetItem(channelWidget->invisibleRootItem());
|
|
add->setFlags(add->flags() | Qt::ItemIsEditable);
|
|
|
|
// sensor type
|
|
QComboBox *sensorSelector = new QComboBox(this);
|
|
addSensorTypes(dynamic_cast<ANTlocalController*>(wizard->controller)->myANTlocal, sensorSelector);
|
|
sensorSelector->setCurrentIndex(index[i]);
|
|
channelWidget->setItemWidget(add, 0, sensorSelector);
|
|
|
|
// sensor id
|
|
QLineEdit *sensorId = new QLineEdit(this);
|
|
sensorId->setEnabled(false);
|
|
sensorId->setText("none");
|
|
channelWidget->setItemWidget(add, 1, sensorId);
|
|
|
|
// value
|
|
QLabel *value = new QLabel(this);
|
|
QFont bigger;
|
|
bigger.setPointSize(25);
|
|
value->setFont(bigger);
|
|
value->setAlignment(Qt::AlignCenter | Qt::AlignVCenter);
|
|
value->setText("0");
|
|
channelWidget->setItemWidget(add, 2, value);
|
|
|
|
// status
|
|
QLabel *status = new QLabel(this);
|
|
status->setText("Un-Paired");
|
|
channelWidget->setItemWidget(add, 3, status);
|
|
|
|
//channelWidget->verticalHeader()->resizeSection(i,40)
|
|
connect(sensorSelector, SIGNAL(currentIndexChanged(int)), signalMapper, SLOT(map()));
|
|
signalMapper->setMapping(sensorSelector, i);
|
|
}
|
|
channelWidget->setCurrentItem(channelWidget->invisibleRootItem()->child(0));
|
|
enableDisable(channelWidget);
|
|
|
|
updateValues.start(200); // 5hz
|
|
connect(signalMapper, SIGNAL(mapped(int)), this, SLOT(sensorChanged(int)));
|
|
connect(&updateValues, SIGNAL(timeout()), this, SLOT(getChannelValues()));
|
|
connect(wizard->controller, SIGNAL(foundDevice(int,int,int)), this, SLOT(channelInfo(int,int,int)));
|
|
connect(wizard->controller, SIGNAL(searchTimeout(int)), this, SLOT(searchTimeout(int)));
|
|
//connect(wizard->controller, SIGNAL(lostDevice(int)), this, SLOT(searchTimeout(int)));
|
|
|
|
// now we're ready to get notifications - set channels
|
|
for (int i=0; i<channels; i++) sensorChanged(i);
|
|
|
|
}
|
|
|
|
void
|
|
AddPairBTLE::sensorChanged(int channel)
|
|
{
|
|
QTreeWidgetItem *item = channelWidget->invisibleRootItem()->child(channel);
|
|
enableDisable(channelWidget);
|
|
|
|
// first off lets unassign this channel
|
|
dynamic_cast<ANTlocalController*>(wizard->controller)->myANTlocal->setChannel(channel, -1, 0);
|
|
dynamic_cast<QLineEdit*>(channelWidget->itemWidget(item,1))->setText("none");
|
|
dynamic_cast<QLabel*>(channelWidget->itemWidget(item,2))->setText(0);
|
|
|
|
// what is it then? unused or restart scan?
|
|
QComboBox *p = dynamic_cast<QComboBox *>(channelWidget->itemWidget(item,0));
|
|
int channel_type = p->itemData(p->currentIndex()).toInt();
|
|
if (channel_type == ANTChannel::CHANNEL_TYPE_UNUSED) {
|
|
dynamic_cast<QLabel*>(channelWidget->itemWidget(item,3))->setText("Unused");
|
|
} else {
|
|
dynamic_cast<QLabel*>(channelWidget->itemWidget(item,3))->setText("Searching...");
|
|
dynamic_cast<ANTlocalController*>(wizard->controller)->myANTlocal->setChannel(channel, 0, channel_type);
|
|
}
|
|
}
|
|
|
|
void
|
|
AddPairBTLE::channelInfo(int channel, int device_number, int device_id)
|
|
{
|
|
Q_UNUSED(device_id);
|
|
QTreeWidgetItem *item = channelWidget->invisibleRootItem()->child(channel);
|
|
dynamic_cast<QLineEdit *>(channelWidget->itemWidget(item,1))->setText(QString("%1").arg(device_number));
|
|
dynamic_cast<QLabel *>(channelWidget->itemWidget(item,3))->setText(QString("Paired"));
|
|
}
|
|
|
|
void
|
|
AddPairBTLE::searchTimeout(int channel)
|
|
{
|
|
// Kick if off again, just mimic user reselecting the same sensor type
|
|
sensorChanged(channel);
|
|
}
|
|
|
|
|
|
void
|
|
AddPairBTLE::getChannelValues()
|
|
{
|
|
if (wizard->controller == NULL) return;
|
|
|
|
// enable disable widgets based upon sensor selection
|
|
for (int i=0; i< channelWidget->invisibleRootItem()->childCount(); i++) {
|
|
QTreeWidgetItem *item = channelWidget->invisibleRootItem()->child(i);
|
|
|
|
// is it selected or not?
|
|
bool enable = (dynamic_cast<QComboBox*>(channelWidget->itemWidget(item,0))->currentIndex() != 0);
|
|
|
|
if (enable) {
|
|
QComboBox *p =dynamic_cast<QComboBox*>(channelWidget->itemWidget(item,0));
|
|
|
|
// speed+cadence is two values!
|
|
if (p->itemData(p->currentIndex()) == ANTChannel::CHANNEL_TYPE_SandC) {
|
|
dynamic_cast<QLabel *>(channelWidget->itemWidget(item,2))->setText(QString("%1 %2")
|
|
.arg((int)dynamic_cast<ANTlocalController*>(wizard->controller)->myANTlocal->channelValue2(i) //speed
|
|
* (appsettings->value(NULL, GC_WHEELSIZE, 2100).toInt()/1000) * 60 / 1000)
|
|
.arg((int)dynamic_cast<ANTlocalController*>(wizard->controller)->myANTlocal->channelValue(i))); // cad
|
|
} else {
|
|
dynamic_cast<QLabel *>(channelWidget->itemWidget(item,2))->setText(QString("%1")
|
|
.arg((int)dynamic_cast<ANTlocalController*>(wizard->controller)->myANTlocal->channelValue(i)));
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
bool
|
|
AddPairBTLE::validatePage()
|
|
{
|
|
// when next is clicked we need to get the paired values
|
|
// and create a profile, a blank profile will be created if
|
|
// no devices have been paired. This means devices will be
|
|
// automatically paired at runtime
|
|
wizard->profile="";
|
|
for (int i=0; i< channelWidget->invisibleRootItem()->childCount(); i++) {
|
|
QTreeWidgetItem *item = channelWidget->invisibleRootItem()->child(i);
|
|
|
|
// what is it then? unused or restart scan?
|
|
QComboBox *p = dynamic_cast<QComboBox *>(channelWidget->itemWidget(item,0));
|
|
int channel_type = p->itemData(p->currentIndex()).toInt();
|
|
|
|
if (channel_type == ANTChannel::CHANNEL_TYPE_UNUSED) continue; // not paired
|
|
|
|
int device_number = dynamic_cast<QLineEdit*>(channelWidget->itemWidget(item,1))->text().toInt();
|
|
|
|
if (device_number)
|
|
wizard->profile += QString(wizard->profile != "" ? ", %1%2" : "%1%2")
|
|
.arg(device_number)
|
|
.arg(ANT::deviceIdCode(channel_type));
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// Final confirmation
|
|
AddFinal::AddFinal(AddDeviceWizard *parent) : QWizardPage(parent), wizard(parent)
|
|
{
|
|
setTitle(tr("Done"));
|
|
setSubTitle(tr("Confirm configuration and add device"));
|
|
|
|
QVBoxLayout *layout = new QVBoxLayout;
|
|
setLayout(layout);
|
|
|
|
QLabel *label = new QLabel("We will now add a new device with the configuration shown "
|
|
"below. Please take a moment to review and then click Finish "
|
|
"to add the device and complete this wizard, or press the Back "
|
|
"button to make amendments.\n\n");
|
|
label->setWordWrap(true);
|
|
layout->addWidget(label);
|
|
|
|
QHBoxLayout *hlayout = new QHBoxLayout;
|
|
layout->addLayout(hlayout);
|
|
|
|
QFormLayout *formlayout = new QFormLayout;
|
|
formlayout->addRow(new QLabel("Name*", this), (name=new QLineEdit(this)));
|
|
formlayout->addRow(new QLabel("Port", this), (port=new QLineEdit(this)));
|
|
formlayout->addRow(new QLabel("Profile", this), (profile=new QLineEdit(this)));
|
|
formlayout->setFieldGrowthPolicy(QFormLayout::FieldsStayAtSizeHint);
|
|
//profile->setFixedWidth(200);
|
|
port->setFixedWidth(150);
|
|
port->setEnabled(false); // no edit
|
|
//name->setFixedWidth(230);
|
|
hlayout->addLayout(formlayout);
|
|
|
|
QFormLayout *form2layout = new QFormLayout;
|
|
form2layout->addRow(new QLabel("Virtual", this), (virtualPower=new QComboBox(this)));
|
|
form2layout->addRow(new QLabel("Wheel Size", this), (wheelSize=new QComboBox(this)));
|
|
// XXX NOTE: THESE MUST CORRESPOND TO THE CODE
|
|
// IN RealtimeController.cpp WHICH
|
|
// POST-PROCESSES INBOUND TELEMETRY
|
|
virtualPower->addItem("None");
|
|
virtualPower->addItem("Power - Kurt Kinetic Cyclone");
|
|
virtualPower->addItem("Power - Kurt Kinetic Road Machine");
|
|
virtualPower->addItem("Power - Cyclops Fluid 2");
|
|
virtualPower->addItem("Power - BT Advanced Training System");
|
|
virtualPower->addItem("Power - LeMond Revolution");
|
|
virtualPower->addItem("Power - 1UP USA Trainer");
|
|
virtualPower->addItem("Power - Minoura V100 Trainer (H)");
|
|
virtualPower->addItem("Power - Minoura V100 Trainer (5)");
|
|
virtualPower->addItem("Power - Minoura V100 Trainer (4)");
|
|
virtualPower->addItem("Power - Minoura V100 Trainer (3)");
|
|
virtualPower->addItem("Power - Minoura V100 Trainer (2)");
|
|
virtualPower->addItem("Power - Minoura V100 Trainer (1)");
|
|
virtualPower->addItem("Power - Minoura V100 Trainer (L)");
|
|
virtualPower->addItem("Power - Saris Powerbeam Pro");
|
|
|
|
wheelSize->addItem("Road/Cross (700C/622)"); // 2100mm
|
|
wheelSize->addItem("Tri/TT (650C)"); // 1960mm
|
|
wheelSize->addItem("Mountain (26\")"); // 1985mm
|
|
wheelSize->addItem("BMX (20\")"); // 1750mm
|
|
|
|
hlayout->addLayout(form2layout);
|
|
layout->addStretch();
|
|
|
|
selectDefault = new QGroupBox("Selected by default", this);
|
|
selectDefault->setCheckable(true);
|
|
selectDefault->setChecked(false);
|
|
layout->addWidget(selectDefault);
|
|
|
|
QGridLayout *grid = new QGridLayout;
|
|
selectDefault->setLayout(grid);
|
|
grid->addWidget((defWatts=new QCheckBox("Power")), 0,0, Qt::AlignVCenter|Qt::AlignLeft);
|
|
grid->addWidget((defBPM=new QCheckBox("Heartrate")), 1,0, Qt::AlignVCenter|Qt::AlignLeft);
|
|
grid->addWidget((defKPH=new QCheckBox("Speed")), 0,1, Qt::AlignVCenter|Qt::AlignLeft);
|
|
grid->addWidget((defRPM=new QCheckBox("Cadence")), 1,1, Qt::AlignVCenter|Qt::AlignLeft);
|
|
layout->addStretch();
|
|
}
|
|
|
|
void
|
|
AddFinal::initializePage()
|
|
{
|
|
port->setText(wizard->portSpec);
|
|
profile->setText(wizard->profile);
|
|
virtualPower->setCurrentIndex(0);
|
|
}
|
|
|
|
bool
|
|
AddFinal::validatePage()
|
|
{
|
|
if (name->text() != "") {
|
|
|
|
DeviceConfigurations all;
|
|
DeviceConfiguration add;
|
|
|
|
|
|
// lets update 'here' with what we did then...
|
|
add.type = wizard->type;
|
|
add.name = name->text();
|
|
add.portSpec = port->text();
|
|
add.deviceProfile = profile->text();
|
|
add.defaultString = QString(defWatts->isChecked() ? "P" : "") +
|
|
QString(defBPM->isChecked() ? "H" : "") +
|
|
QString(defRPM->isChecked() ? "C" : "") +
|
|
QString(defKPH->isChecked() ? "S" : "");
|
|
add.postProcess = virtualPower->currentIndex();
|
|
|
|
switch (wheelSize->currentIndex()) {
|
|
|
|
default:
|
|
case 0: add.wheelSize = 2100 ; break;
|
|
case 1: add.wheelSize = 1960 ; break;
|
|
case 2: add.wheelSize = 1985 ; break;
|
|
case 3: add.wheelSize = 1750 ; break;
|
|
}
|
|
|
|
QList<DeviceConfiguration> list = all.getList();
|
|
list.insert(0, add);
|
|
|
|
// call device add wizard.
|
|
all.writeConfig(list);
|
|
|
|
// tell everyone
|
|
wizard->main->notifyConfigChanged();
|
|
|
|
// shut down the controller, if it is there, since it will
|
|
// still be connected to the device (in case we hit the back button)
|
|
if (wizard->controller) {
|
|
wizard->controller->stop();
|
|
#ifdef WIN32
|
|
Sleep(1000);
|
|
#else
|
|
sleep(1);
|
|
#endif
|
|
delete wizard->controller;
|
|
wizard->controller = NULL;
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|