Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 30 additions & 12 deletions src/devices/ftmsbike/ftmsbike.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "ftmsbike.h"
#include "devices/cscbike/cscbike.h"
#include "horizon5r_defaults.h"
#include "speedracex_defaults.h"
#include "homeform.h"
#include "virtualdevices/virtualbike.h"
Expand Down Expand Up @@ -589,19 +590,32 @@ void ftmsbike::update() {
lastRequestedPower().value() > 0 && autoResistance()) {
resistance_t newR = resistanceFromPowerRequest(
(uint16_t)lastRequestedPower().value());
if (newR != m_lastErgResistance && newR > 0) {
// ERG death spiral protection: below 50 RPM, only allow resistance decreases
if (Cadence.value() > 0 && Cadence.value() < 50 && newR > m_lastErgResistance) {
qDebug() << "ERG death spiral protection: cadence" << Cadence.value()
<< "< 50, blocking resistance increase"
<< m_lastErgResistance << "->" << newR;
} else {
qDebug() << "continuous ERG: cadence" << Cadence.value()
<< "target" << lastRequestedPower().value()
<< "resistance" << m_lastErgResistance << "->" << newR;
forceResistance(newR);
m_lastErgResistance = newR;
if (newR > 0 && newR != m_lastErgResistance) {
// Debounce: only commit a resistance change once the new value has been
// requested consistently for ERG_RESISTANCE_DEBOUNCE_MS. Cadence noise right
// at a lookup-table boundary can otherwise flip newR back and forth every
// update() cycle even after quantizing the cadence (see resistanceFromPowerRequest).
const int ERG_RESISTANCE_DEBOUNCE_MS = 2000;
if (newR != m_pendingErgResistance) {
m_pendingErgResistance = newR;
m_pendingErgResistanceTime = QDateTime::currentDateTime();
} else if (m_pendingErgResistanceTime.msecsTo(QDateTime::currentDateTime()) >=
ERG_RESISTANCE_DEBOUNCE_MS) {
// ERG death spiral protection: below 50 RPM, only allow resistance decreases
if (Cadence.value() > 0 && Cadence.value() < 50 && newR > m_lastErgResistance) {
qDebug() << "ERG death spiral protection: cadence" << Cadence.value()
<< "< 50, blocking resistance increase"
<< m_lastErgResistance << "->" << newR;
} else {
qDebug() << "continuous ERG: cadence" << Cadence.value()
<< "target" << lastRequestedPower().value()
<< "resistance" << m_lastErgResistance << "->" << newR;
forceResistance(newR);
m_lastErgResistance = newR;
}
}
} else {
m_pendingErgResistance = -1;
}
}

Expand Down Expand Up @@ -2020,6 +2034,10 @@ void ftmsbike::deviceDiscovered(const QBluetoothDeviceInfo &device) {
resistance_lvl_mode = true;
ergModeSupported = false;
JFBK5_0 = true;
if (bluetoothDevice.name().compare(QStringLiteral("JFBK5.0R"), Qt::CaseInsensitive) == 0) {
_ergTable.loadDefaultData(kHorizon5RDefaultErgData);
_ergTable.setCadenceResistanceBandStep(5);
}
} else if((bluetoothDevice.name().toUpper().startsWith("BIKE-"))) {
qDebug() << QStringLiteral("BIKE- found");
BIKE_ = true;
Expand Down
2 changes: 2 additions & 0 deletions src/devices/ftmsbike/ftmsbike.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,8 @@ class ftmsbike : public bike {

bool powerForced = false;
resistance_t m_lastErgResistance = 0;
resistance_t m_pendingErgResistance = -1;
QDateTime m_pendingErgResistanceTime;
bool manualResistancePowerAdjustmentActive = false;
bool manualResistancePowerAdjustmentToastShown = false;
resistance_t manualResistanceTarget = 1;
Expand Down
237 changes: 237 additions & 0 deletions src/devices/ftmsbike/horizon5r_defaults.h

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions src/ergtable.h
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,15 @@ class ergTable : public QObject {
return sameResPoints.first().wattage;
}

void setCadenceResistanceBandStep(uint16_t step) {
cadenceResistanceBandStep = step;
}

uint16_t resistanceFromPowerRequest(uint16_t power, uint16_t cadence, uint16_t maxResistance) {
if (cadenceResistanceBandStep > 1) {
cadence = (cadence / cadenceResistanceBandStep) * cadenceResistanceBandStep;
}

qDebug() << QStringLiteral("resistanceFromPowerRequest") << cadence;

if (cadence == 0)
Expand Down Expand Up @@ -263,6 +271,7 @@ class ergTable : public QObject {
QMap<CadenceResistancePair, WattageStats> wattageData;
QList<ergDataPoint> consolidatedData;
uint16_t lastResistanceValue = 0xFFFF;
uint16_t cadenceResistanceBandStep = 0;
QDateTime lastResistanceTime = QDateTime::currentDateTime();

void updateDataTable(const CadenceResistancePair& pair) {
Expand Down
1 change: 1 addition & 0 deletions src/qdomyos-zwift.pri
Original file line number Diff line number Diff line change
Expand Up @@ -784,6 +784,7 @@ fit-sdk/fit_zones_target_mesg.hpp \
fit-sdk/fit_zones_target_mesg_listener.hpp \
devices/flywheelbike/flywheelbike.h \
devices/ftmsbike/ftmsbike.h \
devices/ftmsbike/horizon5r_defaults.h \
devices/ftmsbike/speedracex_defaults.h \
devices/heartratebelt/heartratebelt.h \
homeform.h \
Expand Down
1 change: 1 addition & 0 deletions tst/Devices/deviceindex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ DEFINE_DEVICE(FTMSBikeHammerRacerS, "FTMS Bike Hammer Racer S");
DEFINE_DEVICE(FTMSBike, "FTMS Bike");
DEFINE_DEVICE(FTMSBike2, "FTMS Bike 2");
DEFINE_DEVICE(FTMSBike3, "FTMS Bike 3");
DEFINE_DEVICE(FTMSBikeHorizon5R, "FTMS Bike Horizon 5.0R");
DEFINE_DEVICE(FTMSKICKRCORE, "FTMS KICKR CORE");
DEFINE_DEVICE(FTMSRower, "FTMS Rower");
DEFINE_DEVICE(FakeBike, "Fake Bike");
Expand Down
2 changes: 1 addition & 1 deletion tst/Devices/deviceindex.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ class DeviceIndex
DEFINE_DEVICE(FTMSBike, "FTMS Bike");
DEFINE_DEVICE(FTMSBike2, "FTMS Bike 2");
DEFINE_DEVICE(FTMSBike3, "FTMS Bike 3");
DEFINE_DEVICE(FTMSBikeHorizon5R, "FTMS Bike Horizon 5.0R");
DEFINE_DEVICE(FTMSKICKRCORE, "FTMS KICKR CORE");
DEFINE_DEVICE(FTMSRower, "FTMS Rower");
DEFINE_DEVICE(FakeBike, "Fake Bike");
Expand Down Expand Up @@ -179,4 +180,3 @@ class DeviceIndex

};


6 changes: 6 additions & 0 deletions tst/Devices/devicetestdataindex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -658,6 +658,12 @@ void DeviceTestDataIndex::Initialize() {
->excluding(ftmsBikeConfigureExclusions)
->configureSettingsWith(QBluetoothUuid((quint16)0x1826));

// FTMS Bike Horizon 5.0R
RegisterNewDeviceTestData(DeviceIndex::FTMSBikeHorizon5R)
->expectDevice<ftmsbike>()
->acceptDeviceName("JFBK5.0R", DeviceNameComparison::IgnoreCase)
->excluding(ftmsBikeConfigureExclusions);

// FTMS Rower
RegisterNewDeviceTestData(DeviceIndex::FTMSRower)
->expectDevice<ftmsrower>()
Expand Down
18 changes: 18 additions & 0 deletions tst/Erg/ergtabletestsuite.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -592,3 +592,21 @@ void ErgTableTestSuite::test_dynamicErgTable() {
this->test_wattageEstimation(inputs, expected);

}

void ErgTableTestSuite::test_resistanceCadenceBanding() {

TestSettings testSettings("Roberto Viola", "QDomyos-Zwift Testing");
testSettings.activate();
testSettings.qsettings.remove("ergDataPoints");

ergTable erg;
erg.loadDefaultData(QStringLiteral("80|100|1;80|120|2;85|130|1;85|150|2"));

EXPECT_EQ(1, erg.resistanceFromPowerRequest(130, 84, 3));

erg.setCadenceResistanceBandStep(5);

EXPECT_EQ(2, erg.resistanceFromPowerRequest(130, 80, 3));
EXPECT_EQ(2, erg.resistanceFromPowerRequest(130, 84, 3));
EXPECT_EQ(1, erg.resistanceFromPowerRequest(130, 85, 3));
}
4 changes: 4 additions & 0 deletions tst/Erg/ergtabletestsuite.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,15 @@ class ErgTableTestSuite: public testing::Test {
* @brief Test the overall functionality of an ergtable object
*/
void test_dynamicErgTable();
void test_resistanceCadenceBanding();

};

TEST_F(ErgTableTestSuite, TestDynamicErgTable) {
this->test_dynamicErgTable();
}

TEST_F(ErgTableTestSuite, TestResistanceCadenceBanding) {
this->test_resistanceCadenceBanding();
}

Loading