Skip to content

Instantly share code, notes, and snippets.

@ihewitt
Created February 16, 2016 20:51
Show Gist options
  • Save ihewitt/6f89405bf3e0d8a216f3 to your computer and use it in GitHub Desktop.
Save ihewitt/6f89405bf3e0d8a216f3 to your computer and use it in GitHub Desktop.
diff --git a/src/ANT.cpp b/src/ANT.cpp
index e23f0bf..39316d2 100644
--- a/src/ANT.cpp
+++ b/src/ANT.cpp
@@ -69,6 +69,8 @@ const ant_sensor_type_t ANT::ant_sensor_types[] = {
ANT_TACX_VORTEX_FREQUENCY, DEFAULT_NETWORK_NUMBER, "Tacx Vortex Smart", 'v', ":images/IconPower.png" },
{ true, ANTChannel::CHANNEL_TYPE_FITNESS_EQUIPMENT, ANT_SPORT_FITNESS_EQUIPMENT_PERIOD, ANT_SPORT_FITNESS_EQUIPMENT_TYPE,
ANT_FITNESS_EQUIPMENT_FREQUENCY, ANT_SPORT_NETWORK_NUMBER, "Fitness Equipment Control (FE-C)", 'f', ":images/IconPower.png" },
+ { true, ANTChannel::CHANNEL_TYPE_QUBO_DIGITAL, ANT_SPORT_QUBO_PERIOD, ANT_SPORT_SandC_TYPE,
+ ANT_SPORT_FREQUENCY, ANT_SPORT_NETWORK_NUMBER, "Elite QUBO Digital", 'q', ":images/IconPower.png" },
{ false, ANTChannel::CHANNEL_TYPE_GUARD, 0, 0, 0, 0, "", '\0', "" }
};
@@ -108,6 +110,8 @@ ANT::ANT(QObject *parent, DeviceConfiguration *devConf, QString athlete) : QThre
fecChannel = -1;
+ quboChannel = -1;
+
// current and desired modes/load/gradients
// set so first time through current != desired
currentMode = 0;
@@ -297,6 +301,12 @@ ANT::setLoad(double load)
{
sendMessage(ANTMessage::fecSetTargetPower(fecChannel, (int)load));
}
+
+ // if we have a qubo digital trainer set the target power
+ if (quboChannel != -1)
+ {
+ sendMessage(ANTMessage::quboSetTargetPower(quboChannel, (int)load));
+ }
}
void ANT::refreshFecLoad()
@@ -333,6 +343,13 @@ void ANT::refreshVortexLoad()
sendMessage(ANTMessage::tacxVortexSetPower(vortexChannel, vortexID, (int)load));
}
+void ANT::refreshQuboLoad()
+{
+ if (quboChannel == -1)
+ return;
+
+ sendMessage(ANTMessage::quboSetTargetPower(quboChannel, (int)load));
+}
void
ANT::setGradient(double gradient)
{
@@ -482,6 +499,7 @@ ANT::setup()
addDevice(0, ANTChannel::CHANNEL_TYPE_SandC, 4);
addDevice(0, ANTChannel::CHANNEL_TYPE_MOXY, 5);
addDevice(0, ANTChannel::CHANNEL_TYPE_FITNESS_EQUIPMENT, 6);
+ addDevice(0, ANTChannel::CHANNEL_TYPE_QUBO_DIGITAL, 7);
}
}
}
@@ -1290,6 +1308,11 @@ void ANT::setFecChannel(int channel)
fecChannel = channel;
}
+void ANT::setQuboChannel(int channel)
+{
+ quboChannel = channel;
+}
+
void ANT::setControlChannel(int channel)
{
controlChannel = channel;
diff --git a/src/ANT.h b/src/ANT.h
index 880fcba..65cfcb1 100644
--- a/src/ANT.h
+++ b/src/ANT.h
@@ -242,6 +242,7 @@ struct setChannelAtom {
#define ANT_SPORT_FITNESS_EQUIPMENT_PERIOD 8192
#define ANT_FAST_QUARQ_PERIOD (8182/16)
#define ANT_QUARQ_PERIOD (8182*4)
+#define ANT_SPORT_QUBO_PERIOD 16172
#define ANT_SPORT_HR_TYPE 0x78
#define ANT_SPORT_POWER_TYPE 11
@@ -541,6 +542,9 @@ public:
void refreshFecGradient();
void requestFecCapabilities();
+ void setQuboChannel(int channel);
+ void refreshQuboLoad();
+
void setVortexData(int channel, int id);
void refreshVortexLoad();
@@ -618,6 +622,9 @@ private:
int vortexID;
int vortexChannel;
+ // Qubo digital data
+ int quboChannel;
+
// remote control data
int controlChannel;
diff --git a/src/ANTChannel.cpp b/src/ANTChannel.cpp
index 356a2bd..37ab066 100644
--- a/src/ANTChannel.cpp
+++ b/src/ANTChannel.cpp
@@ -709,6 +709,30 @@ void ANTChannel::broadcastEvent(unsigned char *ant_message)
}
break;
+ //QUBO Digital
+ case CHANNEL_TYPE_QUBO_DIGITAL:
+ {
+ static int quboRefreshCounter = 1;
+
+ parent->setQuboChannel(number);
+
+ if ((quboRefreshCounter++ % 10) == 0)
+ {
+ parent->refreshQuboLoad();
+ }
+ if (antMessage.quboSpeed > 0)
+ {
+ parent->setSpeed(antMessage.quboSpeed);
+ value = antMessage.quboSpeed;
+ }
+ if (antMessage.quboCadence)
+ {
+ parent->setSecondaryCadence(antMessage.quboCadence);
+ value2 = antMessage.quboCadence;
+ }
+ }
+ break;
+
//moxy
case CHANNEL_TYPE_MOXY:
{
diff --git a/src/ANTChannel.h b/src/ANTChannel.h
index 8b48b33..8dd89bc 100644
--- a/src/ANTChannel.h
+++ b/src/ANTChannel.h
@@ -133,6 +133,7 @@ class ANTChannel : public QObject {
CHANNEL_TYPE_CONTROL,
CHANNEL_TYPE_TACX_VORTEX,
CHANNEL_TYPE_FITNESS_EQUIPMENT,
+ CHANNEL_TYPE_QUBO_DIGITAL,
CHANNEL_TYPE_GUARD
};
typedef enum channeltype ChannelType;
diff --git a/src/ANTMessage.cpp b/src/ANTMessage.cpp
index 7a4f989..8d7a4a8 100644
--- a/src/ANTMessage.cpp
+++ b/src/ANTMessage.cpp
@@ -509,6 +509,21 @@ ANTMessage::ANTMessage(ANT *parent, const unsigned char *message) {
wheelRevolutions = message[10] + (message[11]<<8);
break;
+ case ANTChannel::CHANNEL_TYPE_QUBO_DIGITAL:
+ channel=message[3];
+
+ quboSpeed = 0.1f * (message[4] & 0xf)+
+ 1 * (message[4] >> 4)+
+ 10 * (message[5] >> 4)+
+ 100 * (message[5] & 0xf);
+
+ quboCadence = 1 * (message[8] >> 4)+
+ 10 * (message[9] >> 4)+
+ 100 * (message[9] & 0xf);
+
+// dist = (message[6]<<1) + (message[4]<<7); //distance?
+ break;
+
case ANTChannel::CHANNEL_TYPE_MOXY:
channel = message[3];
utcTimeRequired = message[6] & 0x01;
@@ -759,6 +774,8 @@ void ANTMessage::init()
fecPowerOverLimits = fecState = fecHRSource = 0;
fecDistanceCapability = fecSpeedIsVirtual = false;
fecEqtType = 0;
+ quboSpeed = 0;
+ quboCadence = 0.0;
}
ANTMessage ANTMessage::resetSystem()
@@ -1010,6 +1027,14 @@ ANTMessage ANTMessage::fecSetResistance(const uint8_t channel, const uint8_t res
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, resistance);
}
+ANTMessage ANTMessage::quboSetResistance(const uint8_t channel, const uint8_t resistance) // 0-200% -> 0-16
+{
+ uint8_t levelValue = resistance * 16 / 200;
+
+ return ANTMessage(9, ANT_ACK_DATA, channel,
+ 0xFF, 0xFF, levelValue, 0, 0, 0, 0, 1 );
+}
+
ANTMessage ANTMessage::fecSetTargetPower(const uint8_t channel, const uint16_t targetPower)
{
// unit is 0.25W, but targetPower are full watts and theres no trainer with that precision anyway
@@ -1019,6 +1044,13 @@ ANTMessage ANTMessage::fecSetTargetPower(const uint8_t channel, const uint16_t t
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, (uint8_t)(powerValue & 0xFF), (uint8_t)(powerValue >> 8));
}
+ANTMessage ANTMessage::quboSetTargetPower(const uint8_t channel, const uint16_t targetPower) // power in 1W
+{
+ return ANTMessage(9, ANT_ACK_DATA, channel,
+ (uint8_t)(targetPower & 0xFF), (uint8_t)(targetPower >> 8),
+ 0, 0, 0, 0, 0, 1 );
+}
+
ANTMessage ANTMessage::fecSetWindResistance(const uint8_t channel, const double windResistance, const uint8_t windSpeed, const uint8_t draftingFactor)
// 0.00 < kg/m < 1.86 -127 < kph < + 127 0 < % < 100%
{
diff --git a/src/ANTMessage.h b/src/ANTMessage.h
index c81c5bb..f80a963 100644
--- a/src/ANTMessage.h
+++ b/src/ANTMessage.h
@@ -77,6 +77,10 @@ class ANTMessage {
static ANTMessage tacxVortexSetCalibrationValue(const uint8_t channel, const uint16_t vortexId, const uint8_t calibrationValue);
static ANTMessage tacxVortexSetPower(const uint8_t channel, const uint16_t vortexId, const uint16_t power);
+ // QUBO digital control messages
+ static ANTMessage quboSetResistance(const uint8_t channel, const uint8_t resistance);
+ static ANTMessage quboSetTargetPower(const uint8_t channel, const uint16_t targetPower);
+
// fitness equipment control messages
static ANTMessage fecSetResistance(const uint8_t channel, const uint8_t resistance);
static ANTMessage fecSetTargetPower(const uint8_t channel, const uint16_t targetPower);
@@ -175,6 +179,10 @@ class ANTMessage {
int8_t fecSetWindSpeedAck; // -127 / +127 km/h
uint8_t fecSetDraftingFactorAck; // 0 / 100 %
+ // qubo digital
+ uint16_t quboCadence;
+ double quboSpeed;
+
// remote control
uint8_t controlSeq;
uint16_t controlSerial, controlVendor, controlCmd;
diff --git a/src/AddDeviceWizard.cpp b/src/AddDeviceWizard.cpp
index ae99e21..dd52400 100644
--- a/src/AddDeviceWizard.cpp
+++ b/src/AddDeviceWizard.cpp
@@ -686,7 +686,7 @@ AddPair::initializePage()
// defaults
static const int index4[4] = { 1,2,3,5 };
- static const int index8[8] = { 1,2,3,4,5,6,9,0 };
+ static const int index8[8] = { 1,2,3,4,5,6,9,10 };
const int *index = channels == 4 ? index4 : index8;
// how many devices we got then?
@@ -815,6 +815,11 @@ AddPair::getChannelValues()
.arg(dynamic_cast<ANTlocalController*>(wizard->controller)->myANTlocal->channelValue(i), 0, 'f', 1) // tHb
.arg(dynamic_cast<ANTlocalController*>(wizard->controller)->myANTlocal->channelValue2(i), 0, 'f', 1)); // SmO2
+ } else if (p->itemData(p->currentIndex()) == ANTChannel::CHANNEL_TYPE_QUBO_DIGITAL) {
+
+ dynamic_cast<QLabel *>(channelWidget->itemWidget(item,2))->setText(QString("%1 %2")
+ .arg(dynamic_cast<ANTlocalController*>(wizard->controller)->myANTlocal->channelValue(i),0,'f',1) //speed
+ .arg((int)dynamic_cast<ANTlocalController*>(wizard->controller)->myANTlocal->channelValue2(i))); // cad
} else {
dynamic_cast<QLabel *>(channelWidget->itemWidget(item,2))->setText(QString("%1")
.arg((int)dynamic_cast<ANTlocalController*>(wizard->controller)->myANTlocal->channelValue(i)));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment