From 678facc187294531383e05ebc1e1e2234c0671d3 Mon Sep 17 00:00:00 2001 From: David Mason Date: Fri, 1 Mar 2024 21:50:19 +0000 Subject: [PATCH 01/13] #2174 Added tests for bike power functions --- tst/Devices/ApexBike/apexbiketestdata.h | 7 +- tst/Devices/Bike/biketestdata.h | 27 +++ tst/Devices/BkoolBike/bkoolbiketestdata.h | 11 +- tst/Devices/CSCBike/cscbiketestdata.h | 5 + tst/Devices/Chronobike/chronobiketestdata.h | 5 +- .../CompuTrainer/computrainertestdata.h | 4 + tst/Devices/DomyosBike/domyosbiketestdata.h | 5 +- .../echelonconnectsportbiketestdata.h | 5 +- tst/Devices/FTMSBike/ftmsbiketestdata.cpp | 4 + tst/Devices/FTMSBike/ftmsbiketestdata.h | 6 +- tst/Devices/FakeBike/fakebiketestdata.h | 4 + tst/Devices/FitPlusBike/fitplusbiketestdata.h | 9 +- .../FlywheelBike/flywheelbiketestdata.h | 3 + .../HorizonGR7Bike/horizongr7biketestdata.h | 5 +- tst/Devices/InspireBike/inspirebiketestdata.h | 5 +- tst/Devices/KeepBike/keepbiketestdata.h | 5 +- tst/Devices/M3IBike/m3ibiketestdata.h | 3 + tst/Devices/MCFBike/mcfbiketestdata.h | 5 +- tst/Devices/MepanelBike/mepanelbiketestdata.h | 5 +- .../NPECableBike/npecablebiketestdata.h | 3 + .../NautilusBike/nautilusbiketestdata.h | 5 +- tst/Devices/PafersBike/pafersbiketestdata.h | 3 + tst/Devices/ProFormBike/proformbiketestdata.h | 5 +- .../ProFormWiFiBike/proformwifibiketestdata.h | 4 + tst/Devices/RenphoBike/renphobiketestdata.cpp | 2 + tst/Devices/RenphoBike/renphobiketestdata.h | 7 +- .../Schwinn170Bike/schwinn170biketestdata.h | 5 +- .../SchwinnIC4Bike/schwinnic4biketestdata.h | 5 +- .../skandikawirybiketestdata.h | 5 +- tst/Devices/SnodeBike/snodebiketestdata.h | 3 + tst/Devices/SoleBike/solebiketestdata.h | 5 +- .../SportsPlusBike/sportsplusbiketestdata.h | 5 +- .../SportsTechBike/sportstechbiketestdata.h | 5 +- tst/Devices/StagesBike/stagesbiketestdata.h | 3 + tst/Devices/TacxNeo2/tacxneo2testdata.h | 5 +- .../trxappgateusbbiketestdata.h | 3 + .../UltrasportBike/ultrasportbiketestdata.h | 5 +- .../wahookickrsnapbiketestdata.h | 5 +- tst/Devices/YesoulBike/yesoulbiketestdata.h | 8 +- tst/Devices/biketestsuite.cpp | 173 ++++++++++++++++++ tst/Devices/biketestsuite.h | 85 +++++++++ tst/Devices/devices.h | 57 +++++- .../iConceptBike/iconceptbiketestdata.h | 7 +- tst/ErgInterface/bikeergfunctions.cpp | 30 +++ tst/ErgInterface/bikeergfunctions.h | 29 +++ tst/ErgInterface/erginterface.h | 60 ++++++ tst/main.cpp | 17 +- tst/qdomyos-zwift-tests.pro | 7 +- 48 files changed, 634 insertions(+), 45 deletions(-) create mode 100644 tst/Devices/biketestsuite.cpp create mode 100644 tst/Devices/biketestsuite.h create mode 100644 tst/ErgInterface/bikeergfunctions.cpp create mode 100644 tst/ErgInterface/bikeergfunctions.h create mode 100644 tst/ErgInterface/erginterface.h diff --git a/tst/Devices/ApexBike/apexbiketestdata.h b/tst/Devices/ApexBike/apexbiketestdata.h index b37e1edb0..390fb7147 100644 --- a/tst/Devices/ApexBike/apexbiketestdata.h +++ b/tst/Devices/ApexBike/apexbiketestdata.h @@ -1,10 +1,13 @@ #pragma once -#include "Devices/Bike/biketestdata.h".h" +#include "Devices/Bike/biketestdata.h" #include "devices/apexbike/apexbike.h" class ApexBikeTestData : public BikeTestData { - +protected: + bike* doCreateInstance(const BikeOptions& options) override { + return new apexbike(options.noResistance, options.noHeartService, options.resistanceOffset, options.resistanceGain); + } public: ApexBikeTestData() : BikeTestData("Apex Bike") { this->addDeviceName("WLT8266BM", comparison::StartsWithIgnoreCase); diff --git a/tst/Devices/Bike/biketestdata.h b/tst/Devices/Bike/biketestdata.h index ffaea9520..333ec6c46 100644 --- a/tst/Devices/Bike/biketestdata.h +++ b/tst/Devices/Bike/biketestdata.h @@ -3,7 +3,21 @@ #include "Devices/bluetoothdevicetestdata.h" #include "devices/bike.h" +class BikeOptions { +public: + double resistanceGain=1.0, resistanceOffset=0.0; + bool noResistance=false, noHeartService = false, noVirtualDevice = false; + +}; + class BikeTestData : public BluetoothDeviceTestData { +protected: + /** + * @brief Template function called from createInstance to create an instance of the device class. + * @param options + * @return + */ + virtual bike* doCreateInstance(const BikeOptions& options) =0; public: BikeTestData(std::string deviceName) : BluetoothDeviceTestData(deviceName) {} @@ -15,5 +29,18 @@ class BikeTestData : public BluetoothDeviceTestData { bool get_isExpectedDevice(bluetoothdevice * detectedDevice) const override { return dynamic_cast(detectedDevice)!=nullptr; } + + /** + * @brief (Potentially amongst other things) Calls a protected function to create an instance of the device class. + * @param options + * @return + */ + bike* createInstance(const BikeOptions& options) { + // potentially validate or alter the options + auto result = this->doCreateInstance(options); + + // potentially adjust the device object (e.g. connect signals and slots) + return result; + } }; diff --git a/tst/Devices/BkoolBike/bkoolbiketestdata.h b/tst/Devices/BkoolBike/bkoolbiketestdata.h index 96f7163d5..c1bfc335c 100644 --- a/tst/Devices/BkoolBike/bkoolbiketestdata.h +++ b/tst/Devices/BkoolBike/bkoolbiketestdata.h @@ -1,12 +1,15 @@ #pragma once -#include "Devices/bluetoothdevicetestdata.h" +#include "Devices/Bike/biketestdata.h" #include "devices/bkoolbike/bkoolbike.h" -class BkoolBikeTestData : public BluetoothDeviceTestData { - +class BkoolBikeTestData : public BikeTestData { +protected: + bike* doCreateInstance(const BikeOptions& options) override { + return new bkoolbike(options.noResistance, options.noHeartService); + } public: - BkoolBikeTestData() : BluetoothDeviceTestData("Bkool Bike") { + BkoolBikeTestData() : BikeTestData("Bkool Bike") { this->addDeviceName("BKOOLSMARTPRO", comparison::StartsWithIgnoreCase); } diff --git a/tst/Devices/CSCBike/cscbiketestdata.h b/tst/Devices/CSCBike/cscbiketestdata.h index c24db03df..abdaa1265 100644 --- a/tst/Devices/CSCBike/cscbiketestdata.h +++ b/tst/Devices/CSCBike/cscbiketestdata.h @@ -6,6 +6,11 @@ class CSCBikeTestData : public BikeTestData { protected: QString cscBikeName; + + + bike* doCreateInstance(const BikeOptions& options) override { + return new cscbike(options.noResistance, options.noHeartService, options.noVirtualDevice); + } public: CSCBikeTestData(std::string testName) : BikeTestData(testName) { this->cscBikeName = "CyclingSpeedCadenceBike-"; diff --git a/tst/Devices/Chronobike/chronobiketestdata.h b/tst/Devices/Chronobike/chronobiketestdata.h index 40fe1f3ac..a43cda3bb 100644 --- a/tst/Devices/Chronobike/chronobiketestdata.h +++ b/tst/Devices/Chronobike/chronobiketestdata.h @@ -4,7 +4,10 @@ #include "devices/chronobike/chronobike.h" class ChronobikeTestData : public BikeTestData { - +protected: + bike* doCreateInstance(const BikeOptions& options) override { + return new chronobike(options.noResistance, options.noHeartService); + } public: ChronobikeTestData() : BikeTestData("Chronobike") { this->addDeviceName("CHRONO ", comparison::StartsWithIgnoreCase); diff --git a/tst/Devices/CompuTrainer/computrainertestdata.h b/tst/Devices/CompuTrainer/computrainertestdata.h index a93f537ca..b6d64c116 100644 --- a/tst/Devices/CompuTrainer/computrainertestdata.h +++ b/tst/Devices/CompuTrainer/computrainertestdata.h @@ -5,6 +5,10 @@ class CompuTrainerTestData : public BikeTestData { protected: + bike* doCreateInstance(const BikeOptions& options) override { + return new computrainerbike(options.noResistance, options.noHeartService, options.resistanceOffset, options.resistanceGain); + } + bool configureSettings(DeviceDiscoveryInfo& info, bool enable) const override { info.computrainer_serial_port = enable ? "X":QString(); return true; diff --git a/tst/Devices/DomyosBike/domyosbiketestdata.h b/tst/Devices/DomyosBike/domyosbiketestdata.h index ba91cc8e8..031765331 100644 --- a/tst/Devices/DomyosBike/domyosbiketestdata.h +++ b/tst/Devices/DomyosBike/domyosbiketestdata.h @@ -4,7 +4,10 @@ #include "devices/domyosbike/domyosbike.h" class DomyosBikeTestData : public BikeTestData { - +protected: + bike* doCreateInstance(const BikeOptions& options) override { + return new domyosbike(options.noResistance, options.noHeartService, false, options.resistanceOffset, options.resistanceGain); + } public: DomyosBikeTestData() : BikeTestData("Domyos Bike") { diff --git a/tst/Devices/EchelonConnectSportBike/echelonconnectsportbiketestdata.h b/tst/Devices/EchelonConnectSportBike/echelonconnectsportbiketestdata.h index 9e08797ff..2ff101dde 100644 --- a/tst/Devices/EchelonConnectSportBike/echelonconnectsportbiketestdata.h +++ b/tst/Devices/EchelonConnectSportBike/echelonconnectsportbiketestdata.h @@ -6,7 +6,10 @@ #include "devices/echelonconnectsport/echelonconnectsport.h" class EchelonConnectSportBikeTestData : public BikeTestData { - +protected: + bike* doCreateInstance(const BikeOptions& options) override { + return new echelonconnectsport(options.noResistance, options.noHeartService, options.resistanceOffset, options.resistanceGain); + } public: EchelonConnectSportBikeTestData() : BikeTestData("Echelon Connect Sport Bike") { this->addDeviceName("ECH", comparison::StartsWith); diff --git a/tst/Devices/FTMSBike/ftmsbiketestdata.cpp b/tst/Devices/FTMSBike/ftmsbiketestdata.cpp index 1fcfa5619..bbb8c9469 100644 --- a/tst/Devices/FTMSBike/ftmsbiketestdata.cpp +++ b/tst/Devices/FTMSBike/ftmsbiketestdata.cpp @@ -1,5 +1,9 @@ #include "ftmsbiketestdata.h" +#include "Devices/SnodeBike/snodebiketestdata.h" +#include "Devices/FitPlusBike/fitplusbiketestdata.h" +#include "Devices/StagesBike/stagesbiketestdata.h" + void FTMSBikeTestData::configureExclusions() { this->exclude(new SnodeBike1TestData()); this->exclude(new SnodeBike2TestData()); diff --git a/tst/Devices/FTMSBike/ftmsbiketestdata.h b/tst/Devices/FTMSBike/ftmsbiketestdata.h index 2c23b4244..4ab988841 100644 --- a/tst/Devices/FTMSBike/ftmsbiketestdata.h +++ b/tst/Devices/FTMSBike/ftmsbiketestdata.h @@ -7,12 +7,12 @@ #include "devices/ftmsbike/ftmsbike.h" -#include "Devices/SnodeBike/snodebiketestdata.h" -#include "Devices/FitPlusBike/fitplusbiketestdata.h" -#include "Devices/StagesBike/stagesbiketestdata.h" class FTMSBikeTestData : public BikeTestData { protected: + bike* doCreateInstance(const BikeOptions& options) override { + return new ftmsbike(options.noResistance, options.noHeartService, options.resistanceOffset, options.resistanceGain); + } void configureExclusions() override; FTMSBikeTestData(std::string testName) : BikeTestData(testName) { diff --git a/tst/Devices/FakeBike/fakebiketestdata.h b/tst/Devices/FakeBike/fakebiketestdata.h index 2679adb69..cb13a9ff3 100644 --- a/tst/Devices/FakeBike/fakebiketestdata.h +++ b/tst/Devices/FakeBike/fakebiketestdata.h @@ -9,6 +9,10 @@ class FakeBikeTestData : public BikeTestData { protected: + bike* doCreateInstance(const BikeOptions& options) override { + return new fakebike(options.noResistance, options.noHeartService, options.noVirtualDevice); + } + bool configureSettings(DeviceDiscoveryInfo& info, bool enable) const override { info.fake_bike = enable; return true; diff --git a/tst/Devices/FitPlusBike/fitplusbiketestdata.h b/tst/Devices/FitPlusBike/fitplusbiketestdata.h index 38668f036..266c25d46 100644 --- a/tst/Devices/FitPlusBike/fitplusbiketestdata.h +++ b/tst/Devices/FitPlusBike/fitplusbiketestdata.h @@ -9,6 +9,10 @@ class FitPlusBikeFSTestData : public BikeTestData { protected: + bike* doCreateInstance(const BikeOptions& options) override { + return new fitplusbike(options.noResistance, options.noHeartService, options.resistanceOffset, options.resistanceGain); + } + bool configureSettings(DeviceDiscoveryInfo& info, bool enable) const override { info.fitplus_bike = enable; return true; @@ -27,7 +31,10 @@ class FitPlusBikeFSTestData : public BikeTestData { }; class FitPlusBikeMRKTestData : public BikeTestData { - +protected: + bike* doCreateInstance(const BikeOptions& options) override { + return new fitplusbike(options.noResistance, options.noHeartService, options.resistanceOffset, options.resistanceGain); + } public: FitPlusBikeMRKTestData() : BikeTestData("FitPlus Bike (MRK, no settings)"){ diff --git a/tst/Devices/FlywheelBike/flywheelbiketestdata.h b/tst/Devices/FlywheelBike/flywheelbiketestdata.h index fd049195f..1660ae3d2 100644 --- a/tst/Devices/FlywheelBike/flywheelbiketestdata.h +++ b/tst/Devices/FlywheelBike/flywheelbiketestdata.h @@ -10,6 +10,9 @@ class FlywheelBikeTestData : public BikeTestData { protected: + bike* doCreateInstance(const BikeOptions& options) override { + return new flywheelbike(options.noResistance, options.noHeartService); + } FlywheelBikeTestData(std::string testName) : BikeTestData(testName) { } public: diff --git a/tst/Devices/HorizonGR7Bike/horizongr7biketestdata.h b/tst/Devices/HorizonGR7Bike/horizongr7biketestdata.h index 540ca42b6..f597feb04 100644 --- a/tst/Devices/HorizonGR7Bike/horizongr7biketestdata.h +++ b/tst/Devices/HorizonGR7Bike/horizongr7biketestdata.h @@ -7,7 +7,10 @@ class HorizonGR7BikeTestData : public BikeTestData { - +protected: + bike* doCreateInstance(const BikeOptions& options) override { + return new horizongr7bike(options.noResistance, options.noHeartService, options.resistanceOffset, options.resistanceGain); + } public: HorizonGR7BikeTestData() : BikeTestData("Horizon GR7 Bike") { this->addDeviceName("JFIC", comparison::StartsWithIgnoreCase); diff --git a/tst/Devices/InspireBike/inspirebiketestdata.h b/tst/Devices/InspireBike/inspirebiketestdata.h index b1156f430..cd0060553 100644 --- a/tst/Devices/InspireBike/inspirebiketestdata.h +++ b/tst/Devices/InspireBike/inspirebiketestdata.h @@ -6,7 +6,10 @@ class InspireBikeTestData : public BikeTestData { - +protected: + bike* doCreateInstance(const BikeOptions& options) override { + return new inspirebike(options.noResistance, options.noHeartService); + } public: InspireBikeTestData() : BikeTestData("Inspire Bike") { this->addDeviceName("IC", comparison::StartsWithIgnoreCase, 8); diff --git a/tst/Devices/KeepBike/keepbiketestdata.h b/tst/Devices/KeepBike/keepbiketestdata.h index 22229f184..bb7a77dab 100644 --- a/tst/Devices/KeepBike/keepbiketestdata.h +++ b/tst/Devices/KeepBike/keepbiketestdata.h @@ -8,7 +8,10 @@ class KeepBikeTestData : public BikeTestData { - +protected: + bike* doCreateInstance(const BikeOptions& options) override { + return new keepbike(options.noResistance, options.noHeartService, options.resistanceOffset, options.resistanceGain); + } public: KeepBikeTestData() : BikeTestData("Keep Bike") { this->addDeviceName("KEEP_BIKE_", comparison::StartsWithIgnoreCase); diff --git a/tst/Devices/M3IBike/m3ibiketestdata.h b/tst/Devices/M3IBike/m3ibiketestdata.h index 30d322b4e..f86431395 100644 --- a/tst/Devices/M3IBike/m3ibiketestdata.h +++ b/tst/Devices/M3IBike/m3ibiketestdata.h @@ -11,6 +11,9 @@ class M3IBikeTestData : public BikeTestData { protected: void configureBluetoothDeviceInfos(const QBluetoothDeviceInfo& info, bool enable, std::vector& bluetoothDeviceInfos) const override; + bike* doCreateInstance(const BikeOptions& options) override { + return new m3ibike(options.noResistance, options.noHeartService); + } public: M3IBikeTestData() : BikeTestData("M3I Bike") { this->addDeviceName("M3", comparison::StartsWith); diff --git a/tst/Devices/MCFBike/mcfbiketestdata.h b/tst/Devices/MCFBike/mcfbiketestdata.h index 6ad140307..bd26bf100 100644 --- a/tst/Devices/MCFBike/mcfbiketestdata.h +++ b/tst/Devices/MCFBike/mcfbiketestdata.h @@ -8,7 +8,10 @@ class MCFBikeTestData : public BikeTestData { - +protected: + bike* doCreateInstance(const BikeOptions& options) override { + return new mcfbike(options.noResistance, options.noHeartService, options.resistanceOffset, options.resistanceGain); + } public: MCFBikeTestData() : BikeTestData("MCF Bike") { this->addDeviceName("MCF-", comparison::StartsWithIgnoreCase); diff --git a/tst/Devices/MepanelBike/mepanelbiketestdata.h b/tst/Devices/MepanelBike/mepanelbiketestdata.h index 526773cc5..763633258 100644 --- a/tst/Devices/MepanelBike/mepanelbiketestdata.h +++ b/tst/Devices/MepanelBike/mepanelbiketestdata.h @@ -9,7 +9,10 @@ class MepanelBikeTestData : public BikeTestData { - +protected: + bike* doCreateInstance(const BikeOptions& options) override { + return new mepanelbike(options.noResistance, options.noHeartService, options.resistanceOffset, options.resistanceGain); + } public: MepanelBikeTestData() : BikeTestData("Mepanel Bike") { this->addDeviceName("MEPANEL", comparison::StartsWithIgnoreCase); diff --git a/tst/Devices/NPECableBike/npecablebiketestdata.h b/tst/Devices/NPECableBike/npecablebiketestdata.h index 00911091e..cf4168d4c 100644 --- a/tst/Devices/NPECableBike/npecablebiketestdata.h +++ b/tst/Devices/NPECableBike/npecablebiketestdata.h @@ -8,6 +8,9 @@ class NPECableBikeTestData : public BikeTestData { protected: + bike* doCreateInstance(const BikeOptions& options) override { + return new npecablebike(options.noResistance, options.noHeartService); + } NPECableBikeTestData(std::string testName) : BikeTestData(testName) {} public: deviceType get_expectedDeviceType() const override { return deviceType::NPECableBike; } diff --git a/tst/Devices/NautilusBike/nautilusbiketestdata.h b/tst/Devices/NautilusBike/nautilusbiketestdata.h index ca971c835..f5d376174 100644 --- a/tst/Devices/NautilusBike/nautilusbiketestdata.h +++ b/tst/Devices/NautilusBike/nautilusbiketestdata.h @@ -6,7 +6,10 @@ class NautilusBikeTestData : public BikeTestData { - +protected: + bike* doCreateInstance(const BikeOptions& options) override { + return new nautilusbike(options.noResistance, options.noHeartService, false, options.resistanceOffset, options.resistanceGain); + } public: NautilusBikeTestData(): BikeTestData("Nautilus Bike") { this->addDeviceName("NAUTILUS B", comparison::StartsWithIgnoreCase); diff --git a/tst/Devices/PafersBike/pafersbiketestdata.h b/tst/Devices/PafersBike/pafersbiketestdata.h index fac76b18d..7366dd3fd 100644 --- a/tst/Devices/PafersBike/pafersbiketestdata.h +++ b/tst/Devices/PafersBike/pafersbiketestdata.h @@ -7,6 +7,9 @@ class PafersBikeTestData : public BikeTestData { protected: + bike* doCreateInstance(const BikeOptions& options) override { + return new pafersbike(options.noResistance, options.noHeartService, options.resistanceOffset, options.resistanceGain); + } bool configureSettings(DeviceDiscoveryInfo& info, bool enable) const override { // the treadmill is given priority info.pafers_treadmill = !enable; diff --git a/tst/Devices/ProFormBike/proformbiketestdata.h b/tst/Devices/ProFormBike/proformbiketestdata.h index db8f64eac..39c7186b3 100644 --- a/tst/Devices/ProFormBike/proformbiketestdata.h +++ b/tst/Devices/ProFormBike/proformbiketestdata.h @@ -7,7 +7,10 @@ class ProFormBikeTestData : public BikeTestData { - +protected: + bike* doCreateInstance(const BikeOptions& options) override { + return new proformbike(options.noResistance, options.noHeartService, options.resistanceOffset, options.resistanceGain); + } public: ProFormBikeTestData() : BikeTestData("ProForm Bike") { this->addDeviceName("I_EB", comparison::StartsWith); diff --git a/tst/Devices/ProFormWiFiBike/proformwifibiketestdata.h b/tst/Devices/ProFormWiFiBike/proformwifibiketestdata.h index 6211c167d..07be0fb76 100644 --- a/tst/Devices/ProFormWiFiBike/proformwifibiketestdata.h +++ b/tst/Devices/ProFormWiFiBike/proformwifibiketestdata.h @@ -8,6 +8,10 @@ class ProFormWiFiBikeTestData : public BikeTestData { protected: + bike* doCreateInstance(const BikeOptions& options) override { + return new proformwifibike(options.noResistance, options.noHeartService, options.resistanceOffset, options.resistanceGain); + } + bool configureSettings(DeviceDiscoveryInfo& info, bool enable) const override { info.proformtdf4ip = enable ? this->get_testIP():QString(); return true; diff --git a/tst/Devices/RenphoBike/renphobiketestdata.cpp b/tst/Devices/RenphoBike/renphobiketestdata.cpp index d4960f3a1..be8f2f79d 100644 --- a/tst/Devices/RenphoBike/renphobiketestdata.cpp +++ b/tst/Devices/RenphoBike/renphobiketestdata.cpp @@ -1,4 +1,6 @@ #include "renphobiketestdata.h" +#include "Devices/FitPlusBike/fitplusbiketestdata.h" +#include "Devices/SnodeBike/snodebiketestdata.h" void RenphoBikeTestData::configureExclusions() { this->exclude(new FitPlusBikeFSTestData()); diff --git a/tst/Devices/RenphoBike/renphobiketestdata.h b/tst/Devices/RenphoBike/renphobiketestdata.h index 8bc2254ce..23b61d83f 100644 --- a/tst/Devices/RenphoBike/renphobiketestdata.h +++ b/tst/Devices/RenphoBike/renphobiketestdata.h @@ -1,13 +1,14 @@ #pragma once #include "Devices/Bike/biketestdata.h" -#include "Devices/FitPlusBike/fitplusbiketestdata.h" -#include "Devices/SnodeBike/snodebiketestdata.h" - #include "devices/renphobike/renphobike.h" class RenphoBikeTestData : public BikeTestData { protected: + bike* doCreateInstance(const BikeOptions& options) override { + return new renphobike(options.noResistance, options.noHeartService); + } + RenphoBikeTestData(std::string testName) : BikeTestData(testName) { } diff --git a/tst/Devices/Schwinn170Bike/schwinn170biketestdata.h b/tst/Devices/Schwinn170Bike/schwinn170biketestdata.h index 3d64746ec..4b30ea20d 100644 --- a/tst/Devices/Schwinn170Bike/schwinn170biketestdata.h +++ b/tst/Devices/Schwinn170Bike/schwinn170biketestdata.h @@ -5,7 +5,10 @@ class Schwinn170BikeTestData : public BikeTestData { - +protected: + bike* doCreateInstance(const BikeOptions& options) override { + return new schwinn170bike(options.noResistance, options.noHeartService, options.resistanceOffset, options.resistanceGain); + } public: Schwinn170BikeTestData() : BikeTestData("Schwinn 170 Bike") { diff --git a/tst/Devices/SchwinnIC4Bike/schwinnic4biketestdata.h b/tst/Devices/SchwinnIC4Bike/schwinnic4biketestdata.h index 9dce84056..678e5d348 100644 --- a/tst/Devices/SchwinnIC4Bike/schwinnic4biketestdata.h +++ b/tst/Devices/SchwinnIC4Bike/schwinnic4biketestdata.h @@ -6,7 +6,10 @@ class SchwinnIC4BikeTestData : public BikeTestData { - +protected: + bike* doCreateInstance(const BikeOptions& options) override { + return new schwinnic4bike(options.noResistance, options.noHeartService); + } public: SchwinnIC4BikeTestData() : BikeTestData("Schwinn IC4 Bike") { diff --git a/tst/Devices/SkandikaWiryBike/skandikawirybiketestdata.h b/tst/Devices/SkandikaWiryBike/skandikawirybiketestdata.h index 41ee111ad..81ca608f4 100644 --- a/tst/Devices/SkandikaWiryBike/skandikawirybiketestdata.h +++ b/tst/Devices/SkandikaWiryBike/skandikawirybiketestdata.h @@ -7,7 +7,10 @@ class SkandikaWiryBikeTestData : public BikeTestData { - +protected: + bike* doCreateInstance(const BikeOptions& options) override { + return new skandikawiribike(options.noResistance, options.noHeartService, options.resistanceOffset, options.resistanceGain); + } public: SkandikaWiryBikeTestData() : BikeTestData("Skandika Wiry Bike") { this->addDeviceName("BFCP", comparison::StartsWithIgnoreCase); diff --git a/tst/Devices/SnodeBike/snodebiketestdata.h b/tst/Devices/SnodeBike/snodebiketestdata.h index f504cf141..1b8a11959 100644 --- a/tst/Devices/SnodeBike/snodebiketestdata.h +++ b/tst/Devices/SnodeBike/snodebiketestdata.h @@ -6,6 +6,9 @@ class SnodeBikeTestData : public BikeTestData { protected: + bike* doCreateInstance(const BikeOptions& options) override { + return new snodebike(options.noResistance, options.noHeartService); + } SnodeBikeTestData(std::string testName) : BikeTestData(testName) { } void configureExclusions() override; diff --git a/tst/Devices/SoleBike/solebiketestdata.h b/tst/Devices/SoleBike/solebiketestdata.h index efca101f1..3cac78bc0 100644 --- a/tst/Devices/SoleBike/solebiketestdata.h +++ b/tst/Devices/SoleBike/solebiketestdata.h @@ -7,7 +7,10 @@ class SoleBikeTestData : public BikeTestData { - +protected: + bike* doCreateInstance(const BikeOptions& options) override { + return new solebike(options.noResistance, options.noHeartService, options.resistanceOffset, options.resistanceGain); + } public: SoleBikeTestData() : BikeTestData("Sole Bike") { this->addDeviceName("LCB", comparison::StartsWithIgnoreCase); diff --git a/tst/Devices/SportsPlusBike/sportsplusbiketestdata.h b/tst/Devices/SportsPlusBike/sportsplusbiketestdata.h index 7e3746057..b1d55ebaa 100644 --- a/tst/Devices/SportsPlusBike/sportsplusbiketestdata.h +++ b/tst/Devices/SportsPlusBike/sportsplusbiketestdata.h @@ -7,7 +7,10 @@ class SportsPlusBikeTestData : public BikeTestData { - +protected: + bike* doCreateInstance(const BikeOptions& options) override { + return new sportsplusbike(options.noResistance, options.noHeartService); + } public: SportsPlusBikeTestData() : BikeTestData("Sports Plus Bike") { this->addDeviceName("CARDIOFIT", comparison::StartsWithIgnoreCase); diff --git a/tst/Devices/SportsTechBike/sportstechbiketestdata.h b/tst/Devices/SportsTechBike/sportstechbiketestdata.h index 7632a56eb..a3fd48824 100644 --- a/tst/Devices/SportsTechBike/sportstechbiketestdata.h +++ b/tst/Devices/SportsTechBike/sportstechbiketestdata.h @@ -7,7 +7,10 @@ class SportsTechBikeTestData : public BikeTestData { - +protected: + bike* doCreateInstance(const BikeOptions& options) override { + return new sportstechbike(options.noResistance, options.noHeartService); + } public: SportsTechBikeTestData() : BikeTestData("Sport Tech Bike") { this->addDeviceName("EW-BK", comparison::StartsWithIgnoreCase); diff --git a/tst/Devices/StagesBike/stagesbiketestdata.h b/tst/Devices/StagesBike/stagesbiketestdata.h index 0939c8add..3c4cb6022 100644 --- a/tst/Devices/StagesBike/stagesbiketestdata.h +++ b/tst/Devices/StagesBike/stagesbiketestdata.h @@ -5,6 +5,9 @@ class StagesBikeTestData : public BikeTestData { protected: + bike* doCreateInstance(const BikeOptions& options) override { + return new stagesbike(options.noResistance, options.noHeartService, options.noVirtualDevice); + } StagesBikeTestData(std::string testName): BikeTestData(testName) { } diff --git a/tst/Devices/TacxNeo2/tacxneo2testdata.h b/tst/Devices/TacxNeo2/tacxneo2testdata.h index 129327229..991cabdcc 100644 --- a/tst/Devices/TacxNeo2/tacxneo2testdata.h +++ b/tst/Devices/TacxNeo2/tacxneo2testdata.h @@ -7,7 +7,10 @@ class TacxNeo2TestData : public BikeTestData { - +protected: + bike* doCreateInstance(const BikeOptions& options) override { + return new tacxneo2(options.noResistance, options.noHeartService); + } public: TacxNeo2TestData() : BikeTestData("Tacx Neo 2 Bike") { this->addDeviceName("TACX NEO", comparison::StartsWithIgnoreCase); diff --git a/tst/Devices/TrxAppGateUSBBike/trxappgateusbbiketestdata.h b/tst/Devices/TrxAppGateUSBBike/trxappgateusbbiketestdata.h index aba3940de..0797e90f8 100644 --- a/tst/Devices/TrxAppGateUSBBike/trxappgateusbbiketestdata.h +++ b/tst/Devices/TrxAppGateUSBBike/trxappgateusbbiketestdata.h @@ -6,6 +6,9 @@ class TrxAppGateUSBBikeTestData : public BikeTestData { protected: + bike* doCreateInstance(const BikeOptions& options) override { + return new trxappgateusbbike(options.noResistance, options.noHeartService, options.resistanceOffset, options.resistanceGain); + } TrxAppGateUSBBikeTestData(std::string testName) : BikeTestData(testName) { } diff --git a/tst/Devices/UltrasportBike/ultrasportbiketestdata.h b/tst/Devices/UltrasportBike/ultrasportbiketestdata.h index 762d849d8..c89b57c33 100644 --- a/tst/Devices/UltrasportBike/ultrasportbiketestdata.h +++ b/tst/Devices/UltrasportBike/ultrasportbiketestdata.h @@ -7,7 +7,10 @@ class UltrasportBikeTestData : public BikeTestData { - +protected: + bike* doCreateInstance(const BikeOptions& options) override { + return new ultrasportbike(options.noResistance, options.noHeartService, options.resistanceOffset, options.resistanceGain); + } public: UltrasportBikeTestData() : BikeTestData("Ultrasport Bike") { this->addDeviceName("X-BIKE", comparison::StartsWithIgnoreCase); diff --git a/tst/Devices/WahooKickrSnapBike/wahookickrsnapbiketestdata.h b/tst/Devices/WahooKickrSnapBike/wahookickrsnapbiketestdata.h index c22a8c437..78cd99133 100644 --- a/tst/Devices/WahooKickrSnapBike/wahookickrsnapbiketestdata.h +++ b/tst/Devices/WahooKickrSnapBike/wahookickrsnapbiketestdata.h @@ -7,7 +7,10 @@ class WahooKickrSnapBikeTestData : public BikeTestData { - +protected: + bike* doCreateInstance(const BikeOptions& options) override { + return new wahookickrsnapbike(options.noResistance, options.noHeartService, options.resistanceOffset, options.resistanceGain); + } public: WahooKickrSnapBikeTestData() : BikeTestData("Wahoo Kickr Snap Bike") { this->addDeviceName("KICKR SNAP", comparison::StartsWithIgnoreCase); diff --git a/tst/Devices/YesoulBike/yesoulbiketestdata.h b/tst/Devices/YesoulBike/yesoulbiketestdata.h index a63f35337..e903c3cb0 100644 --- a/tst/Devices/YesoulBike/yesoulbiketestdata.h +++ b/tst/Devices/YesoulBike/yesoulbiketestdata.h @@ -1,13 +1,13 @@ #pragma once - #include "Devices/Bike/biketestdata.h" - #include "devices/yesoulbike/yesoulbike.h" - class YesoulBikeTestData : public BikeTestData { - +protected: + bike* doCreateInstance(const BikeOptions& options) override { + return new yesoulbike(options.noResistance, options.noHeartService, options.resistanceOffset, options.resistanceGain); + } public: YesoulBikeTestData() : BikeTestData("Yesoul Bike") { this->addDeviceName(yesoulbike::bluetoothName, comparison::StartsWith); diff --git a/tst/Devices/biketestsuite.cpp b/tst/Devices/biketestsuite.cpp new file mode 100644 index 000000000..b98e6534a --- /dev/null +++ b/tst/Devices/biketestsuite.cpp @@ -0,0 +1,173 @@ +#include "biketestsuite.h" +#include "ErgInterface/bikeergfunctions.h" + +template +BikeTestSuite::BikeTestSuite() : testSettings("Roberto Viola", "QDomyos-Zwift Testing") {} + +template +void BikeTestSuite::SetUp() { + BikeOptions options; + this->device =this->typeParam.createInstance(options); + this->ergInterface = new bikeergfunctions(this->device); + + this->maxRPM = this->ergInterface->getMaxCadence().value_or(120); + this->minRPM = this->ergInterface->getMinCadence().value_or(1); + this->maxResistance = this->ergInterface->getMaxResistance().value_or(255); + this->minResistance = this->ergInterface->getMinResistance().value_or(0); + +} + +template +void BikeTestSuite::TearDown() { + if(this->device) delete this->device; + if(this->ergInterface) delete this->ergInterface; + this->device = nullptr; + this->ergInterface = nullptr; +} + +template +void BikeTestSuite::test_powerFunctions_minResistance() { + const auto erg = this->ergInterface; + uint16_t p0, p1; + resistance_t r0, r1; + QStringList errors; + QString powerBeyondResistanceLimit = QStringLiteral("Power at C:%1 RPM not bounded at %6 resistance (R:%2, P:%3W), (R:%4, P:%5W)"); + + if(!erg->getMinResistance().has_value()) + { + GTEST_SKIP() << "No minimum resistance defined"; + } + + // traverse the cadence edges checking the power is clipped to the values for the max and min resistance + for(uint32_t cadenceRPM=minRPM; cadenceRPM<=maxRPM; cadenceRPM++) + { + r0 = minResistance; + r1 = minResistance-1; + p0 = erg->getPower(cadenceRPM, r0); + p1 = erg->getPower(cadenceRPM, r1); + + if(p0 != p1) + errors.append(powerBeyondResistanceLimit.arg(cadenceRPM).arg(r0).arg(p0).arg(r1).arg(p1).arg("minimum")); + } + + ASSERT_TRUE(errors.empty()) << errors.join('\n').toStdString(); +} + + +template +void BikeTestSuite::test_powerFunctions_maxResistance() { + const auto erg = this->ergInterface; + uint16_t p0, p1; + resistance_t r0, r1; + QStringList errors; + QString powerBeyondResistanceLimit = QStringLiteral("Power at C:%1 RPM not bounded at %6 resistance (R:%2, P:%3W), (R:%4, P:%5W)"); + + if(!erg->getMaxResistance().has_value()) + { + GTEST_SKIP() << "No maximum resistance defined."; + } + + // traverse the cadence edges checking the power is clipped to the values for the max and min resistance + for(uint32_t cadenceRPM=minRPM; cadenceRPM<=maxRPM; cadenceRPM++) + { + r0 = maxResistance; + r1 = maxResistance+1; + p0 = erg->getPower(cadenceRPM, r0); + p1 = erg->getPower(cadenceRPM, r1); + + if(p0 != p1) + errors.append(powerBeyondResistanceLimit.arg(cadenceRPM).arg(r0).arg(p0).arg(r1).arg(p1).arg("maximum")); + } + + ASSERT_TRUE(errors.empty()) << errors.join('\n').toStdString(); +} + +template +void BikeTestSuite::test_powerFunctions_minCadence() { + const auto erg = this->ergInterface; + uint16_t p0, p1; + QStringList errors; + + if(!erg->getMinCadence().has_value()) + { + GTEST_SKIP() << "No minimum cadence defined."; + } + + // traverse the resistance edge checking the power is clipped to the values for the max and min cadence + + QString powerBeyondCadenceLimit = QStringLiteral("Power at R:%1 not bounded at %6 cadence (C:%2 RPM, P:%3W), (C:%4 RPM, P:%5W)"); + + for(resistance_t r=minResistance; r<=maxResistance; r++) + { + const int32_t c0 = minRPM, c1=minRPM-1; + p0 = erg->getPower(c0, r); + p1 = erg->getPower(c1, r); + + if(p0!=p1) + errors.append(powerBeyondCadenceLimit.arg(r).arg(c0).arg(p0).arg(c1).arg(p1).arg("minimum")); + } + + ASSERT_TRUE(errors.empty()) << errors.join('\n').toStdString(); +} + +template +void BikeTestSuite::test_powerFunctions_maxCadence() { + const auto erg = this->ergInterface; + uint16_t p0, p1; + QStringList errors; + + if(!erg->getMaxCadence().has_value()) + { + GTEST_SKIP() << "No maximum cadence defined"; + } + + // traverse the resistance edge checking the power is clipped to the values for the max and min cadence + + QString powerBeyondCadenceLimit = QStringLiteral("Power at R:%1 not bounded at %6 cadence (C:%2 RPM, P:%3W), (C:%4 RPM, P:%5W)"); + + for(resistance_t r=minResistance; r<=maxResistance; r++) + { + const int32_t c0 = maxRPM, c1=maxRPM+1; + p0 = erg->getPower(c0, r); + p1 = erg->getPower(c1, r); + + if(p0!=p1) + errors.append(powerBeyondCadenceLimit.arg(r).arg(c0).arg(p0).arg(c1).arg(p1).arg("maximum")); + } + + ASSERT_TRUE(errors.empty()) << errors.join('\n').toStdString(); +} + +template +void BikeTestSuite::test_powerFunctions_resistancePowerConversion() { + const auto erg = this->ergInterface; + QStringList errors; + + // test inverses + QString unexpectedResistance=QStringLiteral("P(C:%3, R:%1)=%2 but R(C:%3, P:%2)=%4 and P(C:%3, R:%4)=%5"); + for(uint32_t cadenceRPM=minRPM; cadenceRPM<=maxRPM; cadenceRPM++) + { + uint16_t lastPower=0xFFFF; + for(resistance_t r=minResistance; r<=maxResistance; r++) + { + uint16_t power = erg->getPower(cadenceRPM, r); + + // if this resistance reaches a new power level, check the inverse + if(power!=lastPower) + { + lastPower = power; + resistance_t resistance = erg->getResistance(cadenceRPM, power); + + if(r!=resistance) { + uint16_t newPower = erg->getPower(cadenceRPM, resistance); + + errors.append(unexpectedResistance.arg(r).arg(power).arg(cadenceRPM).arg(resistance).arg(newPower)); + } + + } + + } + } + + ASSERT_TRUE(errors.empty()) << errors.join('\n').toStdString(); +} diff --git a/tst/Devices/biketestsuite.h b/tst/Devices/biketestsuite.h new file mode 100644 index 000000000..c60e5265a --- /dev/null +++ b/tst/Devices/biketestsuite.h @@ -0,0 +1,85 @@ +#pragma once + +#include "gtest/gtest.h" +#include "devices.h" +#include "ErgInterface/erginterface.h" + +#include "Tools/testsettings.h" + +template +class BikeTestSuite : public testing::Test { +private: + bike * device = nullptr; + +protected: + T typeParam; + + uint32_t maxRPM, minRPM; + resistance_t maxResistance, minResistance; + + erginterface * ergInterface = nullptr; + + /** + * @brief Manages the QSettings used during the tests, separate from QSettings stored in the system generally. + */ + TestSettings testSettings; +public: + BikeTestSuite(); + + // Sets up the test fixture. + void SetUp() override; + + // Tears down the test fixture. + virtual void TearDown() override; + + /** + * @brief Test that power doesn't change below the minimum cadence for a constant resistance. + */ + void test_powerFunctions_minCadence(); + + /** + * @brief Test that power doesn't change below the minimum resistance for a constant cadence. + */ + void test_powerFunctions_minResistance(); + + /** + * @brief Test that power doesn't change below the maximum resistance for a constant cadence. + */ + void test_powerFunctions_maxResistance(); + + /** + * @brief Test that power doesn't change above the maximum cadence for a constant resistance. + */ + void test_powerFunctions_maxCadence(); + + /** + * @brief Test that the resistance from power function returns the minimum resistance required to get the same power + * from the power-from-resistance function at the same cadence. + */ + void test_powerFunctions_resistancePowerConversion(); + +}; + + +TYPED_TEST_SUITE(BikeTestSuite, BikeTestDataTypes); + +TYPED_TEST(BikeTestSuite, TestPowerFunctionsMinCadence) { + this->test_powerFunctions_minCadence(); +} + +TYPED_TEST(BikeTestSuite, TestPowerFunctionsMaxCadence) { + this->test_powerFunctions_maxCadence(); +} + +TYPED_TEST(BikeTestSuite, TestPowerFunctionsMinResistance) { + this->test_powerFunctions_minResistance(); +} + +TYPED_TEST(BikeTestSuite, TestPowerFunctionsMaxResistance) { + this->test_powerFunctions_maxResistance(); +} + +TYPED_TEST(BikeTestSuite, TestPowerFunctionsResistancePowerConversion) { + this->test_powerFunctions_resistancePowerConversion(); +} + diff --git a/tst/Devices/devices.h b/tst/Devices/devices.h index a63e73ad4..2836c38b1 100644 --- a/tst/Devices/devices.h +++ b/tst/Devices/devices.h @@ -1,11 +1,9 @@ -#ifndef DEVICES_H -#define DEVICES_H +#pragma once #include #include #include "gtest/gtest.h" -#include "bluetoothdevicetestdata.h" #include "ActivioTreadmill/activiotreadmilltestdata.h" #include "ApexBike/apexbiketestdata.h" #include "BkoolBike/bkoolbiketestdata.h" @@ -199,7 +197,58 @@ ZiproTreadmillTestData, iConceptBikeTestData, iConceptEllipticalTestData>; -#endif +using BikeTestDataTypes = ::testing::Types< +ApexBikeTestData, +BkoolBikeTestData, +CompuTrainerTestData, +CSCBike1TestData, +CSCBike2TestData, +ChronobikeTestData, +DomyosBikeTestData, +EchelonConnectSportBikeTestData, +FTMSBike1TestData, +FTMSBike2TestData, +FTMSBike3TestData, +FakeBikeTestData, +FitPlusBikeFSTestData, +FitPlusBikeMRKTestData, +FlywheelBike1TestData, +FlywheelBike2TestData, +HorizonGR7BikeTestData, +InspireBikeTestData, +KeepBikeTestData, +M3IBikeTestData, +MCFBikeTestData, +MepanelBikeTestData, +NPECableBike1TestData, +NPECableBike2TestData, +NautilusBikeTestData, +PafersBikeTestData, +ProFormBikeTestData, +ProFormWiFiBikeTestData, +RenphoBike1TestData, +RenphoBike2TestData, +Schwinn170BikeTestData, +SchwinnIC4BikeTestData, +SkandikaWiryBikeTestData, +SnodeBike1TestData, +SnodeBike2TestData, +SoleBikeTestData, +SportsPlusBikeTestData, +SportsTechBikeTestData, +StagesBike1TestData, +StagesBike2TestData, +TacxNeo2TestData, +TrxAppGateUSBBike1TestData, +TrxAppGateUSBBike2TestData, +UltrasportBikeTestData, +WahooKickrSnapBikeTestData, +YesoulBikeTestData, +iConceptBikeTestData>; + + + + diff --git a/tst/Devices/iConceptBike/iconceptbiketestdata.h b/tst/Devices/iConceptBike/iconceptbiketestdata.h index 164c5d56f..1dc2199ba 100644 --- a/tst/Devices/iConceptBike/iconceptbiketestdata.h +++ b/tst/Devices/iConceptBike/iconceptbiketestdata.h @@ -5,7 +5,12 @@ class iConceptBikeTestData : public BikeTestData { -void configureSettings(const DeviceDiscoveryInfo &info, bool enable, +protected: + bike* doCreateInstance(const BikeOptions& options) override { + return new iconceptbike(); + } + + void configureSettings(const DeviceDiscoveryInfo &info, bool enable, std::vector &configurations) const override { DeviceDiscoveryInfo config(info); diff --git a/tst/ErgInterface/bikeergfunctions.cpp b/tst/ErgInterface/bikeergfunctions.cpp new file mode 100644 index 000000000..eeef02cfb --- /dev/null +++ b/tst/ErgInterface/bikeergfunctions.cpp @@ -0,0 +1,30 @@ +#include "bikeergfunctions.h" + +void bikeergfunctions::setCadence(int32_t cadence) { this->device->cadenceSensor(cadence); } + +bikeergfunctions::bikeergfunctions(bike *device) : device(device) {} + +std::optional bikeergfunctions::getMaxCadence() const { return std::optional{};} + +std::optional bikeergfunctions::getMinCadence() const { return 0; } + +std::optional bikeergfunctions::getMaxResistance() const { return this->device->maxResistance(); } + +std::optional bikeergfunctions::getMinResistance() const { return 0; } + +double bikeergfunctions::getPower(const int32_t cadence, resistance_t resistance) { + auto originalCadence = this->device->currentCadence().value(); + + this->setCadence(cadence); + auto result = this->device->powerFromResistanceRequest(resistance); + this->setCadence(originalCadence); + return result; +} + +int32_t bikeergfunctions::getResistance(const int32_t cadence, const double power) { + auto originalCadence = this->device->currentCadence().value(); + this->setCadence(cadence); + auto result = this->device->resistanceFromPowerRequest(power); + this->setCadence(originalCadence); + return result; +} diff --git a/tst/ErgInterface/bikeergfunctions.h b/tst/ErgInterface/bikeergfunctions.h new file mode 100644 index 000000000..de31f6834 --- /dev/null +++ b/tst/ErgInterface/bikeergfunctions.h @@ -0,0 +1,29 @@ +#pragma once + +#include "erginterface.h" +#include "bike.h" + +class bikeergfunctions : public virtual erginterface { + protected: + bike* device; + + void setCadence(int32_t cadence); +public: + bikeergfunctions(bike *device); + + + std::optional getMaxCadence() const override; + + std::optional getMinCadence() const override; + + std::optional getMaxResistance() const override; + + std::optional getMinResistance() const override; + + + double getPower(const int32_t cadence, const resistance_t resistance) override; + + + int32_t getResistance(const int32_t cadence, const double power) override; + +}; diff --git a/tst/ErgInterface/erginterface.h b/tst/ErgInterface/erginterface.h new file mode 100644 index 000000000..a60fd9e34 --- /dev/null +++ b/tst/ErgInterface/erginterface.h @@ -0,0 +1,60 @@ +#pragma once + +#include +#include "definitions.h" + +/** + * @brief An interface for power calculation functions + */ +class erginterface { + protected: + erginterface() {} + erginterface(const erginterface&) {} + public: + /** + * @brief The maximum cadence the object understands. + * @return + */ + virtual std::optional getMaxCadence() const = 0; + + /** + * @brief The minimum cadence the object understands. + * @return + */ + virtual std::optional getMinCadence() const = 0; + + /** + * @brief The maximum resistance the device accepts. + * @return + */ + virtual std::optional getMaxResistance() const = 0; + + /** + * @brief The minimum resistance level. + * @return + */ + virtual std::optional getMinResistance() const = 0; + + + /** + * @brief Gets the power in watts for the given cadence and resistance level. + * @param cadence The cadence in a unit appropriate for the device, e.g. revolutions/strides/strokes per minute. + * @param resistance The resistance level. + * @return + */ + virtual double getPower(const int32_t cadence, const resistance_t resistance) = 0; + + + /** + * @brief Gets the resistance required to acheive the specified power in watts at the specified cadence. + * @param cadence The cadence in a unit appropriate for the device, e.g. revolutions/strides/strokes per minute. + * @param power The power in watts to acheive. + * @return + */ + virtual int32_t getResistance(const int32_t cadence, const double power) = 0; + + /** + * @brief Destructor + */ + virtual ~erginterface() = default; +}; diff --git a/tst/main.cpp b/tst/main.cpp index 372fee8a4..a5e807336 100644 --- a/tst/main.cpp +++ b/tst/main.cpp @@ -1,8 +1,19 @@ - #include +#include +#include + +// https://forum.qt.io/topic/84229/is-there-a-canonical-way-to-set-up-qapplication-and-google-test-together/2 int main(int argc, char *argv[]) { - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); + QCoreApplication app{argc, argv}; + + QTimer::singleShot(0, [&]() + { + ::testing::InitGoogleTest(&argc, argv); + auto testResult = RUN_ALL_TESTS(); + app.exit(testResult); + }); + + return app.exec(); } diff --git a/tst/qdomyos-zwift-tests.pro b/tst/qdomyos-zwift-tests.pro index 7faaa2e74..84c8f4839 100644 --- a/tst/qdomyos-zwift-tests.pro +++ b/tst/qdomyos-zwift-tests.pro @@ -5,7 +5,7 @@ include(gtest_dependency.pri) TEMPLATE = app -CONFIG += console c++11 +CONFIG += console c++17 CONFIG -= app_bundle CONFIG += thread CONFIG += androidextras @@ -19,10 +19,12 @@ SOURCES += \ Devices/SnodeBike/snodebiketestdata.cpp \ Devices/StagesBike/stagesbiketestdata.cpp \ Devices/TrxAppGateUSBTreadmill/trxappgateusbtreadmilltestdata.cpp \ + Devices/biketestsuite.cpp \ Devices/bluetoothdevicetestdata.cpp \ Devices/bluetoothdevicetestsuite.cpp \ Devices/bluetoothsignalreceiver.cpp \ Devices/devicediscoveryinfo.cpp \ + ErgInterface/bikeergfunctions.cpp \ ToolTests/testsettingstestsuite.cpp \ Tools/testsettings.cpp \ main.cpp @@ -130,6 +132,7 @@ HEADERS += \ Devices/WahooKickrSnapBike/wahookickrsnapbiketestdata.h \ Devices/YesoulBike/yesoulbiketestdata.h \ Devices/ZiproTreadmill/ziprotreadmilltestdata.h \ + Devices/biketestsuite.h \ Devices/bluetoothdevicetestdata.h \ Devices/bluetoothdevicetestsuite.h \ Devices/bluetoothsignalreceiver.h \ @@ -139,5 +142,7 @@ HEADERS += \ Devices/iConceptElliptical/iconceptellipticaltestdata.h \ Devices/YpooElliptical/ypooellipticaltestdata.h \ Devices/TrxAppGateUsbElliptical/trxappgateusbellipticaltestdata.h \ + ErgInterface/bikeergfunctions.h \ + ErgInterface/erginterface.h \ ToolTests/testsettingstestsuite.h \ Tools/testsettings.h From 15d27532701fcfa9efb1cf8e1307fbf4c1cedf70 Mon Sep 17 00:00:00 2001 From: David Mason Date: Fri, 1 Mar 2024 23:31:57 +0000 Subject: [PATCH 02/13] #2174 restrict the samples when exploring the boundaries of the power table --- tst/Devices/biketestsuite.cpp | 38 ++++++++++++++++++++++++++++++----- tst/Devices/biketestsuite.h | 20 ++++++++++++++++++ 2 files changed, 53 insertions(+), 5 deletions(-) diff --git a/tst/Devices/biketestsuite.cpp b/tst/Devices/biketestsuite.cpp index b98e6534a..1dca88e1e 100644 --- a/tst/Devices/biketestsuite.cpp +++ b/tst/Devices/biketestsuite.cpp @@ -1,6 +1,16 @@ #include "biketestsuite.h" #include "ErgInterface/bikeergfunctions.h" +template +QList BikeTestSuite::getResistanceSamples() { + return this->getSamples(this->minResistance, this->maxResistance); +} + +template +QList BikeTestSuite::getCadenceSamples() { + return this->getSamples(this->minRPM, this->maxRPM); +} + template BikeTestSuite::BikeTestSuite() : testSettings("Roberto Viola", "QDomyos-Zwift Testing") {} @@ -39,7 +49,7 @@ void BikeTestSuite::test_powerFunctions_minResistance() { } // traverse the cadence edges checking the power is clipped to the values for the max and min resistance - for(uint32_t cadenceRPM=minRPM; cadenceRPM<=maxRPM; cadenceRPM++) + for( uint32_t cadenceRPM : this->getCadenceSamples()) { r0 = minResistance; r1 = minResistance-1; @@ -68,7 +78,7 @@ void BikeTestSuite::test_powerFunctions_maxResistance() { } // traverse the cadence edges checking the power is clipped to the values for the max and min resistance - for(uint32_t cadenceRPM=minRPM; cadenceRPM<=maxRPM; cadenceRPM++) + for(uint16_t cadenceRPM : this->getCadenceSamples()) { r0 = maxResistance; r1 = maxResistance+1; @@ -97,7 +107,7 @@ void BikeTestSuite::test_powerFunctions_minCadence() { QString powerBeyondCadenceLimit = QStringLiteral("Power at R:%1 not bounded at %6 cadence (C:%2 RPM, P:%3W), (C:%4 RPM, P:%5W)"); - for(resistance_t r=minResistance; r<=maxResistance; r++) + for( resistance_t r : this->getResistanceSamples()) { const int32_t c0 = minRPM, c1=minRPM-1; p0 = erg->getPower(c0, r); @@ -125,7 +135,7 @@ void BikeTestSuite::test_powerFunctions_maxCadence() { QString powerBeyondCadenceLimit = QStringLiteral("Power at R:%1 not bounded at %6 cadence (C:%2 RPM, P:%3W), (C:%4 RPM, P:%5W)"); - for(resistance_t r=minResistance; r<=maxResistance; r++) + for( resistance_t r : this->getResistanceSamples()) { const int32_t c0 = maxRPM, c1=maxRPM+1; p0 = erg->getPower(c0, r); @@ -145,7 +155,8 @@ void BikeTestSuite::test_powerFunctions_resistancePowerConversion() { // test inverses QString unexpectedResistance=QStringLiteral("P(C:%3, R:%1)=%2 but R(C:%3, P:%2)=%4 and P(C:%3, R:%4)=%5"); - for(uint32_t cadenceRPM=minRPM; cadenceRPM<=maxRPM; cadenceRPM++) + //for(uint32_t cadenceRPM=minRPM; cadenceRPM<=maxRPM; cadenceRPM++) + for(uint16_t cadenceRPM : this->getCadenceSamples()) { uint16_t lastPower=0xFFFF; for(resistance_t r=minResistance; r<=maxResistance; r++) @@ -171,3 +182,20 @@ void BikeTestSuite::test_powerFunctions_resistancePowerConversion() { ASSERT_TRUE(errors.empty()) << errors.join('\n').toStdString(); } + +template +template +QList BikeTestSuite::getSamples(const T0 min, const T0 max) { + QList result; + T0 d = max-min; + T0 inc = d/10; + + if(inc<1) inc = 1; + + for(T0 v=min; v<=max; v+=inc) + result.append(v); + if(result.last()!=max) + result.append(max); + + return result; +} diff --git a/tst/Devices/biketestsuite.h b/tst/Devices/biketestsuite.h index c60e5265a..bcdd900d9 100644 --- a/tst/Devices/biketestsuite.h +++ b/tst/Devices/biketestsuite.h @@ -23,6 +23,26 @@ class BikeTestSuite : public testing::Test { * @brief Manages the QSettings used during the tests, separate from QSettings stored in the system generally. */ TestSettings testSettings; + + /** + * @brief Gets a subset of the range for testing samples. Increment varies depending on delta. + * @return A QList containing min, max and some, or sometimes all values in between. + */ + template + QList getSamples(const T0 min, const T0 max); + + /** + * @brief Determines from provided or estimated minimum and maximum resistance, which values to test, to avoid testing all. + * @return + */ + virtual QList getResistanceSamples(); + + /** + * @brief Determines from provided or estimated minimum and maximum cadence, which values to test, to avoid testing all. + * @return + */ + virtual QList getCadenceSamples(); + public: BikeTestSuite(); From c74fe53ffbfaf103c4d7be5a319352de6b6879a0 Mon Sep 17 00:00:00 2001 From: David Mason Date: Thu, 7 Mar 2024 22:03:01 +0000 Subject: [PATCH 03/13] #2174 moved erg test functionality into the new Erg folder from other PR --- tst/Devices/biketestsuite.cpp | 2 +- tst/Devices/biketestsuite.h | 2 +- tst/{ErgInterface => Erg}/bikeergfunctions.cpp | 0 tst/{ErgInterface => Erg}/bikeergfunctions.h | 0 tst/{ErgInterface => Erg}/erginterface.h | 0 tst/qdomyos-zwift-tests.pro | 6 +++--- 6 files changed, 5 insertions(+), 5 deletions(-) rename tst/{ErgInterface => Erg}/bikeergfunctions.cpp (100%) rename tst/{ErgInterface => Erg}/bikeergfunctions.h (100%) rename tst/{ErgInterface => Erg}/erginterface.h (100%) diff --git a/tst/Devices/biketestsuite.cpp b/tst/Devices/biketestsuite.cpp index 1dca88e1e..247bbfefe 100644 --- a/tst/Devices/biketestsuite.cpp +++ b/tst/Devices/biketestsuite.cpp @@ -1,5 +1,5 @@ #include "biketestsuite.h" -#include "ErgInterface/bikeergfunctions.h" +#include "Erg/bikeergfunctions.h" template QList BikeTestSuite::getResistanceSamples() { diff --git a/tst/Devices/biketestsuite.h b/tst/Devices/biketestsuite.h index bcdd900d9..424d37740 100644 --- a/tst/Devices/biketestsuite.h +++ b/tst/Devices/biketestsuite.h @@ -2,7 +2,7 @@ #include "gtest/gtest.h" #include "devices.h" -#include "ErgInterface/erginterface.h" +#include "Erg/erginterface.h" #include "Tools/testsettings.h" diff --git a/tst/ErgInterface/bikeergfunctions.cpp b/tst/Erg/bikeergfunctions.cpp similarity index 100% rename from tst/ErgInterface/bikeergfunctions.cpp rename to tst/Erg/bikeergfunctions.cpp diff --git a/tst/ErgInterface/bikeergfunctions.h b/tst/Erg/bikeergfunctions.h similarity index 100% rename from tst/ErgInterface/bikeergfunctions.h rename to tst/Erg/bikeergfunctions.h diff --git a/tst/ErgInterface/erginterface.h b/tst/Erg/erginterface.h similarity index 100% rename from tst/ErgInterface/erginterface.h rename to tst/Erg/erginterface.h diff --git a/tst/qdomyos-zwift-tests.pro b/tst/qdomyos-zwift-tests.pro index 8cfa7c39d..8cc125c67 100644 --- a/tst/qdomyos-zwift-tests.pro +++ b/tst/qdomyos-zwift-tests.pro @@ -24,7 +24,7 @@ SOURCES += \ Devices/bluetoothdevicetestsuite.cpp \ Devices/bluetoothsignalreceiver.cpp \ Devices/devicediscoveryinfo.cpp \ - ErgInterface/bikeergfunctions.cpp \ + Erg/bikeergfunctions.cpp \ Erg/ergtabletestsuite.cpp \ ToolTests/testsettingstestsuite.cpp \ Tools/testsettings.cpp \ @@ -143,8 +143,8 @@ HEADERS += \ Devices/iConceptElliptical/iconceptellipticaltestdata.h \ Devices/YpooElliptical/ypooellipticaltestdata.h \ Devices/TrxAppGateUsbElliptical/trxappgateusbellipticaltestdata.h \ - ErgInterface/bikeergfunctions.h \ - ErgInterface/erginterface.h \ + Erg/bikeergfunctions.h \ + Erg/erginterface.h \ Erg/ergtabletestsuite.h \ ToolTests/testsettingstestsuite.h \ Tools/testsettings.h From e335ac24f994726eaee93ee869fcbc285eb9f364 Mon Sep 17 00:00:00 2001 From: David Mason Date: Mon, 25 Mar 2024 23:46:12 +0000 Subject: [PATCH 04/13] #2174 added minmax type and introduced minimum and maximum resistance for bikes. Move some power-related functionality up the class heirarchy --- src/devices/apexbike/apexbike.cpp | 5 +- src/devices/apexbike/apexbike.h | 4 +- src/devices/bike.cpp | 51 ++++++++++++++++++- src/devices/bike.h | 2 + src/devices/bkoolbike/bkoolbike.cpp | 11 ---- src/devices/bkoolbike/bkoolbike.h | 6 +-- src/devices/bluetooth.cpp | 2 +- src/devices/bluetoothdevice.cpp | 1 - src/devices/bluetoothdevice.h | 13 ++++- src/devices/chronobike/chronobike.cpp | 6 +-- src/devices/chronobike/chronobike.h | 2 + .../computrainerbike/computrainerbike.cpp | 28 +--------- .../computrainerbike/computrainerbike.h | 7 +-- src/devices/cscbike/cscbike.cpp | 6 +-- src/devices/cscbike/cscbike.h | 1 + src/devices/domyosbike/domyosbike.cpp | 16 +++--- src/devices/domyosbike/domyosbike.h | 4 +- .../echelonconnectsport.cpp | 22 ++++---- .../echelonconnectsport/echelonconnectsport.h | 3 +- src/devices/fakebike/fakebike.cpp | 12 +++-- src/devices/fakebike/fakebike.h | 2 +- src/devices/fitplusbike/fitplusbike.cpp | 22 ++++---- src/devices/fitplusbike/fitplusbike.h | 4 +- src/devices/flywheelbike/flywheelbike.cpp | 6 +-- src/devices/flywheelbike/flywheelbike.h | 2 + src/devices/ftmsbike/ftmsbike.cpp | 24 ++------- src/devices/ftmsbike/ftmsbike.h | 7 ++- src/devices/horizongr7bike/horizongr7bike.cpp | 7 +-- src/devices/horizongr7bike/horizongr7bike.h | 4 +- src/devices/iconceptbike/iconceptbike.cpp | 7 +-- src/devices/iconceptbike/iconceptbike.h | 2 + src/devices/inspirebike/inspirebike.cpp | 8 +-- src/devices/inspirebike/inspirebike.h | 4 +- src/devices/keepbike/keepbike.cpp | 16 +----- src/devices/keepbike/keepbike.h | 7 ++- src/devices/mcfbike/mcfbike.cpp | 34 +------------ src/devices/mcfbike/mcfbike.h | 10 ++-- src/devices/mepanelbike/mepanelbike.cpp | 5 +- src/devices/mepanelbike/mepanelbike.h | 2 +- src/devices/nautilusbike/nautilusbike.cpp | 19 ++++--- src/devices/nautilusbike/nautilusbike.h | 3 +- .../nordictrackifitadbbike.cpp | 17 +------ .../nordictrackifitadbbike.h | 7 +-- src/devices/npecablebike/npecablebike.cpp | 6 +-- src/devices/npecablebike/npecablebike.h | 2 +- src/devices/pafersbike/pafersbike.cpp | 33 +----------- src/devices/pafersbike/pafersbike.h | 10 ++-- src/devices/proformbike/proformbike.cpp | 51 +++++-------------- src/devices/proformbike/proformbike.h | 8 +-- .../proformtelnetbike/proformtelnetbike.cpp | 26 +--------- .../proformtelnetbike/proformtelnetbike.h | 8 ++- .../proformwifibike/proformwifibike.cpp | 27 +--------- src/devices/proformwifibike/proformwifibike.h | 5 +- src/devices/renphobike/renphobike.cpp | 7 +-- src/devices/renphobike/renphobike.h | 3 +- src/devices/rower.h | 6 ++- src/devices/schwinn170bike/schwinn170bike.cpp | 6 +-- src/devices/schwinn170bike/schwinn170bike.h | 3 +- src/devices/schwinnic4bike/schwinnic4bike.cpp | 6 +-- src/devices/schwinnic4bike/schwinnic4bike.h | 4 +- .../skandikawiribike/skandikawiribike.cpp | 6 +-- .../skandikawiribike/skandikawiribike.h | 1 + src/devices/smartspin2k/smartspin2k.cpp | 9 +--- src/devices/smartspin2k/smartspin2k.h | 4 +- src/devices/snodebike/snodebike.cpp | 6 +-- src/devices/snodebike/snodebike.h | 1 + src/devices/solebike/solebike.cpp | 16 +----- src/devices/solebike/solebike.h | 6 +-- src/devices/sportsplusbike/sportsplusbike.cpp | 11 ++-- src/devices/sportsplusbike/sportsplusbike.h | 4 +- src/devices/sportstechbike/sportstechbike.cpp | 25 +-------- src/devices/sportstechbike/sportstechbike.h | 4 +- src/devices/stagesbike/stagesbike.cpp | 6 +-- src/devices/stagesbike/stagesbike.h | 2 +- src/devices/tacxneo2/tacxneo2.cpp | 12 ----- src/devices/tacxneo2/tacxneo2.h | 7 ++- .../trxappgateusbbike/trxappgateusbbike.cpp | 30 +---------- .../trxappgateusbbike/trxappgateusbbike.h | 5 +- src/devices/ultrasportbike/ultrasportbike.cpp | 16 +----- src/devices/ultrasportbike/ultrasportbike.h | 7 ++- .../wahookickrsnapbike/wahookickrsnapbike.cpp | 8 +-- .../wahookickrsnapbike/wahookickrsnapbike.h | 2 +- src/devices/yesoulbike/yesoulbike.cpp | 5 +- src/devices/yesoulbike/yesoulbike.h | 2 + src/minmax.cpp | 23 +++++++++ src/minmax.h | 19 +++++++ src/qdomyos-zwift.pri | 2 + tst/Erg/bikeergfunctions.cpp | 4 +- 88 files changed, 296 insertions(+), 579 deletions(-) create mode 100644 src/minmax.cpp create mode 100644 src/minmax.h diff --git a/src/devices/apexbike/apexbike.cpp b/src/devices/apexbike/apexbike.cpp index b7ab04ff6..d8bb3a095 100644 --- a/src/devices/apexbike/apexbike.cpp +++ b/src/devices/apexbike/apexbike.cpp @@ -97,10 +97,7 @@ void apexbike::update() { } if (requestResistance != -1) { - if (requestResistance > max_resistance) - requestResistance = max_resistance; - else if (requestResistance <= 0) - requestResistance = 1; + requestResistance = this->resistanceLimits().clip(requestResistance); if (requestResistance != currentResistance().value()) { qDebug() << QStringLiteral("writing resistance ") + QString::number(requestResistance); diff --git a/src/devices/apexbike/apexbike.h b/src/devices/apexbike/apexbike.h index 88d90843d..4f0fafa1a 100644 --- a/src/devices/apexbike/apexbike.h +++ b/src/devices/apexbike/apexbike.h @@ -38,8 +38,10 @@ class apexbike : public bike { apexbike(bool noWriteResistance, bool noHeartService, uint8_t bikeResistanceOffset, double bikeResistanceGain); bool connected() override; + minmax resistanceLimits() override {return minmax(1,32);} + private: - const resistance_t max_resistance = 32; + void btinit(); void writeCharacteristic(uint8_t *data, uint8_t data_len, const QString &info, bool disable_log = false, bool wait_for_response = false); diff --git a/src/devices/bike.cpp b/src/devices/bike.cpp index 69872c165..8523a08e7 100644 --- a/src/devices/bike.cpp +++ b/src/devices/bike.cpp @@ -41,10 +41,20 @@ void bike::changeInclination(double grade, double percentage) { // originally made for renphobike, but i guess it could be very generic uint16_t bike::powerFromResistanceRequest(resistance_t requestResistance) { + auto minMaxR = this->resistanceLimits(); + if(requestResistance<=minMaxR.min()) + return 0; + // this bike has resistance level to N.m so the formula is Power (kW) = Torque (N.m) x Speed (RPM) / 9.5488 double cadence = RequestedCadence.value(); if (cadence <= 0) cadence = Cadence.value(); + + if(cadence <= 0) + return 0; + + requestResistance = minMaxR.clip(requestResistance); + return (requestResistance * cadence) / 9.5488; } @@ -103,8 +113,45 @@ uint8_t bike::fanSpeed() { return FanSpeed; } bool bike::connected() { return false; } uint16_t bike::watts() { return 0; } metric bike::pelotonResistance() { return m_pelotonResistance; } -resistance_t bike::pelotonToBikeResistance(int pelotonResistance) { return pelotonResistance; } -resistance_t bike::resistanceFromPowerRequest(uint16_t power) { return power / 10; } // in order to have something + +resistance_t bike::pelotonToBikeResistance(int pelotonResistance) { + + auto minMaxR = this->resistanceLimits(); + + for (resistance_t i = minMaxR.min(); i < minMaxR.max(); i++) { + if (bikeResistanceToPeloton(i) <= pelotonResistance && bikeResistanceToPeloton(i + 1) >= pelotonResistance) { + return i; + } + } + if (pelotonResistance < bikeResistanceToPeloton(minMaxR.min())) + return minMaxR.min(); + else + return minMaxR.max(); +} +resistance_t bike::resistanceFromPowerRequest(uint16_t power) { + qDebug() << QStringLiteral("resistanceFromPowerRequest") << Cadence.value(); + + QSettings settings; + + double watt_gain = settings.value(QZSettings::watt_gain, QZSettings::default_watt_gain).toDouble(); + double watt_offset = settings.value(QZSettings::watt_offset, QZSettings::default_watt_offset).toDouble(); + + auto minMaxR = this->resistanceLimits(); + + for (resistance_t i = minMaxR.min(); i < minMaxR.max(); i++) { + if (((wattsFromResistance(i) * watt_gain) + watt_offset) <= power && + ((wattsFromResistance(i + 1) * watt_gain) + watt_offset) >= power) { + qDebug() << QStringLiteral("resistanceFromPowerRequest") + << ((wattsFromResistance(i) * watt_gain) + watt_offset) + << ((wattsFromResistance(i + 1) * watt_gain) + watt_offset) << power; + return i; + } + } + if (power < ((wattsFromResistance(minMaxR.min()) * watt_gain) + watt_offset)) + return minMaxR.min(); + else + return minMaxR.max(); +} // in order to have something void bike::cadenceSensor(uint8_t cadence) { Cadence.setValue(cadence); } void bike::powerSensor(uint16_t power) { m_watt.setValue(power, false); } diff --git a/src/devices/bike.h b/src/devices/bike.h index 4f70e0ac5..2fde948e0 100644 --- a/src/devices/bike.h +++ b/src/devices/bike.h @@ -25,7 +25,9 @@ class bike : public bluetoothdevice { bool connected() override; virtual uint16_t watts(); virtual resistance_t pelotonToBikeResistance(int pelotonResistance); + virtual double bikeResistanceToPeloton(double resistance) { return resistance; } virtual resistance_t resistanceFromPowerRequest(uint16_t power); + virtual uint16_t wattsFromResistance(double resistance) { return this->powerFromResistanceRequest(resistance); } virtual uint16_t powerFromResistanceRequest(resistance_t requestResistance); virtual bool ergManagedBySS2K() { return false; } bluetoothdevice::BLUETOOTH_TYPE deviceType() override; diff --git a/src/devices/bkoolbike/bkoolbike.cpp b/src/devices/bkoolbike/bkoolbike.cpp index 9cf2896e6..33a15f9e7 100644 --- a/src/devices/bkoolbike/bkoolbike.cpp +++ b/src/devices/bkoolbike/bkoolbike.cpp @@ -732,17 +732,6 @@ void bkoolbike::controllerStateChanged(QLowEnergyController::ControllerState sta } } -resistance_t bkoolbike::pelotonToBikeResistance(int pelotonResistance) { - for (resistance_t i = 0; i < max_resistance; i++) { - if (bikeResistanceToPeloton(i) <= pelotonResistance && bikeResistanceToPeloton(i + 1) >= pelotonResistance) { - return i; - } - } - if (pelotonResistance < bikeResistanceToPeloton(1)) - return 0; - else - return max_resistance; -} double bkoolbike::bikeResistanceToPeloton(double resistance) { QSettings settings; diff --git a/src/devices/bkoolbike/bkoolbike.h b/src/devices/bkoolbike/bkoolbike.h index 8e1732bcb..c9f25ea8c 100644 --- a/src/devices/bkoolbike/bkoolbike.h +++ b/src/devices/bkoolbike/bkoolbike.h @@ -38,20 +38,18 @@ class bkoolbike : public bike { bkoolbike(bool noWriteResistance, bool noHeartService); void changePower(int32_t power) override; bool connected() override; - resistance_t pelotonToBikeResistance(int pelotonResistance); + minmax resistanceLimits() override {return minmax(1,100);} private: void writeCharacteristic(uint8_t *data, uint8_t data_len, const QString &info, bool disable_log = false, bool wait_for_response = false); void startDiscover(); void forceInclination(double inclination); uint16_t watts() override; - double bikeResistanceToPeloton(double resistance); + double bikeResistanceToPeloton(double resistance) override; QTimer *refresh; - const int max_resistance = 100; - QList gattCommunicationChannelService; QLowEnergyCharacteristic gattWriteCharControlPointId; QLowEnergyCharacteristic gattWriteCharCustomId; diff --git a/src/devices/bluetooth.cpp b/src/devices/bluetooth.cpp index 1b3b711f5..92d9cab06 100644 --- a/src/devices/bluetooth.cpp +++ b/src/devices/bluetooth.cpp @@ -2291,7 +2291,7 @@ void bluetooth::connectedAndDiscovered() { #else settings.setValue(QZSettings::ftms_accessory_address, b.deviceUuid().toString()); #endif - ftmsAccessory = new smartspin2k(false, false, this->device()->maxResistance(), (bike *)this->device()); + ftmsAccessory = new smartspin2k(false, false, this->device()->resistanceLimits().max(), (bike *)this->device()); // connect(heartRateBelt, SIGNAL(disconnected()), this, SLOT(restart())); connect(ftmsAccessory, &smartspin2k::debug, this, &bluetooth::debug); diff --git a/src/devices/bluetoothdevice.cpp b/src/devices/bluetoothdevice.cpp index fbb9a0878..007ef14df 100644 --- a/src/devices/bluetoothdevice.cpp +++ b/src/devices/bluetoothdevice.cpp @@ -353,7 +353,6 @@ QStringList bluetoothdevice::metrics() { return r; } -resistance_t bluetoothdevice::maxResistance() { return 100; } uint8_t bluetoothdevice::metrics_override_heartrate() { diff --git a/src/devices/bluetoothdevice.h b/src/devices/bluetoothdevice.h index 9222c55aa..94b3f6ef0 100644 --- a/src/devices/bluetoothdevice.h +++ b/src/devices/bluetoothdevice.h @@ -2,6 +2,7 @@ #define BLUETOOTHDEVICE_H #include "definitions.h" +#include "minmax.h" #include "metric.h" #include "qzsettings.h" @@ -420,10 +421,20 @@ class bluetoothdevice : public QObject { */ virtual uint8_t metrics_override_heartrate(); + /** + * @brief Overridden in subclasses to specify the range of resistance levels supported by the device. + */ + virtual minmax resistanceLimits() { return minmax(0,100); } + /** * @brief Overridden in subclasses to specify the maximum resistance level supported by the device. */ - virtual resistance_t maxResistance(); + // virtual resistance_t maxResistance() { return 100; } + + /** + * @brief Overridden in subclasses to specify the minimum resistance level supported by the device. + */ + // virtual resistance_t minResistance() { return 0; } public Q_SLOTS: virtual void start(); diff --git a/src/devices/chronobike/chronobike.cpp b/src/devices/chronobike/chronobike.cpp index f9834c893..9e89f3217 100644 --- a/src/devices/chronobike/chronobike.cpp +++ b/src/devices/chronobike/chronobike.cpp @@ -93,11 +93,7 @@ void chronobike::update() { } if (requestResistance != -1) { - if (requestResistance > 15) { - requestResistance = 15; - } else if (requestResistance == 0) { - requestResistance = 1; - } + requestResistance = this->resistanceLimits().clip(requestResistance); if (requestResistance != currentResistance().value()) { emit debug(QStringLiteral("writing resistance ") + QString::number(requestResistance)); diff --git a/src/devices/chronobike/chronobike.h b/src/devices/chronobike/chronobike.h index 88acbdb2a..afdd99495 100644 --- a/src/devices/chronobike/chronobike.h +++ b/src/devices/chronobike/chronobike.h @@ -38,6 +38,8 @@ class chronobike : public bike { chronobike(bool noWriteResistance, bool noHeartService); bool connected() override; + minmax resistanceLimits() override {return minmax(1,15);} + private: // void writeCharacteristic(uint8_t *data, uint8_t data_len, QString info, bool disable_log = false, // Unused // bool wait_for_response = false); diff --git a/src/devices/computrainerbike/computrainerbike.cpp b/src/devices/computrainerbike/computrainerbike.cpp index 12090c300..1e8786df2 100644 --- a/src/devices/computrainerbike/computrainerbike.cpp +++ b/src/devices/computrainerbike/computrainerbike.cpp @@ -74,28 +74,6 @@ computrainerbike::computrainerbike(bool noWriteResistance, bool noHeartService, // ******************************************************************************************************** } -resistance_t computrainerbike::resistanceFromPowerRequest(uint16_t power) { - qDebug() << QStringLiteral("resistanceFromPowerRequest") << Cadence.value(); - - QSettings settings; - - double watt_gain = settings.value(QZSettings::watt_gain, QZSettings::default_watt_gain).toDouble(); - double watt_offset = settings.value(QZSettings::watt_offset, QZSettings::default_watt_offset).toDouble(); - - for (resistance_t i = 1; i < max_resistance; i++) { - if (((wattsFromResistance(i) * watt_gain) + watt_offset) <= power && - ((wattsFromResistance(i + 1) * watt_gain) + watt_offset) >= power) { - qDebug() << QStringLiteral("resistanceFromPowerRequest") - << ((wattsFromResistance(i) * watt_gain) + watt_offset) - << ((wattsFromResistance(i + 1) * watt_gain) + watt_offset) << power; - return i; - } - } - if (power < ((wattsFromResistance(1) * watt_gain) + watt_offset)) - return 1; - else - return max_resistance; -} uint16_t computrainerbike::wattsFromResistance(resistance_t resistance) { @@ -183,10 +161,8 @@ void computrainerbike::innerWriteResistance() { bool erg_mode = settings.value(QZSettings::zwift_erg, QZSettings::default_zwift_erg).toBool(); if (requestResistance != -1) { - if (requestResistance > max_resistance) { - requestResistance = max_resistance; - } else if (requestResistance < min_resistance) { - requestResistance = min_resistance; + if(!this->resistanceLimits().contains(requestResistance)) { + requestResistance = resistanceLimits().clip(requestResistance); } else if (requestResistance == 0) { requestResistance = 1; } diff --git a/src/devices/computrainerbike/computrainerbike.h b/src/devices/computrainerbike/computrainerbike.h index 78a178687..115646cd3 100644 --- a/src/devices/computrainerbike/computrainerbike.h +++ b/src/devices/computrainerbike/computrainerbike.h @@ -35,14 +35,11 @@ class computrainerbike : public bike { computrainerbike(bool noWriteResistance, bool noHeartService, uint8_t bikeResistanceOffset, double bikeResistanceGain); resistance_t pelotonToBikeResistance(int pelotonResistance) override; - resistance_t resistanceFromPowerRequest(uint16_t power) override; - resistance_t maxResistance() override { return max_resistance; } + + minmax resistanceLimits() override {return minmax(-20,100);} bool inclinationAvailableByHardware() override; bool connected() override; - private: - resistance_t max_resistance = 100; - resistance_t min_resistance = -20; uint16_t wattsFromResistance(resistance_t resistance); double GetDistanceFromPacket(QByteArray packet); QTime GetElapsedFromPacket(QByteArray packet); diff --git a/src/devices/cscbike/cscbike.cpp b/src/devices/cscbike/cscbike.cpp index fa31fb9d0..a8337c5e5 100644 --- a/src/devices/cscbike/cscbike.cpp +++ b/src/devices/cscbike/cscbike.cpp @@ -105,11 +105,7 @@ void cscbike::update() { } if (requestResistance != -1) { - if (requestResistance > 15) { - requestResistance = 15; - } else if (requestResistance == 0) { - requestResistance = 1; - } + requestResistance = this->resistanceLimits().clip(requestResistance); if (requestResistance != currentResistance().value()) { emit debug(QStringLiteral("writing resistance ") + QString::number(requestResistance)); diff --git a/src/devices/cscbike/cscbike.h b/src/devices/cscbike/cscbike.h index 1c926efb4..6a3d3e49b 100644 --- a/src/devices/cscbike/cscbike.h +++ b/src/devices/cscbike/cscbike.h @@ -38,6 +38,7 @@ class cscbike : public bike { cscbike(bool noWriteResistance, bool noHeartService, bool noVirtualDevice); bool connected() override; + minmax resistanceLimits() override {return minmax(1,15);} private: // void writeCharacteristic(uint8_t *data, uint8_t data_len, QString info, bool disable_log = false, //Unused // bool wait_for_response = false); diff --git a/src/devices/domyosbike/domyosbike.cpp b/src/devices/domyosbike/domyosbike.cpp index c0522eb1c..77d41a71f 100644 --- a/src/devices/domyosbike/domyosbike.cpp +++ b/src/devices/domyosbike/domyosbike.cpp @@ -246,11 +246,7 @@ void domyosbike::update() { } if (requestResistance != -1) { - if (requestResistance > max_resistance) { - requestResistance = max_resistance; - } else if (requestResistance < 1) { - requestResistance = 1; - } + requestResistance = this->resistanceLimits().clip(requestResistance); if (requestResistance != currentResistance().value()) { qDebug() << QStringLiteral("writing resistance ") + QString::number(requestResistance); @@ -391,7 +387,7 @@ void domyosbike::characteristicChanged(const QLowEnergyCharacteristic &character Resistance = 1; } emit resistanceRead(Resistance.value()); - m_pelotonResistance = (Resistance.value() * 100) / max_resistance; + m_pelotonResistance = (Resistance.value() * 100) / this->resistanceLimits().max(); bool disable_hr_frommachinery = settings.value(QZSettings::heart_ignore_builtin, QZSettings::default_heart_ignore_builtin).toBool(); @@ -666,21 +662,21 @@ bool domyosbike::connected() { } resistance_t domyosbike::pelotonToBikeResistance(int pelotonResistance) { - return (pelotonResistance * max_resistance) / 100; + return (pelotonResistance * this->resistanceLimits().max()) / 100; } resistance_t domyosbike::resistanceFromPowerRequest(uint16_t power) { qDebug() << QStringLiteral("resistanceFromPowerRequest") << currentCadence().value(); - for (resistance_t i = 1; i < max_resistance; i++) { + for (resistance_t i = 1; i < this->resistanceLimits().max(); i++) { if (wattsFromResistance(i) <= power && wattsFromResistance(i + 1) >= power) { return i; } } - if (power < wattsFromResistance(1)) + if (power < wattsFromResistance(this->resistanceLimits().min())) return 1; else - return max_resistance; + return this->resistanceLimits().max(); } uint16_t domyosbike::wattsFromResistance(double resistance) { diff --git a/src/devices/domyosbike/domyosbike.h b/src/devices/domyosbike/domyosbike.h index 2b7f7dc2d..ea77a22c1 100644 --- a/src/devices/domyosbike/domyosbike.h +++ b/src/devices/domyosbike/domyosbike.h @@ -40,7 +40,8 @@ class domyosbike : public bike { uint8_t bikeResistanceOffset = 4, double bikeResistanceGain = 1.0); resistance_t resistanceFromPowerRequest(uint16_t power) override; resistance_t pelotonToBikeResistance(int pelotonResistance) override; - resistance_t maxResistance() override { return max_resistance; } + minmax resistanceLimits() override {return minmax(1,15);} + ~domyosbike() override; bool connected() override; @@ -59,7 +60,6 @@ class domyosbike : public bike { void startDiscover(); uint16_t watts() override; - const resistance_t max_resistance = 15; QTimer *refresh; uint8_t firstVirtual = 0; uint8_t firstStateChanged = 0; diff --git a/src/devices/echelonconnectsport/echelonconnectsport.cpp b/src/devices/echelonconnectsport/echelonconnectsport.cpp index 8bb92d4f5..86bac93a4 100644 --- a/src/devices/echelonconnectsport/echelonconnectsport.cpp +++ b/src/devices/echelonconnectsport/echelonconnectsport.cpp @@ -125,10 +125,7 @@ void echelonconnectsport::update() { } if (requestResistance != -1) { - if (requestResistance > max_resistance) - requestResistance = max_resistance; - else if (requestResistance <= 0) - requestResistance = 1; + requestResistance = this->resistanceLimits().clip(requestResistance); if (requestResistance != currentResistance().value()) { qDebug() << QStringLiteral("writing resistance ") + QString::number(requestResistance); @@ -157,34 +154,37 @@ void echelonconnectsport::serviceDiscovered(const QBluetoothUuid &gatt) { } resistance_t echelonconnectsport::pelotonToBikeResistance(int pelotonResistance) { - for (resistance_t i = 1; i < max_resistance; i++) { + auto minMaxR = this->resistanceLimits(); + for (resistance_t i = 1; i < minMaxR.max(); i++) { if (bikeResistanceToPeloton(i) <= pelotonResistance && bikeResistanceToPeloton(i + 1) > pelotonResistance) { return i; } } - if (pelotonResistance < bikeResistanceToPeloton(1)) + if (pelotonResistance < bikeResistanceToPeloton(minMaxR.min())) return 1; else - return max_resistance; + return minMaxR.max(); } resistance_t echelonconnectsport::resistanceFromPowerRequest(uint16_t power) { qDebug() << QStringLiteral("resistanceFromPowerRequest") << Cadence.value(); + auto minMaxR = this->resistanceLimits(); + if (Cadence.value() == 0) - return 1; + return minMaxR.min(); - for (resistance_t i = 1; i < max_resistance; i++) { + for (resistance_t i = 1; i < minMaxR.max(); i++) { if (wattsFromResistance(i) <= power && wattsFromResistance(i + 1) >= power) { qDebug() << QStringLiteral("resistanceFromPowerRequest") << wattsFromResistance(i) << wattsFromResistance(i + 1) << power; return i; } } - if (power < wattsFromResistance(1)) + if (power < wattsFromResistance(minMaxR.min())) return 1; else - return max_resistance; + return minMaxR.max(); } double echelonconnectsport::bikeResistanceToPeloton(double resistance) { diff --git a/src/devices/echelonconnectsport/echelonconnectsport.h b/src/devices/echelonconnectsport/echelonconnectsport.h index dff83d543..d90b54e06 100644 --- a/src/devices/echelonconnectsport/echelonconnectsport.h +++ b/src/devices/echelonconnectsport/echelonconnectsport.h @@ -40,12 +40,11 @@ class echelonconnectsport : public bike { echelonconnectsport(bool noWriteResistance, bool noHeartService, uint8_t bikeResistanceOffset, double bikeResistanceGain); resistance_t pelotonToBikeResistance(int pelotonResistance) override; - resistance_t maxResistance() override { return max_resistance; } + minmax resistanceLimits() override { return minmax(1,32); } resistance_t resistanceFromPowerRequest(uint16_t power) override; bool connected() override; private: - const resistance_t max_resistance = 32; double bikeResistanceToPeloton(double resistance); double GetDistanceFromPacket(const QByteArray &packet); uint16_t wattsFromResistance(double resistance); diff --git a/src/devices/fakebike/fakebike.cpp b/src/devices/fakebike/fakebike.cpp index ef3e1f338..39eec6e24 100644 --- a/src/devices/fakebike/fakebike.cpp +++ b/src/devices/fakebike/fakebike.cpp @@ -175,20 +175,22 @@ resistance_t fakebike::resistanceFromPowerRequest(uint16_t power) { /*if(toorx_srx_3500)*/ { qDebug() << QStringLiteral("resistanceFromPowerRequest") << Cadence.value(); + auto minMaxR = this->resistanceLimits(); + if (Cadence.value() == 0) - return 1; + return minMaxR.min(); - for (resistance_t i = 1; i < maxResistance(); i++) { + for (resistance_t i = 1; i < minMaxR.max(); i++) { if (wattsFromResistance(i) <= power && wattsFromResistance(i + 1) >= power) { qDebug() << QStringLiteral("resistanceFromPowerRequest") << wattsFromResistance(i) << wattsFromResistance(i + 1) << power; return i; } } - if (power < wattsFromResistance(1)) - return 1; + if (power < wattsFromResistance(minMaxR.min())) + return minMaxR.min(); else - return maxResistance(); + return minMaxR.max(); } /*else { return power / 10; }*/ diff --git a/src/devices/fakebike/fakebike.h b/src/devices/fakebike/fakebike.h index e94ac4e14..a40022dda 100644 --- a/src/devices/fakebike/fakebike.h +++ b/src/devices/fakebike/fakebike.h @@ -40,7 +40,7 @@ class fakebike : public bike { fakebike(bool noWriteResistance, bool noHeartService, bool noVirtualDevice); bool connected() override; uint16_t watts() override; - resistance_t maxResistance() override { return 100; } + minmax resistanceLimits() override {return minmax(1,100);} resistance_t resistanceFromPowerRequest(uint16_t power) override; private: diff --git a/src/devices/fitplusbike/fitplusbike.cpp b/src/devices/fitplusbike/fitplusbike.cpp index 8578b8ab7..036a06ae3 100644 --- a/src/devices/fitplusbike/fitplusbike.cpp +++ b/src/devices/fitplusbike/fitplusbike.cpp @@ -343,11 +343,8 @@ void fitplusbike::update() { } if (requestResistance != -1) { - if (requestResistance > max_resistance) { - requestResistance = max_resistance; - } else if (requestResistance <= 0) { - requestResistance = 1; - } + + requestResistance = this->resistanceLimits().clip(requestResistance); if (requestResistance != currentResistance().value()) { qDebug() << QStringLiteral("writing resistance ") + QString::number(requestResistance); @@ -584,7 +581,7 @@ void fitplusbike::characteristicChanged(const QLowEnergyCharacteristic &characte settings.value(QZSettings::peloton_gain, QZSettings::default_peloton_gain).toDouble()) + settings.value(QZSettings::peloton_offset, QZSettings::default_peloton_offset).toDouble(); } else { - m_pelotonResistance = (100 * Resistance.value()) / max_resistance; + m_pelotonResistance = (100 * Resistance.value()) / this->resistanceLimits().max(); } if (settings.value(QZSettings::cadence_sensor_name, QZSettings::default_cadence_sensor_name) @@ -734,8 +731,7 @@ void fitplusbike::btinit() { writeCharacteristic(initData6, sizeof(initData6), QStringLiteral("init"), false, true); writeCharacteristic(initData1, sizeof(initData2), QStringLiteral("init"), false, false); - max_resistance = 32; - + this->bikeResistanceLimits = minmax(1,32); } else { uint8_t initData1[] = {0x02, 0x44, 0x01, 0x45, 0x03}; @@ -1079,18 +1075,20 @@ uint16_t fitplusbike::wattsFromResistance(double resistance) { resistance_t fitplusbike::resistanceFromPowerRequest(uint16_t power) { qDebug() << QStringLiteral("resistanceFromPowerRequest") << Cadence.value(); + auto minMaxR = this->resistanceLimits(); + if (Cadence.value() == 0) return 1; - for (resistance_t i = 1; i < max_resistance; i++) { + for (resistance_t i = 1; i < minMaxR.max(); i++) { if (wattsFromResistance(i) <= power && wattsFromResistance(i + 1) >= power) { qDebug() << QStringLiteral("resistanceFromPowerRequest") << wattsFromResistance(i) << wattsFromResistance(i + 1) << power; return i; } } - if (power < wattsFromResistance(1)) - return 1; + if (power < wattsFromResistance(minMaxR.min())) + return minMaxR.min(); else - return max_resistance; + return minMaxR.max(); } diff --git a/src/devices/fitplusbike/fitplusbike.h b/src/devices/fitplusbike/fitplusbike.h index 2bc94257b..aefab07ad 100644 --- a/src/devices/fitplusbike/fitplusbike.h +++ b/src/devices/fitplusbike/fitplusbike.h @@ -37,12 +37,11 @@ class fitplusbike : public bike { Q_OBJECT public: fitplusbike(bool noWriteResistance, bool noHeartService, uint8_t bikeResistanceOffset, double bikeResistanceGain); - resistance_t maxResistance() override { return max_resistance; } + minmax resistanceLimits() override {return this->bikeResistanceLimits;} bool connected() override; resistance_t resistanceFromPowerRequest(uint16_t power) override; private: - resistance_t max_resistance = 24; void btinit(); void writeCharacteristic(uint8_t *data, uint8_t data_len, const QString &info, bool disable_log = false, bool wait_for_response = false); @@ -60,6 +59,7 @@ class fitplusbike : public bike { QLowEnergyCharacteristic gattNotify1Characteristic; QLowEnergyCharacteristic gattNotifyFTMSCharacteristic; + minmax bikeResistanceLimits{1,24}; uint8_t bikeResistanceOffset = 4; double bikeResistanceGain = 1.0; uint8_t counterPoll = 1; diff --git a/src/devices/flywheelbike/flywheelbike.cpp b/src/devices/flywheelbike/flywheelbike.cpp index 7ee06230a..ccf0347fc 100644 --- a/src/devices/flywheelbike/flywheelbike.cpp +++ b/src/devices/flywheelbike/flywheelbike.cpp @@ -81,11 +81,7 @@ void flywheelbike::update() { }*/ if (requestResistance != -1) { - if (requestResistance > 15) { - requestResistance = 15; - } else if (requestResistance == 0) { - requestResistance = 1; - } + requestResistance = this->resistanceLimits().clip(requestResistance); if (requestResistance != currentResistance().value()) { emit debug(QStringLiteral("writing resistance ") + QString::number(requestResistance)); diff --git a/src/devices/flywheelbike/flywheelbike.h b/src/devices/flywheelbike/flywheelbike.h index 956b2d034..4a1f9df4c 100644 --- a/src/devices/flywheelbike/flywheelbike.h +++ b/src/devices/flywheelbike/flywheelbike.h @@ -38,6 +38,8 @@ class flywheelbike : public bike { flywheelbike(bool noWriteResistance, bool noHeartService); bool connected() override; + minmax resistanceLimits() override {return minmax(1,15);} + private: typedef enum DecoderRXState { WFSYNC_1 = 0, WFLENGTH, WFID, DATA, CHECKSUM, EOF_1 } DecoderRXState; diff --git a/src/devices/ftmsbike/ftmsbike.cpp b/src/devices/ftmsbike/ftmsbike.cpp index 6e124df7e..a4487e050 100644 --- a/src/devices/ftmsbike/ftmsbike.cpp +++ b/src/devices/ftmsbike/ftmsbike.cpp @@ -104,24 +104,6 @@ uint16_t ftmsbike::wattsFromResistance(double resistance) { return 1; } -resistance_t ftmsbike::resistanceFromPowerRequest(uint16_t power) { - qDebug() << QStringLiteral("resistanceFromPowerRequest") << Cadence.value(); - - if (Cadence.value() == 0) - return 1; - - for (resistance_t i = 1; i < max_resistance; i++) { - if (wattsFromResistance(i) <= power && wattsFromResistance(i + 1) >= power) { - qDebug() << QStringLiteral("resistanceFromPowerRequest") << wattsFromResistance(i) - << wattsFromResistance(i + 1) << power; - return i; - } - } - if (power < wattsFromResistance(1)) - return 1; - else - return max_resistance; -} void ftmsbike::forceResistance(resistance_t requestResistance) { @@ -894,7 +876,7 @@ void ftmsbike::error(QLowEnergyController::Error err) { } resistance_t ftmsbike::pelotonToBikeResistance(int pelotonResistance) { - return (pelotonResistance * max_resistance) / 100; + return (pelotonResistance * this->resistanceLimits().max()) / 100; } void ftmsbike::deviceDiscovered(const QBluetoothDeviceInfo &device) { @@ -904,13 +886,13 @@ void ftmsbike::deviceDiscovered(const QBluetoothDeviceInfo &device) { bluetoothDevice = device; if (bluetoothDevice.name().toUpper().startsWith("SUITO")) { qDebug() << QStringLiteral("SUITO found"); - max_resistance = 16; + this->bikeResistanceLimits = minmax(1,16); } else if ((bluetoothDevice.name().toUpper().startsWith("MAGNUS "))) { qDebug() << QStringLiteral("MAGNUS found"); resistance_lvl_mode = true; } else if ((bluetoothDevice.name().toUpper().startsWith("DU30-"))) { qDebug() << QStringLiteral("DU30 found"); - max_resistance = 32; + this->bikeResistanceLimits = minmax(1,32); DU30_bike = true; } diff --git a/src/devices/ftmsbike/ftmsbike.h b/src/devices/ftmsbike/ftmsbike.h index 935a9c9b9..a68ca837c 100644 --- a/src/devices/ftmsbike/ftmsbike.h +++ b/src/devices/ftmsbike/ftmsbike.h @@ -71,8 +71,7 @@ class ftmsbike : public bike { ftmsbike(bool noWriteResistance, bool noHeartService, uint8_t bikeResistanceOffset, double bikeResistanceGain); bool connected() override; resistance_t pelotonToBikeResistance(int pelotonResistance) override; - resistance_t maxResistance() override { return max_resistance; } - resistance_t resistanceFromPowerRequest(uint16_t power) override; + minmax resistanceLimits() override {return this->bikeResistanceLimits;} private: void writeCharacteristic(uint8_t *data, uint8_t data_len, const QString &info, bool disable_log = false, @@ -82,7 +81,7 @@ class ftmsbike : public bike { void init(); void forceResistance(resistance_t requestResistance); void forcePower(int16_t requestPower); - uint16_t wattsFromResistance(double resistance); + uint16_t wattsFromResistance(double resistance) override; QTimer *refresh; @@ -96,7 +95,7 @@ class ftmsbike : public bike { uint8_t firstStateChanged = 0; uint8_t bikeResistanceOffset = 4; double bikeResistanceGain = 1.0; - int max_resistance = 100; + minmax bikeResistanceLimits { 1,100}; bool initDone = false; bool initRequest = false; diff --git a/src/devices/horizongr7bike/horizongr7bike.cpp b/src/devices/horizongr7bike/horizongr7bike.cpp index 4a9386957..3bae646a0 100644 --- a/src/devices/horizongr7bike/horizongr7bike.cpp +++ b/src/devices/horizongr7bike/horizongr7bike.cpp @@ -110,12 +110,7 @@ void horizongr7bike::update() { } if (requestResistance != -1) { - if (requestResistance > max_resistance) { - requestResistance = max_resistance; - } // TODO, use the bluetooth value - else if (requestResistance == 0) { - requestResistance = 1; - } + requestResistance = this->resistanceLimits().clip(requestResistance); // TODO, use the bluetooth value if (requestResistance != currentResistance().value()) { emit debug(QStringLiteral("writing resistance ") + QString::number(requestResistance)); diff --git a/src/devices/horizongr7bike/horizongr7bike.h b/src/devices/horizongr7bike/horizongr7bike.h index 719ab0a42..291653a8e 100644 --- a/src/devices/horizongr7bike/horizongr7bike.h +++ b/src/devices/horizongr7bike/horizongr7bike.h @@ -40,6 +40,8 @@ class horizongr7bike : public bike { double bikeResistanceGain); bool connected() override; + minmax resistanceLimits() override {return minmax(1,12);} + private: void writeCharacteristic(uint8_t *data, uint8_t data_len, const QString &info, bool disable_log = false, bool wait_for_response = false); @@ -58,7 +60,7 @@ class horizongr7bike : public bike { QLowEnergyCharacteristic customWriteChar; double bikeResistanceToPeloton(double resistance); - const resistance_t max_resistance = 12; + uint8_t sec1Update = 0; QByteArray lastPacket; QDateTime lastRefreshCharacteristicChanged = QDateTime::currentDateTime(); diff --git a/src/devices/iconceptbike/iconceptbike.cpp b/src/devices/iconceptbike/iconceptbike.cpp index 308cd0744..08dabeb3f 100644 --- a/src/devices/iconceptbike/iconceptbike.cpp +++ b/src/devices/iconceptbike/iconceptbike.cpp @@ -104,11 +104,8 @@ void iconceptbike::update() { // ******************************************************************************************************** if (requestResistance != -1) { - if (requestResistance > 12) { - requestResistance = 12; - } else if (requestResistance < 1) { - requestResistance = 1; - } + requestResistance = this->resistanceLimits().clip(requestResistance); + char resValues[] = {0x08, 0x0a, 0x0b, 0x0d, 0x0e, 0x10, 0x11, 0x13, 0x14, 0x16, 0x17, 0x18}; char res[] = {0x55, 0x11, 0x01, 0x12}; res[3] = resValues[requestResistance - 1]; diff --git a/src/devices/iconceptbike/iconceptbike.h b/src/devices/iconceptbike/iconceptbike.h index 3011be72f..fe703efc6 100644 --- a/src/devices/iconceptbike/iconceptbike.h +++ b/src/devices/iconceptbike/iconceptbike.h @@ -34,6 +34,8 @@ class iconceptbike : public bike { public: explicit iconceptbike(); + minmax resistanceLimits() override {return minmax(1,12);} + public slots: void deviceDiscovered(const QBluetoothDeviceInfo &device); diff --git a/src/devices/inspirebike/inspirebike.cpp b/src/devices/inspirebike/inspirebike.cpp index bef594ab5..d7d0bb499 100644 --- a/src/devices/inspirebike/inspirebike.cpp +++ b/src/devices/inspirebike/inspirebike.cpp @@ -94,11 +94,7 @@ void inspirebike::update() { } if (requestResistance != -1) { - if (requestResistance > max_resistance) { - requestResistance = max_resistance; - } else if (requestResistance == 0) { - requestResistance = 1; - } + requestResistance = this->resistanceLimits().clip(requestResistance); if (requestResistance != currentResistance().value()) { emit debug(QStringLiteral("writing resistance ") + QString::number(requestResistance)); @@ -390,7 +386,7 @@ uint16_t inspirebike::watts() { -136.8333333, -132.3333333, -160, -66.16666667, -93.5, -131.5, -149.5, -92.16666667}; uint8_t res = qRound(currentResistance().value()); - if (res - 1 < max_resistance && res > 0) { + if (res - 1 < this->resistanceLimits().max() && res > 0) { double w = ((m[res - 1] * (double)(currentCadence().value())) + q[res - 1]); if (w < 0) w = 0; diff --git a/src/devices/inspirebike/inspirebike.h b/src/devices/inspirebike/inspirebike.h index 97303d6e2..ac9177c3f 100644 --- a/src/devices/inspirebike/inspirebike.h +++ b/src/devices/inspirebike/inspirebike.h @@ -37,10 +37,10 @@ class inspirebike : public bike { Q_OBJECT public: inspirebike(bool noWriteResistance, bool noHeartService); - resistance_t maxResistance() override { return max_resistance; } + minmax resistanceLimits() override {return minmax(1,40);} bool connected() override; - const resistance_t max_resistance = 40; + private: void writeCharacteristic(uint8_t *data, uint8_t data_len, QString info, bool disable_log = false, diff --git a/src/devices/keepbike/keepbike.cpp b/src/devices/keepbike/keepbike.cpp index a80bb0391..b693b17b0 100644 --- a/src/devices/keepbike/keepbike.cpp +++ b/src/devices/keepbike/keepbike.cpp @@ -133,10 +133,7 @@ void keepbike::update() { } if (requestResistance != -1) { - if (requestResistance > max_resistance) - requestResistance = max_resistance; - else if (requestResistance <= 0) - requestResistance = 1; + requestResistance = this->resistanceLimits().clip(requestResistance); if (requestResistance != currentResistance().value()) { qDebug() << QStringLiteral("writing resistance ") + QString::number(requestResistance); @@ -164,17 +161,6 @@ void keepbike::serviceDiscovered(const QBluetoothUuid &gatt) { qDebug() << QStringLiteral("serviceDiscovered ") + gatt.toString(); } -resistance_t keepbike::pelotonToBikeResistance(int pelotonResistance) { - for (resistance_t i = 1; i < max_resistance; i++) { - if (bikeResistanceToPeloton(i) <= pelotonResistance && bikeResistanceToPeloton(i + 1) >= pelotonResistance) { - return i; - } - } - if (pelotonResistance < bikeResistanceToPeloton(1)) - return 1; - else - return max_resistance; -} double keepbike::bikeResistanceToPeloton(double resistance) { // 0,0097x3 - 0,4972x2 + 10,126x - 37,08 diff --git a/src/devices/keepbike/keepbike.h b/src/devices/keepbike/keepbike.h index 25305a2be..6bda7513b 100644 --- a/src/devices/keepbike/keepbike.h +++ b/src/devices/keepbike/keepbike.h @@ -37,13 +37,12 @@ class keepbike : public bike { Q_OBJECT public: keepbike(bool noWriteResistance, bool noHeartService, uint8_t bikeResistanceOffset, double bikeResistanceGain); - resistance_t pelotonToBikeResistance(int pelotonResistance) override; - resistance_t maxResistance() override { return max_resistance; } + + minmax resistanceLimits() override {return minmax(1,36);} bool connected() override; private: - const resistance_t max_resistance = 36; - double bikeResistanceToPeloton(double resistance); + double bikeResistanceToPeloton(double resistance) override; double GetDistanceFromPacket(const QByteArray &packet); double GetSpeedFromPacket(const QByteArray &packet); double GetWattFromPacket(const QByteArray &packet); diff --git a/src/devices/mcfbike/mcfbike.cpp b/src/devices/mcfbike/mcfbike.cpp index ecb65b27b..57f97842c 100644 --- a/src/devices/mcfbike/mcfbike.cpp +++ b/src/devices/mcfbike/mcfbike.cpp @@ -104,10 +104,7 @@ void mcfbike::update() { sendPoll(); if (requestResistance != -1) { - if (requestResistance > max_resistance) - requestResistance = max_resistance; - else if (requestResistance <= 0) - requestResistance = 1; + requestResistance = this->resistanceLimits().clip(requestResistance); if (requestResistance != currentResistance().value()) { qDebug() << QStringLiteral("writing resistance ") + QString::number(requestResistance); @@ -135,33 +132,6 @@ void mcfbike::serviceDiscovered(const QBluetoothUuid &gatt) { qDebug() << QStringLiteral("serviceDiscovered ") + gatt.toString(); } -resistance_t mcfbike::pelotonToBikeResistance(int pelotonResistance) { - for (resistance_t i = 1; i < max_resistance; i++) { - if (bikeResistanceToPeloton(i) <= pelotonResistance && bikeResistanceToPeloton(i + 1) >= pelotonResistance) { - return i; - } - } - if (pelotonResistance < bikeResistanceToPeloton(1)) - return 1; - else - return max_resistance; -} - -resistance_t mcfbike::resistanceFromPowerRequest(uint16_t power) { - qDebug() << QStringLiteral("resistanceFromPowerRequest") << Cadence.value(); - - for (resistance_t i = 1; i < max_resistance; i++) { - if (wattsFromResistance(i) <= power && wattsFromResistance(i + 1) >= power) { - qDebug() << QStringLiteral("resistanceFromPowerRequest") << wattsFromResistance(i) - << wattsFromResistance(i + 1) << power; - return i; - } - } - if (power < wattsFromResistance(1)) - return 1; - else - return max_resistance; -} // TO CHANGE uint16_t mcfbike::wattsFromResistance(double resistance) { @@ -169,7 +139,7 @@ uint16_t mcfbike::wattsFromResistance(double resistance) { } double mcfbike::bikeResistanceToPeloton(double resistance) { - double p = resistance * (100.0 / max_resistance); + double p = resistance * (100.0 / this->resistanceLimits().max()); if (p < 0) { p = 0; } diff --git a/src/devices/mcfbike/mcfbike.h b/src/devices/mcfbike/mcfbike.h index 3f0106841..447e1735b 100644 --- a/src/devices/mcfbike/mcfbike.h +++ b/src/devices/mcfbike/mcfbike.h @@ -36,16 +36,14 @@ class mcfbike : public bike { Q_OBJECT public: mcfbike(bool noWriteResistance, bool noHeartService, uint8_t bikeResistanceOffset, double bikeResistanceGain); - resistance_t pelotonToBikeResistance(int pelotonResistance) override; - resistance_t resistanceFromPowerRequest(uint16_t power) override; - resistance_t maxResistance() override { return max_resistance; } + + minmax resistanceLimits() override {return minmax(1,14);} bool connected() override; private: - const resistance_t max_resistance = 14; - double bikeResistanceToPeloton(double resistance); + double bikeResistanceToPeloton(double resistance) override; double GetDistanceFromPacket(const QByteArray &packet); - uint16_t wattsFromResistance(double resistance); + uint16_t wattsFromResistance(double resistance) override; QTime GetElapsedFromPacket(const QByteArray &packet); void btinit(); void writeCharacteristic(uint8_t *data, uint8_t data_len, const QString &info, bool disable_log = false, diff --git a/src/devices/mepanelbike/mepanelbike.cpp b/src/devices/mepanelbike/mepanelbike.cpp index 917801757..4a27b4cce 100644 --- a/src/devices/mepanelbike/mepanelbike.cpp +++ b/src/devices/mepanelbike/mepanelbike.cpp @@ -98,10 +98,7 @@ void mepanelbike::update() { } if (requestResistance != -1) { - if (requestResistance > max_resistance) - requestResistance = max_resistance; - else if (requestResistance <= 0) - requestResistance = 1; + requestResistance = this->resistanceLimits().clip(requestResistance); if (requestResistance != currentResistance().value()) { qDebug() << QStringLiteral("writing resistance ") + QString::number(requestResistance); diff --git a/src/devices/mepanelbike/mepanelbike.h b/src/devices/mepanelbike/mepanelbike.h index 861a3efa1..1e4c9238e 100644 --- a/src/devices/mepanelbike/mepanelbike.h +++ b/src/devices/mepanelbike/mepanelbike.h @@ -38,9 +38,9 @@ class mepanelbike : public bike { public: mepanelbike(bool noWriteResistance, bool noHeartService, uint8_t bikeResistanceOffset, double bikeResistanceGain); bool connected() override; + minmax resistanceLimits() override {return minmax(1,32);} private: - const resistance_t max_resistance = 32; void btinit(); void writeCharacteristic(uint8_t *data, uint8_t data_len, const QString &info, bool disable_log = false, bool wait_for_response = false); diff --git a/src/devices/nautilusbike/nautilusbike.cpp b/src/devices/nautilusbike/nautilusbike.cpp index 7dde95c0e..4972cc3d4 100644 --- a/src/devices/nautilusbike/nautilusbike.cpp +++ b/src/devices/nautilusbike/nautilusbike.cpp @@ -440,23 +440,26 @@ uint16_t nautilusbike::wattsFromResistance(double resistance) { resistance_t nautilusbike::resistanceFromPowerRequest(uint16_t power) { qDebug() << QStringLiteral("resistanceFromPowerRequest") << Cadence.average5s(); + auto minMaxR = this->resistanceLimits(); + if (Cadence.average5s() == 0) - return 1; + return minMaxR.min(); - for (resistance_t i = 1; i < maxResistance(); i++) { + for (resistance_t i = minMaxR.min(); i < minMaxR.max(); i++) { if (wattsFromResistance(i) <= power && wattsFromResistance(i + 1) >= power) { qDebug() << QStringLiteral("resistanceFromPowerRequest") << wattsFromResistance(i) << wattsFromResistance(i + 1) << power; return i; } } - if (power < wattsFromResistance(1)) - return 1; + if (power < wattsFromResistance(minMaxR.min())) + return minMaxR.min(); else - return maxResistance(); + return minMaxR.max(); } -resistance_t nautilusbike::maxResistance() { - // power table nautilus u626 #2118 - return 25; +minmax nautilusbike::resistanceLimits() { + return minmax(1,25);// power table nautilus u626 #2118 } + + diff --git a/src/devices/nautilusbike/nautilusbike.h b/src/devices/nautilusbike/nautilusbike.h index 9dc42192d..2b1951479 100644 --- a/src/devices/nautilusbike/nautilusbike.h +++ b/src/devices/nautilusbike/nautilusbike.h @@ -36,8 +36,7 @@ class nautilusbike : public bike { ~nautilusbike(); bool connected() override; resistance_t resistanceFromPowerRequest(uint16_t power) override; - resistance_t maxResistance() override; - + minmax resistanceLimits() override; private: double GetSpeedFromPacket(const QByteArray &packet); double GetInclinationFromPacket(QByteArray packet); diff --git a/src/devices/nordictrackifitadbbike/nordictrackifitadbbike.cpp b/src/devices/nordictrackifitadbbike/nordictrackifitadbbike.cpp index 7f7bcf90b..47ed8be68 100644 --- a/src/devices/nordictrackifitadbbike/nordictrackifitadbbike.cpp +++ b/src/devices/nordictrackifitadbbike/nordictrackifitadbbike.cpp @@ -574,22 +574,7 @@ bool nordictrackifitadbbike::connected() { return true; } resistance_t nordictrackifitadbbike::resistanceFromPowerRequest(uint16_t power) { // actually it's using inclination for the s22i - qDebug() << QStringLiteral("resistanceFromPowerRequest") << Cadence.value(); - - if (Cadence.value() == 0) - return 0; - - for (resistance_t i = 0; i < max_resistance; i++) { - if (wattsFromResistance(i, Cadence.value()) <= power && wattsFromResistance(i + 1, Cadence.value()) >= power) { - qDebug() << QStringLiteral("resistanceFromPowerRequest") << wattsFromResistance(i, Cadence.value()) - << wattsFromResistance(i + 1, Cadence.value()) << power; - return i; - } - } - if (power < wattsFromResistance(0, Cadence.value())) - return 0; - else - return max_resistance; + return bike::resistanceFromPowerRequest(power); } uint16_t nordictrackifitadbbike::wattsFromResistance(double inclination, double cadence) { diff --git a/src/devices/nordictrackifitadbbike/nordictrackifitadbbike.h b/src/devices/nordictrackifitadbbike/nordictrackifitadbbike.h index b873bb018..0c0eab3f9 100644 --- a/src/devices/nordictrackifitadbbike/nordictrackifitadbbike.h +++ b/src/devices/nordictrackifitadbbike/nordictrackifitadbbike.h @@ -65,10 +65,11 @@ class nordictrackifitadbbike : public bike { bool connected() override; resistance_t pelotonToBikeResistance(int pelotonResistance) override; bool inclinationAvailableByHardware() override; - resistance_t resistanceFromPowerRequest(uint16_t power) override; - + resistance_t resistanceFromPowerRequest(uint16_t power) override; + minmax resistanceLimits() override { + return minmax(0,17); // max inclination for s22i + } private: - const resistance_t max_resistance = 17; // max inclination for s22i void forceResistance(double resistance); uint16_t watts() override; double getDouble(QString v); diff --git a/src/devices/npecablebike/npecablebike.cpp b/src/devices/npecablebike/npecablebike.cpp index 89a7c1d46..0c4e8db6a 100644 --- a/src/devices/npecablebike/npecablebike.cpp +++ b/src/devices/npecablebike/npecablebike.cpp @@ -78,11 +78,7 @@ void npecablebike::update() { } if (requestResistance != -1) { - if (requestResistance > 15) { - requestResistance = 15; - } else if (requestResistance == 0) { - requestResistance = 1; - } + requestResistance = this->resistanceLimits().clip(requestResistance); if (requestResistance != currentResistance().value()) { emit debug(QStringLiteral("writing resistance ") + QString::number(requestResistance)); diff --git a/src/devices/npecablebike/npecablebike.h b/src/devices/npecablebike/npecablebike.h index afef77276..b695b4368 100644 --- a/src/devices/npecablebike/npecablebike.h +++ b/src/devices/npecablebike/npecablebike.h @@ -37,7 +37,7 @@ class npecablebike : public bike { public: npecablebike(bool noWriteResistance, bool noHeartService); bool connected() override; - + minmax resistanceLimits() override {return minmax(1,15);} private: void writeCharacteristic(uint8_t *data, uint8_t data_len, QString info, bool disable_log = false, bool wait_for_response = false); diff --git a/src/devices/pafersbike/pafersbike.cpp b/src/devices/pafersbike/pafersbike.cpp index 7b33f1e6b..20355f697 100644 --- a/src/devices/pafersbike/pafersbike.cpp +++ b/src/devices/pafersbike/pafersbike.cpp @@ -112,10 +112,7 @@ void pafersbike::update() { } if (requestResistance != -1) { - if (requestResistance > max_resistance) - requestResistance = max_resistance; - else if (requestResistance <= 0) - requestResistance = 1; + requestResistance = this->resistanceLimits().clip(requestResistance); if (requestResistance != currentResistance().value()) { qDebug() << QStringLiteral("writing resistance ") + QString::number(requestResistance); @@ -143,34 +140,6 @@ void pafersbike::serviceDiscovered(const QBluetoothUuid &gatt) { qDebug() << QStringLiteral("serviceDiscovered ") + gatt.toString(); } -resistance_t pafersbike::pelotonToBikeResistance(int pelotonResistance) { - for (resistance_t i = 1; i < max_resistance; i++) { - if (bikeResistanceToPeloton(i) <= pelotonResistance && bikeResistanceToPeloton(i + 1) >= pelotonResistance) { - return i; - } - } - if (pelotonResistance < bikeResistanceToPeloton(1)) - return 1; - else - return max_resistance; -} - -resistance_t pafersbike::resistanceFromPowerRequest(uint16_t power) { - qDebug() << QStringLiteral("resistanceFromPowerRequest") << Cadence.value(); - - for (resistance_t i = 1; i < max_resistance; i++) { - if (wattsFromResistance(i) <= power && wattsFromResistance(i + 1) >= power) { - qDebug() << QStringLiteral("resistanceFromPowerRequest") << wattsFromResistance(i) - << wattsFromResistance(i + 1) << power; - return i; - } - } - if (power < wattsFromResistance(1)) - return 1; - else - return max_resistance; -} - uint16_t pafersbike::wattsFromResistance(double resistance) { // to be changed return ((10.39 + 1.45 * (resistance - 1.0)) * (exp(0.028 * (currentCadence().value())))); diff --git a/src/devices/pafersbike/pafersbike.h b/src/devices/pafersbike/pafersbike.h index e424318c3..a6974d02f 100644 --- a/src/devices/pafersbike/pafersbike.h +++ b/src/devices/pafersbike/pafersbike.h @@ -36,16 +36,14 @@ class pafersbike : public bike { Q_OBJECT public: pafersbike(bool noWriteResistance, bool noHeartService, uint8_t bikeResistanceOffset, double bikeResistanceGain); - resistance_t pelotonToBikeResistance(int pelotonResistance) override; - resistance_t resistanceFromPowerRequest(uint16_t power) override; - resistance_t maxResistance() override { return max_resistance; } + + minmax resistanceLimits() override {return minmax(1,24);} bool connected() override; private: - const resistance_t max_resistance = 24; - double bikeResistanceToPeloton(double resistance); + double bikeResistanceToPeloton(double resistance) override; double GetDistanceFromPacket(const QByteArray &packet); - uint16_t wattsFromResistance(double resistance); + uint16_t wattsFromResistance(double resistance) override; QTime GetElapsedFromPacket(const QByteArray &packet); void btinit(); void writeCharacteristic(uint8_t *data, uint8_t data_len, const QString &info, bool disable_log = false, diff --git a/src/devices/proformbike/proformbike.cpp b/src/devices/proformbike/proformbike.cpp index 72d3b44ea..66469c396 100644 --- a/src/devices/proformbike/proformbike.cpp +++ b/src/devices/proformbike/proformbike.cpp @@ -55,35 +55,12 @@ void proformbike::writeCharacteristic(uint8_t *data, uint8_t data_len, const QSt loop.exec(); } -resistance_t proformbike::resistanceFromPowerRequest(uint16_t power) { - qDebug() << QStringLiteral("resistanceFromPowerRequest") << Cadence.value(); - - QSettings settings; - - double watt_gain = settings.value(QZSettings::watt_gain, QZSettings::default_watt_gain).toDouble(); - double watt_offset = settings.value(QZSettings::watt_offset, QZSettings::default_watt_offset).toDouble(); - - for (resistance_t i = 1; i < max_resistance; i++) { - if (((wattsFromResistance(i) * watt_gain) + watt_offset) <= power && - ((wattsFromResistance(i + 1) * watt_gain) + watt_offset) >= power) { - qDebug() << QStringLiteral("resistanceFromPowerRequest") - << ((wattsFromResistance(i) * watt_gain) + watt_offset) - << ((wattsFromResistance(i + 1) * watt_gain) + watt_offset) << power; - return i; - } - } - if (power < ((wattsFromResistance(1) * watt_gain) + watt_offset)) - return 1; - else - return max_resistance; -} - -uint16_t proformbike::wattsFromResistance(resistance_t resistance) { +uint16_t proformbike::wattsFromResistance(double resistance) { if (currentCadence().value() == 0) return 0; - switch (resistance) { + switch ((resistance_t)resistance) { case 0: case 1: // -13.5 + 0.999x + 0.00993x² @@ -482,11 +459,7 @@ void proformbike::forceIncline(double incline) { void proformbike::innerWriteResistance() { if (requestResistance != -1) { - if (requestResistance > max_resistance) { - requestResistance = max_resistance; - } else if (requestResistance == 0) { - requestResistance = 1; - } + requestResistance = this->resistanceLimits().clip(requestResistance); if (requestResistance != currentResistance().value()) { emit debug(QStringLiteral("writing resistance ") + QString::number(requestResistance)); @@ -1321,8 +1294,7 @@ void proformbike::btinit() { bool proform_bike_225_csx = settings.value(QZSettings::proform_bike_225_csx, QZSettings::default_proform_bike_225_csx).toBool(); if (settings.value(QZSettings::proform_studio, QZSettings::default_proform_studio).toBool()) { - - max_resistance = 32; + this->bikeResistanceLimits = minmax(1,32); uint8_t initData1[] = {0xfe, 0x02, 0x08, 0x02}; uint8_t initData2[] = {0xff, 0x08, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x81, 0x87, @@ -1383,7 +1355,8 @@ void proformbike::btinit() { } else if (settings.value(QZSettings::proform_tdf_10, QZSettings::default_proform_tdf_10).toBool() || settings.value(QZSettings::proform_bike_PFEVEX71316_1, QZSettings::default_proform_bike_PFEVEX71316_1) .toBool()) { - max_resistance = 26; + this->bikeResistanceLimits = minmax(1,26); + uint8_t initData1[] = {0xfe, 0x02, 0x08, 0x02}; uint8_t initData2[] = {0xff, 0x08, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x81, 0x87, @@ -1520,7 +1493,7 @@ void proformbike::btinit() { writeCharacteristic(initData12, sizeof(initData12), QStringLiteral("init"), false, false); QThread::msleep(400); } else if (proform_bike_sb) { - max_resistance = 16; + this->bikeResistanceLimits = minmax(1,16); uint8_t initData10[] = {0x00, 0x12, 0x02, 0x04, 0x02, 0x28, 0x07, 0x28, 0x90, 0x07, 0x01, 0x86, 0x64, 0x38, 0x1a, 0xfa, 0xe8, 0xcc, 0xa6, 0x9e}; @@ -1536,7 +1509,7 @@ void proformbike::btinit() { writeCharacteristic(initData12, sizeof(initData12), QStringLiteral("init"), false, false); QThread::msleep(400); } else if (nordictrack_gx_2_7) { - max_resistance = 20; + this->bikeResistanceLimits = minmax(1,20); uint8_t initData10[] = {0x00, 0x12, 0x02, 0x04, 0x02, 0x28, 0x07, 0x28, 0x90, 0x04, 0x00, 0x9e, 0x84, 0x60, 0x4a, 0x32, 0x28, 0x04, 0xf6, 0xe6}; @@ -1552,7 +1525,7 @@ void proformbike::btinit() { writeCharacteristic(initData12, sizeof(initData12), QStringLiteral("init"), false, false); QThread::msleep(400); } else if (proform_cycle_trainer_400) { - max_resistance = 16; + this->bikeResistanceLimits = minmax(1,16); uint8_t initData10[] = {0x00, 0x12, 0x02, 0x04, 0x02, 0x28, 0x07, 0x28, 0x90, 0x07, 0x01, 0x52, 0x74, 0x94, 0xb2, 0xde, 0x08, 0x20, 0x5e, 0x8a}; @@ -1568,7 +1541,7 @@ void proformbike::btinit() { writeCharacteristic(initData12, sizeof(initData12), QStringLiteral("init"), false, false); QThread::msleep(400); } else if (proform_cycle_trainer_300_ci) { - max_resistance = 16; + this->bikeResistanceLimits = minmax(1,16); uint8_t initData10[] = {0x00, 0x12, 0x02, 0x04, 0x02, 0x28, 0x07, 0x28, 0x90, 0x04, 0x00, 0x10, 0xcc, 0x7a, 0x3e, 0xf4, 0xb8, 0x66, 0x3a, 0xf8}; @@ -1677,7 +1650,7 @@ void proformbike::btinit() { writeCharacteristic(noOpData22, sizeof(noOpData22), QStringLiteral("init"), false, false); QThread::msleep(400); } else if (proform_bike_225_csx) { - max_resistance = 10; + this->bikeResistanceLimits = minmax(1,10); uint8_t initData10[] = {0x00, 0x12, 0x02, 0x04, 0x02, 0x28, 0x07, 0x28, 0x90, 0x07, 0x01, 0xd2, 0x74, 0x14, 0xb2, 0x5e, 0x08, 0xa0, 0x5e, 0x0a}; uint8_t initData11[] = {0x01, 0x12, 0xbc, 0x6c, 0x1a, 0xc6, 0x90, 0x28, 0xe6, 0xa2, 0x64, 0x24, 0xe2, 0xae, 0x98, 0x50, 0x0e, 0xfa, 0xac, 0x9c}; uint8_t initData12[] = {0xff, 0x08, 0x4a, 0x36, 0x20, 0x98, 0x02, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; @@ -1689,7 +1662,7 @@ void proformbike::btinit() { writeCharacteristic(initData12, sizeof(initData12), QStringLiteral("init"), false, false); QThread::msleep(400); } else if (proform_hybrid_trainer_PFEL03815) { - max_resistance = 16; + this->bikeResistanceLimits = minmax(1,16); uint8_t initData10[] = {0x00, 0x12, 0x02, 0x04, 0x02, 0x28, 0x07, 0x28, 0x90, 0x04, 0x00, 0xb8, 0xac, 0x92, 0x8e, 0x7c, 0x78, 0x6e, 0x6a, 0x50}; uint8_t initData11[] = {0x01, 0x12, 0x54, 0x5a, 0x56, 0x54, 0x70, 0x76, 0x62, 0x68, diff --git a/src/devices/proformbike/proformbike.h b/src/devices/proformbike/proformbike.h index 2fe5c7ca6..1e9f7c53d 100644 --- a/src/devices/proformbike/proformbike.h +++ b/src/devices/proformbike/proformbike.h @@ -37,14 +37,13 @@ class proformbike : public bike { public: proformbike(bool noWriteResistance, bool noHeartService, uint8_t bikeResistanceOffset, double bikeResistanceGain); resistance_t pelotonToBikeResistance(int pelotonResistance) override; - resistance_t resistanceFromPowerRequest(uint16_t power) override; - resistance_t maxResistance() override { return max_resistance; } + + minmax resistanceLimits() override {return this->bikeResistanceLimits;} bool inclinationAvailableByHardware() override; bool connected() override; private: - resistance_t max_resistance = 16; - uint16_t wattsFromResistance(resistance_t resistance); + uint16_t wattsFromResistance(double resistance) override; double GetDistanceFromPacket(QByteArray packet); QTime GetElapsedFromPacket(QByteArray packet); void btinit(); @@ -71,6 +70,7 @@ class proformbike : public bike { QDateTime lastRefreshCharacteristicChanged = QDateTime::currentDateTime(); uint8_t firstStateChanged = 0; uint16_t m_watts = 0; + minmax bikeResistanceLimits{1,16}; bool initDone = false; bool initRequest = false; diff --git a/src/devices/proformtelnetbike/proformtelnetbike.cpp b/src/devices/proformtelnetbike/proformtelnetbike.cpp index 1802b3a58..08617a40c 100644 --- a/src/devices/proformtelnetbike/proformtelnetbike.cpp +++ b/src/devices/proformtelnetbike/proformtelnetbike.cpp @@ -109,35 +109,13 @@ void proformtelnetbike::writeCharacteristic(uint8_t *data, uint8_t data_len, con loop.exec(); }*/ -resistance_t proformtelnetbike::resistanceFromPowerRequest(uint16_t power) { - qDebug() << QStringLiteral("resistanceFromPowerRequest") << Cadence.value(); - QSettings settings; - - double watt_gain = settings.value(QZSettings::watt_gain, QZSettings::default_watt_gain).toDouble(); - double watt_offset = settings.value(QZSettings::watt_offset, QZSettings::default_watt_offset).toDouble(); - - for (resistance_t i = 1; i < max_resistance; i++) { - if (((wattsFromResistance(i) * watt_gain) + watt_offset) <= power && - ((wattsFromResistance(i + 1) * watt_gain) + watt_offset) >= power) { - qDebug() << QStringLiteral("resistanceFromPowerRequest") - << ((wattsFromResistance(i) * watt_gain) + watt_offset) - << ((wattsFromResistance(i + 1) * watt_gain) + watt_offset) << power; - return i; - } - } - if (power < ((wattsFromResistance(1) * watt_gain) + watt_offset)) - return 1; - else - return max_resistance; -} - -uint16_t proformtelnetbike::wattsFromResistance(resistance_t resistance) { +uint16_t proformtelnetbike::wattsFromResistance(double resistance) { if (currentCadence().value() == 0) return 0; - switch (resistance) { + switch ((resistance_t)resistance) { case 0: case 1: // -13.5 + 0.999x + 0.00993x² diff --git a/src/devices/proformtelnetbike/proformtelnetbike.h b/src/devices/proformtelnetbike/proformtelnetbike.h index 1c8d42e3f..59e66021d 100644 --- a/src/devices/proformtelnetbike/proformtelnetbike.h +++ b/src/devices/proformtelnetbike/proformtelnetbike.h @@ -48,18 +48,16 @@ class proformtelnetbike : public bike { proformtelnetbike(bool noWriteResistance, bool noHeartService, uint8_t bikeResistanceOffset, double bikeResistanceGain); resistance_t pelotonToBikeResistance(int pelotonResistance) override; - resistance_t resistanceFromPowerRequest(uint16_t power) override; - resistance_t maxResistance() override { return max_resistance; } + + minmax resistanceLimits() override {return minmax(-20,100);} bool inclinationAvailableByHardware() override; bool connected() override; private: QTelnet telnet; - resistance_t max_resistance = 100; - resistance_t min_resistance = -20; double max_incline_supported = 20; void connectToDevice(); - uint16_t wattsFromResistance(resistance_t resistance); + uint16_t wattsFromResistance(double resistance) override; double GetDistanceFromPacket(QByteArray packet); QTime GetElapsedFromPacket(QByteArray packet); void btinit(); diff --git a/src/devices/proformwifibike/proformwifibike.cpp b/src/devices/proformwifibike/proformwifibike.cpp index cc6eaebbc..f901b2a14 100644 --- a/src/devices/proformwifibike/proformwifibike.cpp +++ b/src/devices/proformwifibike/proformwifibike.cpp @@ -112,28 +112,7 @@ void proformwifibike::writeCharacteristic(uint8_t *data, uint8_t data_len, const loop.exec(); }*/ -resistance_t proformwifibike::resistanceFromPowerRequest(uint16_t power) { - qDebug() << QStringLiteral("resistanceFromPowerRequest") << Cadence.value(); - QSettings settings; - - double watt_gain = settings.value(QZSettings::watt_gain, QZSettings::default_watt_gain).toDouble(); - double watt_offset = settings.value(QZSettings::watt_offset, QZSettings::default_watt_offset).toDouble(); - - for (resistance_t i = 1; i < max_resistance; i++) { - if (((wattsFromResistance(i) * watt_gain) + watt_offset) <= power && - ((wattsFromResistance(i + 1) * watt_gain) + watt_offset) >= power) { - qDebug() << QStringLiteral("resistanceFromPowerRequest") - << ((wattsFromResistance(i) * watt_gain) + watt_offset) - << ((wattsFromResistance(i + 1) * watt_gain) + watt_offset) << power; - return i; - } - } - if (power < ((wattsFromResistance(1) * watt_gain) + watt_offset)) - return 1; - else - return max_resistance; -} uint16_t proformwifibike::wattsFromResistance(resistance_t resistance) { @@ -246,10 +225,8 @@ void proformwifibike::innerWriteResistance() { static QString last_mode = "MANUAL"; if (requestResistance != -1) { - if (requestResistance > max_resistance) { - requestResistance = max_resistance; - } else if (requestResistance < min_resistance) { - requestResistance = min_resistance; + if(!this->resistanceLimits().contains(requestResistance)) { + requestResistance = this->resistanceLimits().clip(requestResistance); } else if (requestResistance == 0) { requestResistance = 1; } diff --git a/src/devices/proformwifibike/proformwifibike.h b/src/devices/proformwifibike/proformwifibike.h index 96416be8e..33e82b3c3 100644 --- a/src/devices/proformwifibike/proformwifibike.h +++ b/src/devices/proformwifibike/proformwifibike.h @@ -45,15 +45,12 @@ class proformwifibike : public bike { proformwifibike(bool noWriteResistance, bool noHeartService, uint8_t bikeResistanceOffset, double bikeResistanceGain); resistance_t pelotonToBikeResistance(int pelotonResistance) override; - resistance_t resistanceFromPowerRequest(uint16_t power) override; - resistance_t maxResistance() override { return max_resistance; } + minmax resistanceLimits() override {return minmax(-20,100);} bool inclinationAvailableByHardware() override; bool connected() override; private: QWebSocket websocket; - resistance_t max_resistance = 100; - resistance_t min_resistance = -20; double max_incline_supported = 20; void connectToDevice(); uint16_t wattsFromResistance(resistance_t resistance); diff --git a/src/devices/renphobike/renphobike.cpp b/src/devices/renphobike/renphobike.cpp index b84e10f29..7b2074b25 100644 --- a/src/devices/renphobike/renphobike.cpp +++ b/src/devices/renphobike/renphobike.cpp @@ -136,10 +136,7 @@ void renphobike::update() { // if zwift is connected we have to avoid to send resistance to the bike if ((virtualBike && !virtualBike->ftmsDeviceConnected()) || !virtualBike) { if (requestResistance != -1) { - if (requestResistance > max_resistance) - requestResistance = max_resistance; - else if (requestResistance == 0) - requestResistance = 1; + requestResistance = this->resistanceLimits().clip(requestResistance); lastRequestResistance = lastRawRequestedResistanceValue; debug("writing resistance " + QString::number(requestResistance)); @@ -688,7 +685,7 @@ void renphobike::deviceDiscovered(const QBluetoothDeviceInfo &device) { } resistance_t renphobike::pelotonToBikeResistance(int pelotonResistance) { - for (resistance_t i = 1; i < max_resistance - 1; i++) { + for (resistance_t i = 1, max = this->resistanceLimits().max(); i < max - 1; i++) { if (bikeResistanceToPeloton(i) <= pelotonResistance && bikeResistanceToPeloton(i + 1) >= pelotonResistance) return i; } diff --git a/src/devices/renphobike/renphobike.h b/src/devices/renphobike/renphobike.h index 99874ba59..89b648acc 100644 --- a/src/devices/renphobike/renphobike.h +++ b/src/devices/renphobike/renphobike.h @@ -39,10 +39,9 @@ class renphobike : public bike { resistance_t pelotonToBikeResistance(int pelotonResistance) override; // uint8_t resistanceFromPowerRequest(uint16_t power); bool connected() override; - resistance_t maxResistance() override { return max_resistance; } + minmax resistanceLimits() override {return minmax(1,80);} private: - const resistance_t max_resistance = 80; double bikeResistanceToPeloton(double resistance); void writeCharacteristic(uint8_t *data, uint8_t data_len, QString info, bool disable_log = false, bool wait_for_response = false); diff --git a/src/devices/rower.h b/src/devices/rower.h index 048bee07e..6af81d786 100644 --- a/src/devices/rower.h +++ b/src/devices/rower.h @@ -37,8 +37,8 @@ class rower : public bluetoothdevice { void setPaused(bool p) override; QTime speedToPace(double Speed); void setGears(double d); - double gears(); - + double gears(); + minmax resistanceLimits() override { return minmax(0, this->maxResistance()); } public slots: void changeResistance(resistance_t res) override; virtual void changeCadence(int16_t cad); @@ -83,6 +83,8 @@ class rower : public bluetoothdevice { }; QList speedLast500mValues; + + virtual resistance_t maxResistance() { return 100; } }; #endif // ROWER_H diff --git a/src/devices/schwinn170bike/schwinn170bike.cpp b/src/devices/schwinn170bike/schwinn170bike.cpp index 820f7553f..615cc80a1 100644 --- a/src/devices/schwinn170bike/schwinn170bike.cpp +++ b/src/devices/schwinn170bike/schwinn170bike.cpp @@ -80,11 +80,7 @@ void schwinn170bike::update() { } if (requestResistance != -1) { - if (requestResistance > max_resistance) - requestResistance = max_resistance; - else if (requestResistance == 0) { - requestResistance = 1; - } + requestResistance = this->resistanceLimits().clip(requestResistance); if (requestResistance != currentResistance().value()) { emit debug(QStringLiteral("writing resistance ") + QString::number(requestResistance)); diff --git a/src/devices/schwinn170bike/schwinn170bike.h b/src/devices/schwinn170bike/schwinn170bike.h index 27bcce285..e6b5cf2c6 100644 --- a/src/devices/schwinn170bike/schwinn170bike.h +++ b/src/devices/schwinn170bike/schwinn170bike.h @@ -42,7 +42,7 @@ class schwinn170bike : public bike { double bikeResistanceGain); resistance_t pelotonToBikeResistance(int pelotonResistance) override; bool ergManagedBySS2K() override { return true; } - resistance_t maxResistance() override { return max_resistance; } + minmax resistanceLimits() override {return minmax(1,100);} bool connected() override; private: @@ -67,7 +67,6 @@ class schwinn170bike : public bike { bool noWriteResistance = false; bool noHeartService = false; - const resistance_t max_resistance = 100; uint8_t bikeResistanceOffset = 4; double bikeResistanceGain = 1.0; diff --git a/src/devices/schwinnic4bike/schwinnic4bike.cpp b/src/devices/schwinnic4bike/schwinnic4bike.cpp index 72e1d928e..a62498d6d 100644 --- a/src/devices/schwinnic4bike/schwinnic4bike.cpp +++ b/src/devices/schwinnic4bike/schwinnic4bike.cpp @@ -81,11 +81,7 @@ void schwinnic4bike::update() { } if (requestResistance != -1) { - if (requestResistance > max_resistance) - requestResistance = max_resistance; - else if (requestResistance == 0) { - requestResistance = 1; - } + requestResistance = this->resistanceLimits().clip(requestResistance); if (requestResistance != currentResistance().value()) { emit debug(QStringLiteral("writing resistance ") + QString::number(requestResistance)); diff --git a/src/devices/schwinnic4bike/schwinnic4bike.h b/src/devices/schwinnic4bike/schwinnic4bike.h index 707b15075..921c0f1e0 100644 --- a/src/devices/schwinnic4bike/schwinnic4bike.h +++ b/src/devices/schwinnic4bike/schwinnic4bike.h @@ -40,7 +40,7 @@ class schwinnic4bike : public bike { schwinnic4bike(bool noWriteResistance, bool noHeartService); resistance_t pelotonToBikeResistance(int pelotonResistance) override; bool ergManagedBySS2K() override { return true; } - resistance_t maxResistance() override { return max_resistance; } + minmax resistanceLimits() override {return minmax(1,100);} bool connected() override; private: @@ -66,8 +66,6 @@ class schwinnic4bike : public bike { bool noWriteResistance = false; bool noHeartService = false; - const resistance_t max_resistance = 100; - metric ResistanceFromFTMSAccessory; #ifdef Q_OS_IOS diff --git a/src/devices/skandikawiribike/skandikawiribike.cpp b/src/devices/skandikawiribike/skandikawiribike.cpp index a1a3753c6..b56e50dbc 100644 --- a/src/devices/skandikawiribike/skandikawiribike.cpp +++ b/src/devices/skandikawiribike/skandikawiribike.cpp @@ -102,11 +102,7 @@ void skandikawiribike::update() { } if (requestResistance != -1) { - if (requestResistance > 32) { - requestResistance = 32; - } else if (requestResistance < 1) { - requestResistance = 1; - } + requestResistance = this->resistanceLimits().clip(requestResistance); if (requestResistance != currentResistance().value()) { emit debug(QStringLiteral("writing resistance ") + QString::number(requestResistance)); diff --git a/src/devices/skandikawiribike/skandikawiribike.h b/src/devices/skandikawiribike/skandikawiribike.h index e7809e961..ee5d33e3b 100644 --- a/src/devices/skandikawiribike/skandikawiribike.h +++ b/src/devices/skandikawiribike/skandikawiribike.h @@ -39,6 +39,7 @@ class skandikawiribike : public bike { double bikeResistanceGain); ~skandikawiribike(); bool connected() override; + minmax resistanceLimits() override {return minmax(1,32);} private: double GetSpeedFromPacket(const QByteArray &packet); diff --git a/src/devices/smartspin2k/smartspin2k.cpp b/src/devices/smartspin2k/smartspin2k.cpp index 2c2cdd7e3..3404735c5 100644 --- a/src/devices/smartspin2k/smartspin2k.cpp +++ b/src/devices/smartspin2k/smartspin2k.cpp @@ -22,7 +22,7 @@ smartspin2k::smartspin2k(bool noWriteResistance, bool noHeartService, resistance QSettings settings; m_watt.setType(metric::METRIC_WATT); Speed.setType(metric::METRIC_SPEED); - this->max_resistance = max_resistance; + this->bikeResistanceLimits = minmax(1,max_resistance); this->parentDevice = parentDevice; refresh = new QTimer(this); this->noWriteResistance = noWriteResistance; @@ -298,12 +298,7 @@ void smartspin2k::update() { } if (requestResistance != -1) { - if (requestResistance > max_resistance) { - requestResistance = max_resistance; - } // TODO, use the bluetooth value - else if (requestResistance == 0) { - requestResistance = 1; - } + requestResistance = this->resistanceLimits().clip(requestResistance); // TODO, use the bluetooth value if (requestResistance != currentResistance().value()) { emit debug(QStringLiteral("writing resistance ") + QString::number(requestResistance)); diff --git a/src/devices/smartspin2k/smartspin2k.h b/src/devices/smartspin2k/smartspin2k.h index f25c60640..3bfa72f7f 100644 --- a/src/devices/smartspin2k/smartspin2k.h +++ b/src/devices/smartspin2k/smartspin2k.h @@ -42,6 +42,8 @@ class smartspin2k : public bike { smartspin2k(bool noWriteResistance, bool noHeartService, resistance_t max_resistance, bike *parentDevice); bool connected() override; + minmax resistanceLimits() override {return this->bikeResistanceLimits;} + private: #define max_calibration_samples 4 void writeCharacteristic(uint8_t *data, uint8_t data_len, const QString &info, bool disable_log = false, @@ -67,6 +69,7 @@ class smartspin2k : public bike { QByteArray lastPacket; QDateTime lastRefreshCharacteristicChanged = QDateTime::currentDateTime(); uint8_t firstStateChanged = 0; + minmax bikeResistanceLimits {1,100}; bool initDone = false; bool initRequest = false; @@ -79,7 +82,6 @@ class smartspin2k : public bike { resistance_t lastResistance; resistance_t lastRequestResistance; - resistance_t max_resistance; double slope = 0.0; double intercept = 0.0; diff --git a/src/devices/snodebike/snodebike.cpp b/src/devices/snodebike/snodebike.cpp index 19760df18..cadd39f53 100644 --- a/src/devices/snodebike/snodebike.cpp +++ b/src/devices/snodebike/snodebike.cpp @@ -80,11 +80,7 @@ void snodebike::update() { } if (requestResistance != -1) { - if (requestResistance > 15) { - requestResistance = 15; - } else if (requestResistance == 0) { - requestResistance = 1; - } + requestResistance = this->resistanceLimits().clip(requestResistance); if (requestResistance != currentResistance().value()) { emit debug(QStringLiteral("writing resistance ") + QString::number(requestResistance)); diff --git a/src/devices/snodebike/snodebike.h b/src/devices/snodebike/snodebike.h index fb29922b8..3cd5fa2fa 100644 --- a/src/devices/snodebike/snodebike.h +++ b/src/devices/snodebike/snodebike.h @@ -39,6 +39,7 @@ class snodebike : public bike { public: snodebike(bool noWriteResistance, bool noHeartService); bool connected() override; + minmax resistanceLimits() override {return minmax(1,15);} private: void writeCharacteristic(uint8_t *data, uint8_t data_len, QString info, bool disable_log = false, diff --git a/src/devices/solebike/solebike.cpp b/src/devices/solebike/solebike.cpp index acb9af093..07b117e0e 100644 --- a/src/devices/solebike/solebike.cpp +++ b/src/devices/solebike/solebike.cpp @@ -167,10 +167,7 @@ void solebike::update() { } if (requestResistance != -1) { - if (requestResistance > max_resistance) - requestResistance = max_resistance; - else if (requestResistance <= 0) - requestResistance = 1; + requestResistance = this->resistanceLimits().clip(requestResistance); if (requestResistance != currentResistance().value()) { qDebug() << QStringLiteral("writing resistance ") + QString::number(requestResistance); @@ -198,17 +195,6 @@ void solebike::serviceDiscovered(const QBluetoothUuid &gatt) { qDebug() << QStringLiteral("serviceDiscovered ") + gatt.toString(); } -resistance_t solebike::pelotonToBikeResistance(int pelotonResistance) { - for (resistance_t i = 1; i < max_resistance; i++) { - if (bikeResistanceToPeloton(i) <= pelotonResistance && bikeResistanceToPeloton(i + 1) >= pelotonResistance) { - return i; - } - } - if (pelotonResistance < bikeResistanceToPeloton(1)) - return 1; - else - return max_resistance; -} double solebike::bikeResistanceToPeloton(double resistance) { // 0,0097x3 - 0,4972x2 + 10,126x - 37,08 diff --git a/src/devices/solebike/solebike.h b/src/devices/solebike/solebike.h index 29772889b..614347d42 100644 --- a/src/devices/solebike/solebike.h +++ b/src/devices/solebike/solebike.h @@ -36,14 +36,12 @@ class solebike : public bike { Q_OBJECT public: solebike(bool noWriteResistance, bool noHeartService, uint8_t bikeResistanceOffset, double bikeResistanceGain); - resistance_t pelotonToBikeResistance(int pelotonResistance) override; - resistance_t maxResistance() override { return max_resistance; } + minmax resistanceLimits() override {return minmax(1,40);} bool connected() override; private: bool r92 = false; - const resistance_t max_resistance = 40; - double bikeResistanceToPeloton(double resistance); + double bikeResistanceToPeloton(double resistance) override; double GetDistanceFromPacket(const QByteArray &packet); double GetSpeedFromPacket(const QByteArray &packet); double GetWattFromPacket(const QByteArray &packet); diff --git a/src/devices/sportsplusbike/sportsplusbike.cpp b/src/devices/sportsplusbike/sportsplusbike.cpp index 3b32ca1d3..597a3153e 100644 --- a/src/devices/sportsplusbike/sportsplusbike.cpp +++ b/src/devices/sportsplusbike/sportsplusbike.cpp @@ -71,7 +71,7 @@ void sportsplusbike::forceResistance(resistance_t requestResistance) { } resistance_t sportsplusbike::pelotonToBikeResistance(int pelotonResistance) { - return (pelotonResistance * max_resistance) / 100; + return (pelotonResistance * this->resistanceLimits().max()) / 100; } void sportsplusbike::update() { @@ -103,12 +103,9 @@ void sportsplusbike::update() { QSettings settings; uint8_t noOpData[] = {0x20, 0x01, 0x09, 0x00, 0x2a}; - if (requestResistance < 0) { - requestResistance = 0; - } - if (requestResistance > max_resistance) { - requestResistance = max_resistance; - } + + requestResistance = this->resistanceLimits().clip(requestResistance); + noOpData[2] = requestResistance; noOpData[4] = (0x21 + requestResistance); writeCharacteristic((uint8_t *)noOpData, sizeof(noOpData), QStringLiteral("noOp"), false, true); diff --git a/src/devices/sportsplusbike/sportsplusbike.h b/src/devices/sportsplusbike/sportsplusbike.h index b9436a7b7..27ada5ebd 100644 --- a/src/devices/sportsplusbike/sportsplusbike.h +++ b/src/devices/sportsplusbike/sportsplusbike.h @@ -35,6 +35,8 @@ class sportsplusbike : public bike { resistance_t pelotonToBikeResistance(int pelotonResistance) override; bool connected() override; + minmax resistanceLimits() override {return minmax(0,24);} + private: double GetSpeedFromPacket(const QByteArray &packet); double GetKcalFromPacket(const QByteArray &packet); @@ -75,8 +77,6 @@ class sportsplusbike : public bike { bool carefitness_bike = false; - const resistance_t max_resistance = 24; - signals: void disconnected(); void debug(QString string); diff --git a/src/devices/sportstechbike/sportstechbike.cpp b/src/devices/sportstechbike/sportstechbike.cpp index 361a68391..9a1f44595 100644 --- a/src/devices/sportstechbike/sportstechbike.cpp +++ b/src/devices/sportstechbike/sportstechbike.cpp @@ -99,12 +99,7 @@ void sportstechbike::update() { QSettings settings; uint8_t noOpData[] = {0xf2, 0xc3, 0x07, 0x04, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xbe}; - if (requestResistance < 0) { - requestResistance = 0; - } - if (requestResistance > 23) { - requestResistance = 23; - } + requestResistance = this->resistanceLimits().clip(requestResistance); noOpData[4] = requestResistance; noOpData[10] += requestResistance; writeCharacteristic((uint8_t *)noOpData, sizeof(noOpData), QStringLiteral("noOp"), false, true); @@ -439,21 +434,3 @@ uint16_t sportstechbike::wattsFromResistance(double resistance) { return power; } -resistance_t sportstechbike::resistanceFromPowerRequest(uint16_t power) { - qDebug() << QStringLiteral("resistanceFromPowerRequest") << Cadence.value(); - - if (Cadence.value() == 0) - return 1; - - for (resistance_t i = 1; i < maxResistance(); i++) { - if (wattsFromResistance(i) <= power && wattsFromResistance(i + 1) >= power) { - qDebug() << QStringLiteral("resistanceFromPowerRequest") << wattsFromResistance(i) - << wattsFromResistance(i + 1) << power; - return i; - } - } - if (power < wattsFromResistance(1)) - return 1; - else - return maxResistance(); -} \ No newline at end of file diff --git a/src/devices/sportstechbike/sportstechbike.h b/src/devices/sportstechbike/sportstechbike.h index d973805c1..5731ef1e1 100644 --- a/src/devices/sportstechbike/sportstechbike.h +++ b/src/devices/sportstechbike/sportstechbike.h @@ -32,9 +32,7 @@ class sportstechbike : public bike { public: sportstechbike(bool noWriteResistance, bool noHeartService); bool connected() override; - resistance_t maxResistance() override { return 24; } - resistance_t resistanceFromPowerRequest(uint16_t power) override; - + minmax resistanceLimits() override {return minmax(0,24);} private: double GetSpeedFromPacket(const QByteArray &packet); double GetResistanceFromPacket(const QByteArray &packet); diff --git a/src/devices/stagesbike/stagesbike.cpp b/src/devices/stagesbike/stagesbike.cpp index 9a86d207e..cfe1b0e82 100644 --- a/src/devices/stagesbike/stagesbike.cpp +++ b/src/devices/stagesbike/stagesbike.cpp @@ -82,11 +82,7 @@ void stagesbike::update() { } if (requestResistance != -1) { - if (requestResistance > 100) { - requestResistance = 100; - } else if (requestResistance == 0) { - requestResistance = 1; - } + requestResistance = this->resistanceLimits().clip(requestResistance); if (requestResistance != currentResistance().value()) { emit debug(QStringLiteral("writing resistance ") + QString::number(requestResistance)); diff --git a/src/devices/stagesbike/stagesbike.h b/src/devices/stagesbike/stagesbike.h index 71fed7976..c0f29ae4e 100644 --- a/src/devices/stagesbike/stagesbike.h +++ b/src/devices/stagesbike/stagesbike.h @@ -38,7 +38,7 @@ class stagesbike : public bike { stagesbike(bool noWriteResistance, bool noHeartService, bool noVirtualDevice); resistance_t pelotonToBikeResistance(int pelotonResistance) override; bool connected() override; - resistance_t maxResistance() override { return 100; } + minmax resistanceLimits() override {return minmax(1,100);} bool ergManagedBySS2K() override { return true; } private: diff --git a/src/devices/tacxneo2/tacxneo2.cpp b/src/devices/tacxneo2/tacxneo2.cpp index f00edf42d..d025c795b 100644 --- a/src/devices/tacxneo2/tacxneo2.cpp +++ b/src/devices/tacxneo2/tacxneo2.cpp @@ -586,18 +586,6 @@ void tacxneo2::controllerStateChanged(QLowEnergyController::ControllerState stat } } -resistance_t tacxneo2::pelotonToBikeResistance(int pelotonResistance) { - for (resistance_t i = 0; i < max_resistance; i++) { - if (bikeResistanceToPeloton(i) <= pelotonResistance && bikeResistanceToPeloton(i + 1) > pelotonResistance) { - return i; - } - } - if (pelotonResistance < bikeResistanceToPeloton(1)) - return 0; - else - return max_resistance; -} - double tacxneo2::bikeResistanceToPeloton(double resistance) { QSettings settings; bool tacx_neo2_peloton = diff --git a/src/devices/tacxneo2/tacxneo2.h b/src/devices/tacxneo2/tacxneo2.h index 4dd512e51..4a62e501f 100644 --- a/src/devices/tacxneo2/tacxneo2.h +++ b/src/devices/tacxneo2/tacxneo2.h @@ -38,7 +38,8 @@ class tacxneo2 : public bike { tacxneo2(bool noWriteResistance, bool noHeartService); void changePower(int32_t power) override; bool connected() override; - resistance_t pelotonToBikeResistance(int pelotonResistance) override; + + minmax resistanceLimits() override {return minmax(0,100);} private: void writeCharacteristic(uint8_t *data, uint8_t data_len, const QString &info, bool disable_log = false, @@ -46,12 +47,10 @@ class tacxneo2 : public bike { void startDiscover(); void forceInclination(double inclination); uint16_t watts() override; - double bikeResistanceToPeloton(double resistance); + double bikeResistanceToPeloton(double resistance) override; QTimer *refresh; - const int max_resistance = 100; - QList gattCommunicationChannelService; QLowEnergyCharacteristic gattWriteCharControlPointId; QLowEnergyCharacteristic gattWriteCharCustomId; diff --git a/src/devices/trxappgateusbbike/trxappgateusbbike.cpp b/src/devices/trxappgateusbbike/trxappgateusbbike.cpp index 9f5f77628..866ac82bf 100644 --- a/src/devices/trxappgateusbbike/trxappgateusbbike.cpp +++ b/src/devices/trxappgateusbbike/trxappgateusbbike.cpp @@ -176,11 +176,8 @@ void trxappgateusbbike::update() { writeCharacteristic((uint8_t *)noOpData, sizeof(noOpData), QStringLiteral("noOp"), false, true); } if (requestResistance != -1) { - if (requestResistance > 32) { - requestResistance = 32; - } else if (requestResistance < 1) { - requestResistance = 1; - } + requestResistance = this->resistanceLimits().clip(requestResistance); + if (requestResistance != currentResistance().value()) { emit debug(QStringLiteral("writing resistance ") + QString::number(requestResistance)); @@ -1177,27 +1174,4 @@ uint16_t trxappgateusbbike::wattsFromResistance(double resistance) { } } -resistance_t trxappgateusbbike::resistanceFromPowerRequest(uint16_t power) { - //QSettings settings; - //bool toorx_srx_3500 = settings.value(QZSettings::toorx_srx_3500, QZSettings::default_toorx_srx_3500).toBool(); - /*if(toorx_srx_3500)*/ { - qDebug() << QStringLiteral("resistanceFromPowerRequest") << Cadence.value(); - if (Cadence.value() == 0) - return 1; - - for (resistance_t i = 1; i < maxResistance(); i++) { - if (wattsFromResistance(i) <= power && wattsFromResistance(i + 1) >= power) { - qDebug() << QStringLiteral("resistanceFromPowerRequest") << wattsFromResistance(i) - << wattsFromResistance(i + 1) << power; - return i; - } - } - if (power < wattsFromResistance(1)) - return 1; - else - return maxResistance(); - } /*else { - return power / 10; - }*/ -} diff --git a/src/devices/trxappgateusbbike/trxappgateusbbike.h b/src/devices/trxappgateusbbike/trxappgateusbbike.h index 9401d5e41..c8951fa40 100644 --- a/src/devices/trxappgateusbbike/trxappgateusbbike.h +++ b/src/devices/trxappgateusbbike/trxappgateusbbike.h @@ -38,8 +38,7 @@ class trxappgateusbbike : public bike { trxappgateusbbike(bool noWriteResistance, bool noHeartService, uint8_t bikeResistanceOffset, double bikeResistanceGain); bool connected() override; - resistance_t maxResistance() override { return 32; } - resistance_t resistanceFromPowerRequest(uint16_t power) override; + minmax resistanceLimits() override {return minmax(1,32);} private: double GetSpeedFromPacket(const QByteArray &packet); @@ -57,7 +56,7 @@ class trxappgateusbbike : public bike { double GetWattFromPacket(const QByteArray &packet); double GetWattFromPacketFytter(const QByteArray &packet); double GetCadenceFromPacket(const QByteArray &packet); - uint16_t wattsFromResistance(double resistance); + uint16_t wattsFromResistance(double resistance) override; QTimer *refresh; diff --git a/src/devices/ultrasportbike/ultrasportbike.cpp b/src/devices/ultrasportbike/ultrasportbike.cpp index c38e4761b..f8c638f74 100644 --- a/src/devices/ultrasportbike/ultrasportbike.cpp +++ b/src/devices/ultrasportbike/ultrasportbike.cpp @@ -107,10 +107,7 @@ void ultrasportbike::update() { } if (requestResistance != -1) { - if (requestResistance > max_resistance) - requestResistance = max_resistance; - else if (requestResistance <= 0) - requestResistance = 1; + requestResistance = this->resistanceLimits().clip(requestResistance); if (requestResistance != currentResistance().value()) { qDebug() << QStringLiteral("writing resistance ") + QString::number(requestResistance); @@ -137,17 +134,6 @@ void ultrasportbike::serviceDiscovered(const QBluetoothUuid &gatt) { qDebug() << QStringLiteral("serviceDiscovered ") + gatt.toString(); } -resistance_t ultrasportbike::pelotonToBikeResistance(int pelotonResistance) { - for (resistance_t i = 1; i < max_resistance; i++) { - if (bikeResistanceToPeloton(i) <= pelotonResistance && bikeResistanceToPeloton(i + 1) >= pelotonResistance) { - return i; - } - } - if (pelotonResistance < bikeResistanceToPeloton(1)) - return 1; - else - return max_resistance; -} double ultrasportbike::bikeResistanceToPeloton(double resistance) { // 0,0097x3 - 0,4972x2 + 10,126x - 37,08 diff --git a/src/devices/ultrasportbike/ultrasportbike.h b/src/devices/ultrasportbike/ultrasportbike.h index 091c41980..894928322 100644 --- a/src/devices/ultrasportbike/ultrasportbike.h +++ b/src/devices/ultrasportbike/ultrasportbike.h @@ -38,14 +38,13 @@ class ultrasportbike : public bike { public: ultrasportbike(bool noWriteResistance, bool noHeartService, uint8_t bikeResistanceOffset, double bikeResistanceGain); - resistance_t pelotonToBikeResistance(int pelotonResistance) override; - resistance_t maxResistance() override { return max_resistance; } + + minmax resistanceLimits() override {return minmax(1,40);} bool connected() override; private: bool r92 = false; - const resistance_t max_resistance = 40; - double bikeResistanceToPeloton(double resistance); + double bikeResistanceToPeloton(double resistance) override; double GetWattFromPacket(const QByteArray &packet); void btinit(); void writeCharacteristic(uint8_t *data, uint8_t data_len, const QString &info, bool disable_log = false, diff --git a/src/devices/wahookickrsnapbike/wahookickrsnapbike.cpp b/src/devices/wahookickrsnapbike/wahookickrsnapbike.cpp index 69bba6a91..550b14e2f 100644 --- a/src/devices/wahookickrsnapbike/wahookickrsnapbike.cpp +++ b/src/devices/wahookickrsnapbike/wahookickrsnapbike.cpp @@ -236,11 +236,7 @@ void wahookickrsnapbike::update() { } lastGearValue = gears(); } else if (requestResistance != -1 && KICKR_BIKE == false) { - if (requestResistance > 100) { - requestResistance = 100; - } else if (requestResistance == 0) { - requestResistance = 1; - } + requestResistance = this->resistanceLimits().clip(requestResistance); auto virtualBike = this->VirtualBike(); if (requestResistance != currentResistance().value() && @@ -824,4 +820,4 @@ void wahookickrsnapbike::inclinationChanged(double grade, double percentage) { bool wahookickrsnapbike::inclinationAvailableByHardware() { return KICKR_BIKE; -} \ No newline at end of file +} diff --git a/src/devices/wahookickrsnapbike/wahookickrsnapbike.h b/src/devices/wahookickrsnapbike/wahookickrsnapbike.h index 3d4ae1f53..b7dc9394c 100644 --- a/src/devices/wahookickrsnapbike/wahookickrsnapbike.h +++ b/src/devices/wahookickrsnapbike/wahookickrsnapbike.h @@ -40,7 +40,7 @@ class wahookickrsnapbike : public bike { double bikeResistanceGain); resistance_t pelotonToBikeResistance(int pelotonResistance) override; bool connected() override; - resistance_t maxResistance() override { return 100; } + minmax resistanceLimits() override {return minmax(1,100);} bool inclinationAvailableByHardware() override; enum OperationCode : uint8_t { diff --git a/src/devices/yesoulbike/yesoulbike.cpp b/src/devices/yesoulbike/yesoulbike.cpp index 27032d171..f34de6673 100644 --- a/src/devices/yesoulbike/yesoulbike.cpp +++ b/src/devices/yesoulbike/yesoulbike.cpp @@ -78,10 +78,7 @@ void yesoulbike::update() { } if (requestResistance != -1) { - if (requestResistance > 15) - requestResistance = 15; - else if (requestResistance == 0) - requestResistance = 1; + requestResistance = this->resistanceLimits().clip(requestResistance); if (requestResistance != currentResistance().value()) { emit debug(QStringLiteral("writing resistance ") + QString::number(requestResistance)); diff --git a/src/devices/yesoulbike/yesoulbike.h b/src/devices/yesoulbike/yesoulbike.h index 1090f01d5..84b54d47a 100644 --- a/src/devices/yesoulbike/yesoulbike.h +++ b/src/devices/yesoulbike/yesoulbike.h @@ -44,6 +44,8 @@ class yesoulbike : public bike { double bikeResistanceGain); bool connected() override; + minmax resistanceLimits() override {return minmax(1,15);} + private: double GetDistanceFromPacket(const QByteArray &packet); QTime GetElapsedFromPacket(QByteArray packet); diff --git a/src/minmax.cpp b/src/minmax.cpp new file mode 100644 index 000000000..b21b785d0 --- /dev/null +++ b/src/minmax.cpp @@ -0,0 +1,23 @@ +#include "minmax.h" + +template +const T minmax::max() { return this->_max; } + +template +const T minmax::min() { return this->_min; } + +template +minmax::minmax(const T min, const T max) : _max(max), _min(min) {} + +template +T minmax::clip(const T value) const { + T result = value; + if(value_min) result=_min; + else if(value>this->_max) result=_max; + return result; +} + +template +bool minmax::contains(const T value) const { + return value>=this->_min && value<=this->_max; +} diff --git a/src/minmax.h b/src/minmax.h new file mode 100644 index 000000000..5c7dd8d8a --- /dev/null +++ b/src/minmax.h @@ -0,0 +1,19 @@ +#ifndef MINMAX_H +#define MINMAX_H + +template +struct minmax { + private: + T _max, _min; + public: + const T max(); + const T min(); + + explicit minmax(const T min, const T max); + + T clip(const T value) const; + + bool contains(const T value) const; +}; + +#endif diff --git a/src/qdomyos-zwift.pri b/src/qdomyos-zwift.pri index 4533a2870..d0a8c872f 100755 --- a/src/qdomyos-zwift.pri +++ b/src/qdomyos-zwift.pri @@ -74,6 +74,7 @@ DEFINES += QT_DEPRECATED_WARNINGS IO_UNDER_QT SMTP_BUILD NOMINMAX SOURCES += \ $$PWD/devices/focustreadmill/focustreadmill.cpp \ $$PWD/devices/trxappgateusbelliptical/trxappgateusbelliptical.cpp \ + $$PWD/minmax.cpp \ QTelnet.cpp \ devices/bkoolbike/bkoolbike.cpp \ devices/csaferower/csafe.cpp \ @@ -290,6 +291,7 @@ HEADERS += \ $$PWD/devices/focustreadmill/focustreadmill.h \ $$PWD/devices/trxappgateusbelliptical/trxappgateusbelliptical.h \ $$PWD/ergtable.h \ + $$PWD/minmax.h \ QTelnet.h \ devices/bkoolbike/bkoolbike.h \ devices/csaferower/csafe.h \ diff --git a/tst/Erg/bikeergfunctions.cpp b/tst/Erg/bikeergfunctions.cpp index eeef02cfb..3d693c434 100644 --- a/tst/Erg/bikeergfunctions.cpp +++ b/tst/Erg/bikeergfunctions.cpp @@ -8,9 +8,9 @@ std::optional bikeergfunctions::getMaxCadence() const { return std::opt std::optional bikeergfunctions::getMinCadence() const { return 0; } -std::optional bikeergfunctions::getMaxResistance() const { return this->device->maxResistance(); } +std::optional bikeergfunctions::getMaxResistance() const { return this->device->resistanceLimits().max(); } -std::optional bikeergfunctions::getMinResistance() const { return 0; } +std::optional bikeergfunctions::getMinResistance() const { return this->device->resistanceLimits().min(); } double bikeergfunctions::getPower(const int32_t cadence, resistance_t resistance) { auto originalCadence = this->device->currentCadence().value(); From 2ab31e8bad196b4855ae5dd39041f861704dd8ef Mon Sep 17 00:00:00 2001 From: David Mason Date: Tue, 26 Mar 2024 00:01:42 +0000 Subject: [PATCH 05/13] #2174 avoid template in cpp --- src/minmax.cpp | 23 ----------------------- src/minmax.h | 17 ++++++++++++----- src/qdomyos-zwift.pri | 1 - 3 files changed, 12 insertions(+), 29 deletions(-) delete mode 100644 src/minmax.cpp diff --git a/src/minmax.cpp b/src/minmax.cpp deleted file mode 100644 index b21b785d0..000000000 --- a/src/minmax.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "minmax.h" - -template -const T minmax::max() { return this->_max; } - -template -const T minmax::min() { return this->_min; } - -template -minmax::minmax(const T min, const T max) : _max(max), _min(min) {} - -template -T minmax::clip(const T value) const { - T result = value; - if(value_min) result=_min; - else if(value>this->_max) result=_max; - return result; -} - -template -bool minmax::contains(const T value) const { - return value>=this->_min && value<=this->_max; -} diff --git a/src/minmax.h b/src/minmax.h index 5c7dd8d8a..f4fa49642 100644 --- a/src/minmax.h +++ b/src/minmax.h @@ -6,14 +6,21 @@ struct minmax { private: T _max, _min; public: - const T max(); - const T min(); + const T max() { return _max; } + const T min() { return _min; } - explicit minmax(const T min, const T max); + explicit minmax(const T min, const T max) : _max(max), _min(min) {} - T clip(const T value) const; + T clip(const T value) const { + T result = value; + if(value<_min) result=_min; + else if(value>_max) result=_max; + return result; + } - bool contains(const T value) const; + bool contains(const T value) const { + return value>=_min && value<=_max; + } }; #endif diff --git a/src/qdomyos-zwift.pri b/src/qdomyos-zwift.pri index d0a8c872f..35707903d 100755 --- a/src/qdomyos-zwift.pri +++ b/src/qdomyos-zwift.pri @@ -74,7 +74,6 @@ DEFINES += QT_DEPRECATED_WARNINGS IO_UNDER_QT SMTP_BUILD NOMINMAX SOURCES += \ $$PWD/devices/focustreadmill/focustreadmill.cpp \ $$PWD/devices/trxappgateusbelliptical/trxappgateusbelliptical.cpp \ - $$PWD/minmax.cpp \ QTelnet.cpp \ devices/bkoolbike/bkoolbike.cpp \ devices/csaferower/csafe.cpp \ From 6d76f987393edfd1ab2f19c367368fd99d9c0d87 Mon Sep 17 00:00:00 2001 From: David Mason Date: Tue, 26 Mar 2024 00:50:46 +0000 Subject: [PATCH 06/13] #2174 added bike cadence limits. - Disabled test for going below minimum cadence as there's no public way of setting a negative cadence. - Boundary tests mostly if not all passing. - Tests that resistanceFromPowerRequest inverts powerFromResistanceRequest still failing --- src/devices/bike.cpp | 6 +++--- src/devices/bike.h | 1 + tst/Devices/biketestsuite.h | 3 +++ tst/Erg/bikeergfunctions.cpp | 4 ++-- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/devices/bike.cpp b/src/devices/bike.cpp index 8523a08e7..5e67f0662 100644 --- a/src/devices/bike.cpp +++ b/src/devices/bike.cpp @@ -46,16 +46,16 @@ uint16_t bike::powerFromResistanceRequest(resistance_t requestResistance) { return 0; // this bike has resistance level to N.m so the formula is Power (kW) = Torque (N.m) x Speed (RPM) / 9.5488 - double cadence = RequestedCadence.value(); + double cadence = this->RequestedCadence.value(); if (cadence <= 0) cadence = Cadence.value(); - if(cadence <= 0) + if(cadence <= this->cadenceLimits().min()) return 0; requestResistance = minMaxR.clip(requestResistance); - return (requestResistance * cadence) / 9.5488; + return (requestResistance * this->cadenceLimits().clip(cadence)) / 9.5488; } void bike::changeRequestedPelotonResistance(int8_t resistance) { RequestedPelotonResistance = resistance; } diff --git a/src/devices/bike.h b/src/devices/bike.h index 2fde948e0..51e549acd 100644 --- a/src/devices/bike.h +++ b/src/devices/bike.h @@ -50,6 +50,7 @@ class bike : public bluetoothdevice { virtual bool inclinationAvailableByHardware(); bool ergModeSupportedAvailableByHardware() { return ergModeSupported; } + virtual minmax cadenceLimits() { return minmax(0, 250); } public Q_SLOTS: void changeResistance(resistance_t res) override; virtual void changeCadence(int16_t cad); diff --git a/tst/Devices/biketestsuite.h b/tst/Devices/biketestsuite.h index 424d37740..3ce2ff941 100644 --- a/tst/Devices/biketestsuite.h +++ b/tst/Devices/biketestsuite.h @@ -84,6 +84,9 @@ class BikeTestSuite : public testing::Test { TYPED_TEST_SUITE(BikeTestSuite, BikeTestDataTypes); TYPED_TEST(BikeTestSuite, TestPowerFunctionsMinCadence) { + + GTEST_SKIP() << "Disabled because no public way to set a negative cadence."; + this->test_powerFunctions_minCadence(); } diff --git a/tst/Erg/bikeergfunctions.cpp b/tst/Erg/bikeergfunctions.cpp index 3d693c434..8fa660582 100644 --- a/tst/Erg/bikeergfunctions.cpp +++ b/tst/Erg/bikeergfunctions.cpp @@ -4,9 +4,9 @@ void bikeergfunctions::setCadence(int32_t cadence) { this->device->cadenceSensor bikeergfunctions::bikeergfunctions(bike *device) : device(device) {} -std::optional bikeergfunctions::getMaxCadence() const { return std::optional{};} +std::optional bikeergfunctions::getMaxCadence() const { return this->device->cadenceLimits().max();} -std::optional bikeergfunctions::getMinCadence() const { return 0; } +std::optional bikeergfunctions::getMinCadence() const { return this->device->cadenceLimits().min(); } std::optional bikeergfunctions::getMaxResistance() const { return this->device->resistanceLimits().max(); } From 26d2aac0e714464057e8f16ae8a3c590739f479e Mon Sep 17 00:00:00 2001 From: David Mason Date: Tue, 26 Mar 2024 23:08:35 +0000 Subject: [PATCH 07/13] #2174 - adjusted power conversion test to force no watt gain - adjusted bike::resistanceFromPowerRequest to make it easier to see what it's comparing and to cache calculations - many power conversion tests now passing, but some strange values remain in the failing tests --- src/devices/bike.cpp | 29 ++++++++++++++++++----------- tst/Devices/biketestsuite.cpp | 16 ++++++++++------ 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/src/devices/bike.cpp b/src/devices/bike.cpp index 5e67f0662..357b954d2 100644 --- a/src/devices/bike.cpp +++ b/src/devices/bike.cpp @@ -138,20 +138,27 @@ resistance_t bike::resistanceFromPowerRequest(uint16_t power) { auto minMaxR = this->resistanceLimits(); - for (resistance_t i = minMaxR.min(); i < minMaxR.max(); i++) { - if (((wattsFromResistance(i) * watt_gain) + watt_offset) <= power && - ((wattsFromResistance(i + 1) * watt_gain) + watt_offset) >= power) { - qDebug() << QStringLiteral("resistanceFromPowerRequest") - << ((wattsFromResistance(i) * watt_gain) + watt_offset) - << ((wattsFromResistance(i + 1) * watt_gain) + watt_offset) << power; + uint16_t power0 = (wattsFromResistance(minMaxR.min()) * watt_gain) + watt_offset; + + // Is the requested power at or below the power of the minimum resistance the device provides? + if (power <= power0) + return minMaxR.min(); + + // Search from the 1st resistance level above minimum to the maximum + for (resistance_t i = 1 + minMaxR.min(); i < minMaxR.max(); i++) { + uint16_t power1 = wattsFromResistance(i)*watt_gain + watt_offset; + + if(power0 <= power && power1>=power) { + qDebug() << QStringLiteral("resistanceFromPowerRequest") << power0 << power1 << power; return i; } + + power0 = power1; } - if (power < ((wattsFromResistance(minMaxR.min()) * watt_gain) + watt_offset)) - return minMaxR.min(); - else - return minMaxR.max(); -} // in order to have something + + // requested power requires resistance beyond the maximum + return minMaxR.max(); +} void bike::cadenceSensor(uint8_t cadence) { Cadence.setValue(cadence); } void bike::powerSensor(uint16_t power) { m_watt.setValue(power, false); } diff --git a/tst/Devices/biketestsuite.cpp b/tst/Devices/biketestsuite.cpp index 247bbfefe..b8d51e9cc 100644 --- a/tst/Devices/biketestsuite.cpp +++ b/tst/Devices/biketestsuite.cpp @@ -131,6 +131,10 @@ void BikeTestSuite::test_powerFunctions_maxCadence() { GTEST_SKIP() << "No maximum cadence defined"; } + ASSERT_TRUE(this->testSettings.get_active()) << "TestSettings object should be active."; + this->testSettings.qsettings.setValue(QZSettings::watt_gain, 1.0); + this->testSettings.qsettings.setValue(QZSettings::watt_offset, 0.0); + // traverse the resistance edge checking the power is clipped to the values for the max and min cadence QString powerBeyondCadenceLimit = QStringLiteral("Power at R:%1 not bounded at %6 cadence (C:%2 RPM, P:%3W), (C:%4 RPM, P:%5W)"); @@ -159,20 +163,20 @@ void BikeTestSuite::test_powerFunctions_resistancePowerConversion() { for(uint16_t cadenceRPM : this->getCadenceSamples()) { uint16_t lastPower=0xFFFF; - for(resistance_t r=minResistance; r<=maxResistance; r++) + for(resistance_t resistanceToPower=minResistance; resistanceToPower<=maxResistance; resistanceToPower++) { - uint16_t power = erg->getPower(cadenceRPM, r); + uint16_t power = erg->getPower(cadenceRPM, resistanceToPower); // if this resistance reaches a new power level, check the inverse if(power!=lastPower) { lastPower = power; - resistance_t resistance = erg->getResistance(cadenceRPM, power); + resistance_t resistanceFromPower = erg->getResistance(cadenceRPM, power); - if(r!=resistance) { - uint16_t newPower = erg->getPower(cadenceRPM, resistance); + if(resistanceToPower!=resistanceFromPower) { + uint16_t newPower = erg->getPower(cadenceRPM, resistanceFromPower); - errors.append(unexpectedResistance.arg(r).arg(power).arg(cadenceRPM).arg(resistance).arg(newPower)); + errors.append(unexpectedResistance.arg(resistanceToPower).arg(power).arg(cadenceRPM).arg(resistanceFromPower).arg(newPower)); } } From 439570b71fb6a1f8e6215e2a809223ac3e4038bf Mon Sep 17 00:00:00 2001 From: David Mason Date: Wed, 27 Mar 2024 00:32:01 +0000 Subject: [PATCH 08/13] #2174 - fixed test settings / watt gain - adjusted some wattsFromResistance functions to avoid test timeouts - temporarily use subset of resistance values for power conversion test to avoid timeouts --- src/devices/schwinn170bike/schwinn170bike.cpp | 26 ++++++++++++------- src/devices/schwinn170bike/schwinn170bike.h | 2 +- src/devices/schwinnic4bike/schwinnic4bike.cpp | 10 ++++--- src/devices/stagesbike/stagesbike.cpp | 10 ++++--- .../wahookickrsnapbike/wahookickrsnapbike.cpp | 10 ++++--- tst/Devices/biketestsuite.cpp | 16 +++++++----- 6 files changed, 48 insertions(+), 26 deletions(-) diff --git a/src/devices/schwinn170bike/schwinn170bike.cpp b/src/devices/schwinn170bike/schwinn170bike.cpp index 615cc80a1..5b47873ca 100644 --- a/src/devices/schwinn170bike/schwinn170bike.cpp +++ b/src/devices/schwinn170bike/schwinn170bike.cpp @@ -523,23 +523,29 @@ resistance_t schwinn170bike::pelotonToBikeResistance(int pelotonResistance) { uint16_t schwinn170bike::wattsFromResistance(double resistance) { QSettings settings; - double ac = 0.01243107769; - double bc = 1.145964912; - double cc = -23.50977444; + constexpr double ac = 0.01243107769; + constexpr double bc = 1.145964912; + constexpr double cc = -23.50977444; - double ar = 0.1469553975; - double br = -5.841344538; - double cr = 97.62165482; + constexpr double ar = 0.1469553975; + constexpr double br = -5.841344538; + constexpr double cr = 97.62165482; + + constexpr double brSq = br*br; + + const double peloton_gain = settings.value(QZSettings::peloton_gain, QZSettings::default_peloton_gain).toDouble(); + const double peloton_offset = settings.value(QZSettings::peloton_offset, QZSettings::default_peloton_offset).toDouble(); + const double cadence = this->Cadence.value(), cadenceSq = cadence*cadence; for (uint16_t i = 1; i < 2000; i += 5) { double res = - (((sqrt(pow(br, 2.0) - + (((sqrt(brSq - 4.0 * ar * - (cr - ((double)i * 132.0 / (ac * pow(Cadence.value(), 2.0) + bc * Cadence.value() + cc)))) - + (cr - ((double)i * 132.0 / (ac * cadenceSq + bc * cadence + cc)))) - br) / (2.0 * ar)) * - settings.value(QZSettings::peloton_gain, QZSettings::default_peloton_gain).toDouble()) + - settings.value(QZSettings::peloton_offset, QZSettings::default_peloton_offset).toDouble(); + peloton_gain) + + peloton_offset; if (!isnan(res) && res >= resistance) { return i; diff --git a/src/devices/schwinn170bike/schwinn170bike.h b/src/devices/schwinn170bike/schwinn170bike.h index e6b5cf2c6..6bdface73 100644 --- a/src/devices/schwinn170bike/schwinn170bike.h +++ b/src/devices/schwinn170bike/schwinn170bike.h @@ -48,7 +48,7 @@ class schwinn170bike : public bike { private: void writeCharacteristic(QLowEnergyService *service, QLowEnergyCharacteristic characteristic, uint8_t *data, uint8_t data_len, QString info, bool disable_log = false, bool wait_for_response = false); - uint16_t wattsFromResistance(double resistance); + uint16_t wattsFromResistance(double resistance) override; void startDiscover(); uint16_t watts() override; diff --git a/src/devices/schwinnic4bike/schwinnic4bike.cpp b/src/devices/schwinnic4bike/schwinnic4bike.cpp index a62498d6d..5a8b12b1f 100644 --- a/src/devices/schwinnic4bike/schwinnic4bike.cpp +++ b/src/devices/schwinnic4bike/schwinnic4bike.cpp @@ -597,15 +597,19 @@ uint16_t schwinnic4bike::wattsFromResistance(double resistance) { double br = -5.841344538; double cr = 97.62165482; + const double peloton_gain = settings.value(QZSettings::peloton_gain, QZSettings::default_peloton_gain).toDouble(); + const double peloton_offset = settings.value(QZSettings::peloton_offset, QZSettings::default_peloton_offset).toDouble(); + const double cadence = this->Cadence.value(), cadenceSq = cadence*cadence; + for (uint16_t i = 1; i < 2000; i += 5) { double res = (((sqrt(pow(br, 2.0) - 4.0 * ar * - (cr - ((double)i * 132.0 / (ac * pow(Cadence.value(), 2.0) + bc * Cadence.value() + cc)))) - + (cr - ((double)i * 132.0 / (ac * cadenceSq + bc * cadence + cc)))) - br) / (2.0 * ar)) * - settings.value(QZSettings::peloton_gain, QZSettings::default_peloton_gain).toDouble()) + - settings.value(QZSettings::peloton_offset, QZSettings::default_peloton_offset).toDouble(); + peloton_gain) + + peloton_offset; if (!isnan(res) && res >= resistance) { return i; diff --git a/src/devices/stagesbike/stagesbike.cpp b/src/devices/stagesbike/stagesbike.cpp index cfe1b0e82..0a4de1bdc 100644 --- a/src/devices/stagesbike/stagesbike.cpp +++ b/src/devices/stagesbike/stagesbike.cpp @@ -141,15 +141,19 @@ uint16_t stagesbike::wattsFromResistance(double resistance) { double br = -5.841344538; double cr = 97.62165482; + const double peloton_gain = settings.value(QZSettings::peloton_gain, QZSettings::default_peloton_gain).toDouble(); + const double peloton_offset = settings.value(QZSettings::peloton_offset, QZSettings::default_peloton_offset).toDouble(); + const double cadence = this->Cadence.value(), cadenceSq = cadence*cadence; + for (uint16_t i = 1; i < 2000; i += 5) { double res = (((sqrt(pow(br, 2.0) - 4.0 * ar * - (cr - ((double)i * 132.0 / (ac * pow(Cadence.value(), 2.0) + bc * Cadence.value() + cc)))) - + (cr - ((double)i * 132.0 / (ac * cadenceSq + bc * cadence + cc)))) - br) / (2.0 * ar)) * - settings.value(QZSettings::peloton_gain, QZSettings::default_peloton_gain).toDouble()) + - settings.value(QZSettings::peloton_offset, QZSettings::default_peloton_offset).toDouble(); + peloton_gain) + + peloton_offset; if (!isnan(res) && res >= resistance) { return i; diff --git a/src/devices/wahookickrsnapbike/wahookickrsnapbike.cpp b/src/devices/wahookickrsnapbike/wahookickrsnapbike.cpp index 550b14e2f..3f9c7cc79 100644 --- a/src/devices/wahookickrsnapbike/wahookickrsnapbike.cpp +++ b/src/devices/wahookickrsnapbike/wahookickrsnapbike.cpp @@ -311,15 +311,19 @@ uint16_t wahookickrsnapbike::wattsFromResistance(double resistance) { double br = -5.841344538; double cr = 97.62165482; + const double peloton_gain = settings.value(QZSettings::peloton_gain, QZSettings::default_peloton_gain).toDouble(); + const double peloton_offset = settings.value(QZSettings::peloton_offset, QZSettings::default_peloton_offset).toDouble(); + const double cadence = this->Cadence.value(), cadenceSq = cadence*cadence; + for (uint16_t i = 1; i < 2000; i += 5) { double res = (((sqrt(pow(br, 2.0) - 4.0 * ar * - (cr - ((double)i * 132.0 / (ac * pow(Cadence.value(), 2.0) + bc * Cadence.value() + cc)))) - + (cr - ((double)i * 132.0 / (ac * cadenceSq + bc * cadence + cc)))) - br) / (2.0 * ar)) * - settings.value(QZSettings::peloton_gain, QZSettings::default_peloton_gain).toDouble()) + - settings.value(QZSettings::peloton_offset, QZSettings::default_peloton_offset).toDouble(); + peloton_gain) + + peloton_offset; if (!isnan(res) && res >= resistance) { return i; diff --git a/tst/Devices/biketestsuite.cpp b/tst/Devices/biketestsuite.cpp index b8d51e9cc..501ba2bf8 100644 --- a/tst/Devices/biketestsuite.cpp +++ b/tst/Devices/biketestsuite.cpp @@ -17,6 +17,10 @@ BikeTestSuite::BikeTestSuite() : testSettings("Roberto Viola", "QDomyos-Zwift template void BikeTestSuite::SetUp() { BikeOptions options; + + // activate the test settings before doing anything + this->testSettings.activate(); + this->device =this->typeParam.createInstance(options); this->ergInterface = new bikeergfunctions(this->device); @@ -24,7 +28,6 @@ void BikeTestSuite::SetUp() { this->minRPM = this->ergInterface->getMinCadence().value_or(1); this->maxResistance = this->ergInterface->getMaxResistance().value_or(255); this->minResistance = this->ergInterface->getMinResistance().value_or(0); - } template @@ -131,10 +134,6 @@ void BikeTestSuite::test_powerFunctions_maxCadence() { GTEST_SKIP() << "No maximum cadence defined"; } - ASSERT_TRUE(this->testSettings.get_active()) << "TestSettings object should be active."; - this->testSettings.qsettings.setValue(QZSettings::watt_gain, 1.0); - this->testSettings.qsettings.setValue(QZSettings::watt_offset, 0.0); - // traverse the resistance edge checking the power is clipped to the values for the max and min cadence QString powerBeyondCadenceLimit = QStringLiteral("Power at R:%1 not bounded at %6 cadence (C:%2 RPM, P:%3W), (C:%4 RPM, P:%5W)"); @@ -157,13 +156,18 @@ void BikeTestSuite::test_powerFunctions_resistancePowerConversion() { const auto erg = this->ergInterface; QStringList errors; + ASSERT_TRUE(this->testSettings.get_active()) << "TestSettings object should be active."; + this->testSettings.qsettings.setValue(QZSettings::watt_gain, 1.0); + this->testSettings.qsettings.setValue(QZSettings::watt_offset, 0.0); + // test inverses QString unexpectedResistance=QStringLiteral("P(C:%3, R:%1)=%2 but R(C:%3, P:%2)=%4 and P(C:%3, R:%4)=%5"); //for(uint32_t cadenceRPM=minRPM; cadenceRPM<=maxRPM; cadenceRPM++) for(uint16_t cadenceRPM : this->getCadenceSamples()) { uint16_t lastPower=0xFFFF; - for(resistance_t resistanceToPower=minResistance; resistanceToPower<=maxResistance; resistanceToPower++) + for( resistance_t resistanceToPower : this->getResistanceSamples()) + //for(resistance_t resistanceToPower=minResistance; resistanceToPower<=maxResistance; resistanceToPower++) { uint16_t power = erg->getPower(cadenceRPM, resistanceToPower); From d2be67c014cae47c1746239cfde0c804067f1dc0 Mon Sep 17 00:00:00 2001 From: David Mason Date: Wed, 27 Mar 2024 22:24:21 +0000 Subject: [PATCH 09/13] #2174 removed typo --- src/ergtable.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ergtable.h b/src/ergtable.h index 2c6161513..c4ebd25d0 100644 --- a/src/ergtable.h +++ b/src/ergtable.h @@ -5,7 +5,7 @@ #include #include #include -#include > +#include #include "qzsettings.h" struct ergDataPoint { From ce5479944f17a89b310ad2703490db141a20a5ad Mon Sep 17 00:00:00 2001 From: David Mason Date: Wed, 27 Mar 2024 22:32:09 +0000 Subject: [PATCH 10/13] #2174 consistent interface for bike::wattsFromResistance --- src/devices/bike.h | 6 ++++- .../computrainerbike/computrainerbike.cpp | 8 +++---- .../computrainerbike/computrainerbike.h | 6 +++-- src/devices/domyosbike/domyosbike.cpp | 8 +++---- src/devices/domyosbike/domyosbike.h | 3 ++- .../echelonconnectsport.cpp | 6 ++--- .../echelonconnectsport/echelonconnectsport.h | 4 +++- src/devices/fakebike/fakebike.cpp | 2 +- src/devices/fakebike/fakebike.h | 4 ++-- src/devices/fitplusbike/fitplusbike.cpp | 22 +------------------ src/devices/fitplusbike/fitplusbike.h | 4 ++-- src/devices/ftmsbike/ftmsbike.cpp | 2 +- src/devices/ftmsbike/ftmsbike.h | 3 ++- src/devices/mcfbike/mcfbike.cpp | 2 +- src/devices/mcfbike/mcfbike.h | 3 ++- src/devices/nautilusbike/nautilusbike.cpp | 2 +- src/devices/nautilusbike/nautilusbike.h | 3 ++- .../nordictrackifitadbbike.cpp | 21 +++++++++++++++++- .../nordictrackifitadbbike.h | 3 +++ src/devices/pafersbike/pafersbike.cpp | 2 +- src/devices/pafersbike/pafersbike.h | 4 +++- src/devices/proformbike/proformbike.cpp | 2 +- src/devices/proformbike/proformbike.h | 4 +++- .../proformtelnetbike/proformtelnetbike.cpp | 2 +- .../proformtelnetbike/proformtelnetbike.h | 5 +++-- .../proformwifibike/proformwifibike.cpp | 9 +++----- src/devices/proformwifibike/proformwifibike.h | 5 +++-- src/devices/schwinn170bike/schwinn170bike.cpp | 2 +- src/devices/schwinn170bike/schwinn170bike.h | 3 ++- src/devices/schwinnic4bike/schwinnic4bike.cpp | 2 +- src/devices/schwinnic4bike/schwinnic4bike.h | 3 ++- src/devices/sportsplusbike/sportsplusbike.cpp | 2 +- src/devices/sportsplusbike/sportsplusbike.h | 3 ++- src/devices/sportstechbike/sportstechbike.cpp | 2 +- src/devices/sportstechbike/sportstechbike.h | 5 +++-- src/devices/stagesbike/stagesbike.cpp | 2 +- src/devices/stagesbike/stagesbike.h | 3 ++- .../trxappgateusbbike/trxappgateusbbike.cpp | 2 +- .../trxappgateusbbike/trxappgateusbbike.h | 3 +-- .../wahookickrsnapbike/wahookickrsnapbike.cpp | 2 +- .../wahookickrsnapbike/wahookickrsnapbike.h | 4 +++- 41 files changed, 102 insertions(+), 81 deletions(-) diff --git a/src/devices/bike.h b/src/devices/bike.h index 51e549acd..08332de39 100644 --- a/src/devices/bike.h +++ b/src/devices/bike.h @@ -27,7 +27,8 @@ class bike : public bluetoothdevice { virtual resistance_t pelotonToBikeResistance(int pelotonResistance); virtual double bikeResistanceToPeloton(double resistance) { return resistance; } virtual resistance_t resistanceFromPowerRequest(uint16_t power); - virtual uint16_t wattsFromResistance(double resistance) { return this->powerFromResistanceRequest(resistance); } + uint16_t wattsFromResistance(double resistance) { return this->wattsFromResistance((resistance_t)resistance); } + virtual uint16_t wattsFromResistance(resistance_t resistance) { return this->powerFromResistanceRequest(resistance); } virtual uint16_t powerFromResistanceRequest(resistance_t requestResistance); virtual bool ergManagedBySS2K() { return false; } bluetoothdevice::BLUETOOTH_TYPE deviceType() override; @@ -50,6 +51,9 @@ class bike : public bluetoothdevice { virtual bool inclinationAvailableByHardware(); bool ergModeSupportedAvailableByHardware() { return ergModeSupported; } + /** + * @brief The inclusive minimum and maximum cadence values that power can be calculated for. + */ virtual minmax cadenceLimits() { return minmax(0, 250); } public Q_SLOTS: void changeResistance(resistance_t res) override; diff --git a/src/devices/computrainerbike/computrainerbike.cpp b/src/devices/computrainerbike/computrainerbike.cpp index 1e8786df2..b7b7dbd92 100644 --- a/src/devices/computrainerbike/computrainerbike.cpp +++ b/src/devices/computrainerbike/computrainerbike.cpp @@ -161,11 +161,9 @@ void computrainerbike::innerWriteResistance() { bool erg_mode = settings.value(QZSettings::zwift_erg, QZSettings::default_zwift_erg).toBool(); if (requestResistance != -1) { - if(!this->resistanceLimits().contains(requestResistance)) { - requestResistance = resistanceLimits().clip(requestResistance); - } else if (requestResistance == 0) { - requestResistance = 1; - } + + requestResistance = resistanceLimits().clip(requestResistance); + if (requestResistance != currentResistance().value()) { emit debug(QStringLiteral("writing resistance ") + QString::number(requestResistance)); diff --git a/src/devices/computrainerbike/computrainerbike.h b/src/devices/computrainerbike/computrainerbike.h index 115646cd3..b8951aa99 100644 --- a/src/devices/computrainerbike/computrainerbike.h +++ b/src/devices/computrainerbike/computrainerbike.h @@ -36,11 +36,13 @@ class computrainerbike : public bike { double bikeResistanceGain); resistance_t pelotonToBikeResistance(int pelotonResistance) override; - minmax resistanceLimits() override {return minmax(-20,100);} + minmax resistanceLimits() override {return minmax(0,100);} bool inclinationAvailableByHardware() override; bool connected() override; + + uint16_t wattsFromResistance(resistance_t resistance) override; private: - uint16_t wattsFromResistance(resistance_t resistance); + double GetDistanceFromPacket(QByteArray packet); QTime GetElapsedFromPacket(QByteArray packet); void btinit(); diff --git a/src/devices/domyosbike/domyosbike.cpp b/src/devices/domyosbike/domyosbike.cpp index 77d41a71f..93ed0e0e7 100644 --- a/src/devices/domyosbike/domyosbike.cpp +++ b/src/devices/domyosbike/domyosbike.cpp @@ -668,25 +668,25 @@ resistance_t domyosbike::pelotonToBikeResistance(int pelotonResistance) { resistance_t domyosbike::resistanceFromPowerRequest(uint16_t power) { qDebug() << QStringLiteral("resistanceFromPowerRequest") << currentCadence().value(); - for (resistance_t i = 1; i < this->resistanceLimits().max(); i++) { + for (resistance_t i = this->resistanceLimits().min(); i < this->resistanceLimits().max(); i++) { if (wattsFromResistance(i) <= power && wattsFromResistance(i + 1) >= power) { return i; } } if (power < wattsFromResistance(this->resistanceLimits().min())) - return 1; + return this->resistanceLimits().min(); else return this->resistanceLimits().max(); } -uint16_t domyosbike::wattsFromResistance(double resistance) { +uint16_t domyosbike::wattsFromResistance(resistance_t resistance) { QSettings settings; if (!settings.value(QZSettings::domyos_bike_500_profile_v1, QZSettings::default_domyos_bike_500_profile_v1) .toBool() || resistance < 8) return ((10.39 + 1.45 * (resistance - 1.0)) * (exp(0.028 * (currentCadence().value())))); else { - switch ((int)resistance) { + switch (resistance) { case 8: return (13.6 * Cadence.value()) / 9.5488; case 9: diff --git a/src/devices/domyosbike/domyosbike.h b/src/devices/domyosbike/domyosbike.h index ea77a22c1..d08ab763b 100644 --- a/src/devices/domyosbike/domyosbike.h +++ b/src/devices/domyosbike/domyosbike.h @@ -45,12 +45,13 @@ class domyosbike : public bike { ~domyosbike() override; bool connected() override; + uint16_t wattsFromResistance(resistance_t resistance) override; + private: double GetSpeedFromPacket(const QByteArray &packet); double GetInclinationFromPacket(QByteArray packet); double GetKcalFromPacket(const QByteArray &packet); double GetDistanceFromPacket(const QByteArray &packet); - uint16_t wattsFromResistance(double resistance); void forceResistance(resistance_t requestResistance); void updateDisplay(uint16_t elapsed); void btinit_changyow(bool startTape); diff --git a/src/devices/echelonconnectsport/echelonconnectsport.cpp b/src/devices/echelonconnectsport/echelonconnectsport.cpp index 86bac93a4..40215b6e1 100644 --- a/src/devices/echelonconnectsport/echelonconnectsport.cpp +++ b/src/devices/echelonconnectsport/echelonconnectsport.cpp @@ -537,7 +537,7 @@ uint16_t echelonconnectsport::watts() { return wattsFromResistance(Resistance.value()); } -uint16_t echelonconnectsport::wattsFromResistance(double resistance) { +uint16_t echelonconnectsport::wattsFromResistance(resistance_t resistance) { // https://github.com/cagnulein/qdomyos-zwift/issues/62#issuecomment-736913564 /*if(currentCadence().value() < 90) return (uint16_t)((3.59 * exp(0.0217 * (double)(currentCadence().value()))) * exp(0.095 * @@ -547,7 +547,7 @@ uint16_t echelonconnectsport::wattsFromResistance(double resistance) { const double Epsilon = 4.94065645841247E-324; const int wattTableFirstDimension = 33; const int wattTableSecondDimension = 11; - double wattTable[wattTableFirstDimension][wattTableSecondDimension] = { + static double wattTable[wattTableFirstDimension][wattTableSecondDimension] = { {Epsilon, 1.0, 2.2, 4.8, 9.5, 13.6, 16.7, 22.6, 26.3, 29.2, 47.0}, {Epsilon, 1.0, 2.2, 4.8, 9.5, 13.6, 16.7, 22.6, 26.3, 29.2, 47.0}, {Epsilon, 1.3, 3.0, 5.4, 10.4, 14.5, 18.5, 24.6, 27.6, 33.5, 49.5}, @@ -582,7 +582,7 @@ uint16_t echelonconnectsport::wattsFromResistance(double resistance) { {Epsilon, 12.5, 48.0, 99.3, 162.2, 232.9, 310.4, 400.3, 435.5, 530.5, 589.0}, {Epsilon, 13.0, 53.0, 102.0, 170.3, 242.0, 320.0, 427.9, 475.2, 570.0, 625.0}}; - double wattTable_mgarcea[wattTableFirstDimension][wattTableSecondDimension] = { + static double wattTable_mgarcea[wattTableFirstDimension][wattTableSecondDimension] = { {Epsilon, 1.0, 2.2, 4.8, 9.5, 13.6, 16.7, 22.6, 26.3, 29.2, 47.0}, {Epsilon, 1.0, 2.2, 4.8, 9.5, 13.6, 16.7, 22.6, 26.3, 29.2, 47.0}, {Epsilon, 1.3, 3.0, 5.4, 10.4, 14.5, 18.5, 24.6, 27.6, 33.5, 49.5}, diff --git a/src/devices/echelonconnectsport/echelonconnectsport.h b/src/devices/echelonconnectsport/echelonconnectsport.h index d90b54e06..94a55b7f1 100644 --- a/src/devices/echelonconnectsport/echelonconnectsport.h +++ b/src/devices/echelonconnectsport/echelonconnectsport.h @@ -44,10 +44,12 @@ class echelonconnectsport : public bike { resistance_t resistanceFromPowerRequest(uint16_t power) override; bool connected() override; + uint16_t wattsFromResistance(resistance_t resistance) override; + private: double bikeResistanceToPeloton(double resistance); double GetDistanceFromPacket(const QByteArray &packet); - uint16_t wattsFromResistance(double resistance); + QTime GetElapsedFromPacket(const QByteArray &packet); void btinit(); void writeCharacteristic(uint8_t *data, uint8_t data_len, const QString &info, bool disable_log = false, diff --git a/src/devices/fakebike/fakebike.cpp b/src/devices/fakebike/fakebike.cpp index 39eec6e24..5fba19d58 100644 --- a/src/devices/fakebike/fakebike.cpp +++ b/src/devices/fakebike/fakebike.cpp @@ -165,7 +165,7 @@ void fakebike::changeInclinationRequested(double grade, double percentage) { changeInclination(grade, percentage); } -uint16_t fakebike::wattsFromResistance(double resistance) { +uint16_t fakebike::wattsFromResistance(resistance_t resistance) { return _ergTable.estimateWattage(Cadence.value(), resistance); } diff --git a/src/devices/fakebike/fakebike.h b/src/devices/fakebike/fakebike.h index a40022dda..676b1890c 100644 --- a/src/devices/fakebike/fakebike.h +++ b/src/devices/fakebike/fakebike.h @@ -42,6 +42,7 @@ class fakebike : public bike { uint16_t watts() override; minmax resistanceLimits() override {return minmax(1,100);} resistance_t resistanceFromPowerRequest(uint16_t power) override; + uint16_t wattsFromResistance(resistance_t resistance) override; private: QTimer *refresh; @@ -67,8 +68,7 @@ class fakebike : public bike { #ifdef Q_OS_IOS lockscreen *h = 0; #endif - - uint16_t wattsFromResistance(double resistance); + signals: void disconnected(); diff --git a/src/devices/fitplusbike/fitplusbike.cpp b/src/devices/fitplusbike/fitplusbike.cpp index 036a06ae3..d80045732 100644 --- a/src/devices/fitplusbike/fitplusbike.cpp +++ b/src/devices/fitplusbike/fitplusbike.cpp @@ -977,7 +977,7 @@ void fitplusbike::controllerStateChanged(QLowEnergyController::ControllerState s } } -uint16_t fitplusbike::wattsFromResistance(double resistance) { +uint16_t fitplusbike::wattsFromResistance(resistance_t resistance) { // https://github.com/cagnulein/qdomyos-zwift/issues/62#issuecomment-736913564 /*if(currentCadence().value() < 90) return (uint16_t)((3.59 * exp(0.0217 * (double)(currentCadence().value()))) * exp(0.095 * @@ -1072,23 +1072,3 @@ uint16_t fitplusbike::wattsFromResistance(double resistance) { } } -resistance_t fitplusbike::resistanceFromPowerRequest(uint16_t power) { - qDebug() << QStringLiteral("resistanceFromPowerRequest") << Cadence.value(); - - auto minMaxR = this->resistanceLimits(); - - if (Cadence.value() == 0) - return 1; - - for (resistance_t i = 1; i < minMaxR.max(); i++) { - if (wattsFromResistance(i) <= power && wattsFromResistance(i + 1) >= power) { - qDebug() << QStringLiteral("resistanceFromPowerRequest") << wattsFromResistance(i) - << wattsFromResistance(i + 1) << power; - return i; - } - } - if (power < wattsFromResistance(minMaxR.min())) - return minMaxR.min(); - else - return minMaxR.max(); -} diff --git a/src/devices/fitplusbike/fitplusbike.h b/src/devices/fitplusbike/fitplusbike.h index aefab07ad..ed90f435b 100644 --- a/src/devices/fitplusbike/fitplusbike.h +++ b/src/devices/fitplusbike/fitplusbike.h @@ -39,7 +39,7 @@ class fitplusbike : public bike { fitplusbike(bool noWriteResistance, bool noHeartService, uint8_t bikeResistanceOffset, double bikeResistanceGain); minmax resistanceLimits() override {return this->bikeResistanceLimits;} bool connected() override; - resistance_t resistanceFromPowerRequest(uint16_t power) override; + uint16_t wattsFromResistance(resistance_t resistance) override; private: void btinit(); @@ -49,7 +49,7 @@ class fitplusbike : public bike { void forceResistance(resistance_t requestResistance); void sendPoll(); uint16_t watts() override; - uint16_t wattsFromResistance(double resistance); + QTimer *refresh; diff --git a/src/devices/ftmsbike/ftmsbike.cpp b/src/devices/ftmsbike/ftmsbike.cpp index a4487e050..90361c1fe 100644 --- a/src/devices/ftmsbike/ftmsbike.cpp +++ b/src/devices/ftmsbike/ftmsbike.cpp @@ -96,7 +96,7 @@ void ftmsbike::forcePower(int16_t requestPower) { powerForced = true; } -uint16_t ftmsbike::wattsFromResistance(double resistance) { +uint16_t ftmsbike::wattsFromResistance(resistance_t resistance) { if(DU30_bike) { double y = 1.46193548 * Cadence.value() + 0.0000887836638 * Cadence.value() * resistance + 0.000625 * resistance * resistance + 0.0580645161 * Cadence.value() + 0.00292986091 * resistance + 6.48448135542904; return y; diff --git a/src/devices/ftmsbike/ftmsbike.h b/src/devices/ftmsbike/ftmsbike.h index a68ca837c..754821d90 100644 --- a/src/devices/ftmsbike/ftmsbike.h +++ b/src/devices/ftmsbike/ftmsbike.h @@ -72,6 +72,7 @@ class ftmsbike : public bike { bool connected() override; resistance_t pelotonToBikeResistance(int pelotonResistance) override; minmax resistanceLimits() override {return this->bikeResistanceLimits;} + uint16_t wattsFromResistance(resistance_t resistance) override; private: void writeCharacteristic(uint8_t *data, uint8_t data_len, const QString &info, bool disable_log = false, @@ -81,7 +82,7 @@ class ftmsbike : public bike { void init(); void forceResistance(resistance_t requestResistance); void forcePower(int16_t requestPower); - uint16_t wattsFromResistance(double resistance) override; + QTimer *refresh; diff --git a/src/devices/mcfbike/mcfbike.cpp b/src/devices/mcfbike/mcfbike.cpp index 57f97842c..b1cd3c7a2 100644 --- a/src/devices/mcfbike/mcfbike.cpp +++ b/src/devices/mcfbike/mcfbike.cpp @@ -134,7 +134,7 @@ void mcfbike::serviceDiscovered(const QBluetoothUuid &gatt) { // TO CHANGE -uint16_t mcfbike::wattsFromResistance(double resistance) { +uint16_t mcfbike::wattsFromResistance(resistance_t resistance) { return ((10.39 + 1.45 * (resistance - 1.0)) * (exp(0.028 * (currentCadence().value())))); } diff --git a/src/devices/mcfbike/mcfbike.h b/src/devices/mcfbike/mcfbike.h index 447e1735b..9ce8b4c34 100644 --- a/src/devices/mcfbike/mcfbike.h +++ b/src/devices/mcfbike/mcfbike.h @@ -40,10 +40,11 @@ class mcfbike : public bike { minmax resistanceLimits() override {return minmax(1,14);} bool connected() override; + uint16_t wattsFromResistance(resistance_t resistance) override; private: double bikeResistanceToPeloton(double resistance) override; double GetDistanceFromPacket(const QByteArray &packet); - uint16_t wattsFromResistance(double resistance) override; + QTime GetElapsedFromPacket(const QByteArray &packet); void btinit(); void writeCharacteristic(uint8_t *data, uint8_t data_len, const QString &info, bool disable_log = false, diff --git a/src/devices/nautilusbike/nautilusbike.cpp b/src/devices/nautilusbike/nautilusbike.cpp index 4972cc3d4..344b14302 100644 --- a/src/devices/nautilusbike/nautilusbike.cpp +++ b/src/devices/nautilusbike/nautilusbike.cpp @@ -418,7 +418,7 @@ void nautilusbike::controllerStateChanged(QLowEnergyController::ControllerState uint16_t nautilusbike::watts() { return m_watt.value(); } -uint16_t nautilusbike::wattsFromResistance(double resistance) { +uint16_t nautilusbike::wattsFromResistance(resistance_t resistance) { // power table nautilus u626 #2118 double intercept = 12.16860795336126; double coefCadence = 0.12260211; diff --git a/src/devices/nautilusbike/nautilusbike.h b/src/devices/nautilusbike/nautilusbike.h index 2b1951479..853a78c0b 100644 --- a/src/devices/nautilusbike/nautilusbike.h +++ b/src/devices/nautilusbike/nautilusbike.h @@ -37,6 +37,7 @@ class nautilusbike : public bike { bool connected() override; resistance_t resistanceFromPowerRequest(uint16_t power) override; minmax resistanceLimits() override; + uint16_t wattsFromResistance(resistance_t resistance) override; private: double GetSpeedFromPacket(const QByteArray &packet); double GetInclinationFromPacket(QByteArray packet); @@ -47,7 +48,7 @@ class nautilusbike : public bike { void writeCharacteristic(uint8_t *data, uint8_t data_len, const QString &info, bool disable_log = false, bool wait_for_response = false); void startDiscover(); - uint16_t wattsFromResistance(double resistance); + QTimer *refresh; uint8_t firstVirtual = 0; diff --git a/src/devices/nordictrackifitadbbike/nordictrackifitadbbike.cpp b/src/devices/nordictrackifitadbbike/nordictrackifitadbbike.cpp index 47ed8be68..f9bed221d 100644 --- a/src/devices/nordictrackifitadbbike/nordictrackifitadbbike.cpp +++ b/src/devices/nordictrackifitadbbike/nordictrackifitadbbike.cpp @@ -574,7 +574,26 @@ bool nordictrackifitadbbike::connected() { return true; } resistance_t nordictrackifitadbbike::resistanceFromPowerRequest(uint16_t power) { // actually it's using inclination for the s22i - return bike::resistanceFromPowerRequest(power); + qDebug() << QStringLiteral("resistanceFromPowerRequest") << Cadence.value(); + + auto minMaxR = this->resistanceLimits(); + + if (Cadence.value() == 0) + return minMaxR.min(); + + const double cadence = Cadence.value(); + + for (resistance_t i = minMaxR.min(); i < minMaxR.max(); i++) { + if (wattsFromResistance(i, cadence) <= power && wattsFromResistance(i + 1, cadence) >= power) { + qDebug() << QStringLiteral("resistanceFromPowerRequest") << wattsFromResistance(i, cadence) + << wattsFromResistance(i + 1, cadence) << power; + return i; + } + } + if (power < wattsFromResistance(this->resistanceLimits().min(), cadence)) + return this->resistanceLimits().min(); + else + return this->resistanceLimits().max(); } uint16_t nordictrackifitadbbike::wattsFromResistance(double inclination, double cadence) { diff --git a/src/devices/nordictrackifitadbbike/nordictrackifitadbbike.h b/src/devices/nordictrackifitadbbike/nordictrackifitadbbike.h index 0c0eab3f9..f1a92822c 100644 --- a/src/devices/nordictrackifitadbbike/nordictrackifitadbbike.h +++ b/src/devices/nordictrackifitadbbike/nordictrackifitadbbike.h @@ -69,6 +69,9 @@ class nordictrackifitadbbike : public bike { minmax resistanceLimits() override { return minmax(0,17); // max inclination for s22i } + + uint16_t wattsFromResistance(resistance_t resistance) override { return this->wattsFromResistance(resistance, this->Cadence.value()); } + private: void forceResistance(double resistance); uint16_t watts() override; diff --git a/src/devices/pafersbike/pafersbike.cpp b/src/devices/pafersbike/pafersbike.cpp index 20355f697..d3447f718 100644 --- a/src/devices/pafersbike/pafersbike.cpp +++ b/src/devices/pafersbike/pafersbike.cpp @@ -140,7 +140,7 @@ void pafersbike::serviceDiscovered(const QBluetoothUuid &gatt) { qDebug() << QStringLiteral("serviceDiscovered ") + gatt.toString(); } -uint16_t pafersbike::wattsFromResistance(double resistance) { +uint16_t pafersbike::wattsFromResistance(resistance_t resistance) { // to be changed return ((10.39 + 1.45 * (resistance - 1.0)) * (exp(0.028 * (currentCadence().value())))); } diff --git a/src/devices/pafersbike/pafersbike.h b/src/devices/pafersbike/pafersbike.h index a6974d02f..6dd535752 100644 --- a/src/devices/pafersbike/pafersbike.h +++ b/src/devices/pafersbike/pafersbike.h @@ -40,10 +40,12 @@ class pafersbike : public bike { minmax resistanceLimits() override {return minmax(1,24);} bool connected() override; + uint16_t wattsFromResistance(resistance_t resistance) override; + private: double bikeResistanceToPeloton(double resistance) override; double GetDistanceFromPacket(const QByteArray &packet); - uint16_t wattsFromResistance(double resistance) override; + QTime GetElapsedFromPacket(const QByteArray &packet); void btinit(); void writeCharacteristic(uint8_t *data, uint8_t data_len, const QString &info, bool disable_log = false, diff --git a/src/devices/proformbike/proformbike.cpp b/src/devices/proformbike/proformbike.cpp index 66469c396..00e6e2c79 100644 --- a/src/devices/proformbike/proformbike.cpp +++ b/src/devices/proformbike/proformbike.cpp @@ -55,7 +55,7 @@ void proformbike::writeCharacteristic(uint8_t *data, uint8_t data_len, const QSt loop.exec(); } -uint16_t proformbike::wattsFromResistance(double resistance) { +uint16_t proformbike::wattsFromResistance(resistance_t resistance) { if (currentCadence().value() == 0) return 0; diff --git a/src/devices/proformbike/proformbike.h b/src/devices/proformbike/proformbike.h index 1e9f7c53d..313c82a4a 100644 --- a/src/devices/proformbike/proformbike.h +++ b/src/devices/proformbike/proformbike.h @@ -42,8 +42,10 @@ class proformbike : public bike { bool inclinationAvailableByHardware() override; bool connected() override; + uint16_t wattsFromResistance(resistance_t resistance) override; + private: - uint16_t wattsFromResistance(double resistance) override; + double GetDistanceFromPacket(QByteArray packet); QTime GetElapsedFromPacket(QByteArray packet); void btinit(); diff --git a/src/devices/proformtelnetbike/proformtelnetbike.cpp b/src/devices/proformtelnetbike/proformtelnetbike.cpp index 08617a40c..ddc2f13d2 100644 --- a/src/devices/proformtelnetbike/proformtelnetbike.cpp +++ b/src/devices/proformtelnetbike/proformtelnetbike.cpp @@ -110,7 +110,7 @@ void proformtelnetbike::writeCharacteristic(uint8_t *data, uint8_t data_len, con }*/ -uint16_t proformtelnetbike::wattsFromResistance(double resistance) { +uint16_t proformtelnetbike::wattsFromResistance(resistance_t resistance) { if (currentCadence().value() == 0) return 0; diff --git a/src/devices/proformtelnetbike/proformtelnetbike.h b/src/devices/proformtelnetbike/proformtelnetbike.h index 59e66021d..717a5b55e 100644 --- a/src/devices/proformtelnetbike/proformtelnetbike.h +++ b/src/devices/proformtelnetbike/proformtelnetbike.h @@ -49,15 +49,16 @@ class proformtelnetbike : public bike { double bikeResistanceGain); resistance_t pelotonToBikeResistance(int pelotonResistance) override; - minmax resistanceLimits() override {return minmax(-20,100);} + minmax resistanceLimits() override {return minmax(0,100);} bool inclinationAvailableByHardware() override; bool connected() override; + uint16_t wattsFromResistance(resistance_t resistance) override; private: QTelnet telnet; double max_incline_supported = 20; void connectToDevice(); - uint16_t wattsFromResistance(double resistance) override; + double GetDistanceFromPacket(QByteArray packet); QTime GetElapsedFromPacket(QByteArray packet); void btinit(); diff --git a/src/devices/proformwifibike/proformwifibike.cpp b/src/devices/proformwifibike/proformwifibike.cpp index f901b2a14..d7eb704d9 100644 --- a/src/devices/proformwifibike/proformwifibike.cpp +++ b/src/devices/proformwifibike/proformwifibike.cpp @@ -119,7 +119,7 @@ uint16_t proformwifibike::wattsFromResistance(resistance_t resistance) { if (currentCadence().value() == 0) return 0; - switch (resistance) { + switch ((resistance_t)resistance) { case 0: case 1: // -13.5 + 0.999x + 0.00993x² @@ -225,11 +225,8 @@ void proformwifibike::innerWriteResistance() { static QString last_mode = "MANUAL"; if (requestResistance != -1) { - if(!this->resistanceLimits().contains(requestResistance)) { - requestResistance = this->resistanceLimits().clip(requestResistance); - } else if (requestResistance == 0) { - requestResistance = 1; - } + + requestResistance = this->resistanceLimits().clip(requestResistance); if (requestResistance != currentResistance().value()) { emit debug(QStringLiteral("writing resistance ") + QString::number(requestResistance)); diff --git a/src/devices/proformwifibike/proformwifibike.h b/src/devices/proformwifibike/proformwifibike.h index 33e82b3c3..d15301cf5 100644 --- a/src/devices/proformwifibike/proformwifibike.h +++ b/src/devices/proformwifibike/proformwifibike.h @@ -45,15 +45,16 @@ class proformwifibike : public bike { proformwifibike(bool noWriteResistance, bool noHeartService, uint8_t bikeResistanceOffset, double bikeResistanceGain); resistance_t pelotonToBikeResistance(int pelotonResistance) override; - minmax resistanceLimits() override {return minmax(-20,100);} + minmax resistanceLimits() override {return minmax(0,100);} bool inclinationAvailableByHardware() override; bool connected() override; + uint16_t wattsFromResistance(resistance_t resistance) override; private: QWebSocket websocket; double max_incline_supported = 20; void connectToDevice(); - uint16_t wattsFromResistance(resistance_t resistance); + double GetDistanceFromPacket(QByteArray packet); QTime GetElapsedFromPacket(QByteArray packet); void btinit(); diff --git a/src/devices/schwinn170bike/schwinn170bike.cpp b/src/devices/schwinn170bike/schwinn170bike.cpp index 5b47873ca..33acd7bcd 100644 --- a/src/devices/schwinn170bike/schwinn170bike.cpp +++ b/src/devices/schwinn170bike/schwinn170bike.cpp @@ -520,7 +520,7 @@ resistance_t schwinn170bike::pelotonToBikeResistance(int pelotonResistance) { } } -uint16_t schwinn170bike::wattsFromResistance(double resistance) { +uint16_t schwinn170bike::wattsFromResistance(resistance_t resistance) { QSettings settings; constexpr double ac = 0.01243107769; diff --git a/src/devices/schwinn170bike/schwinn170bike.h b/src/devices/schwinn170bike/schwinn170bike.h index 6bdface73..ff3e9d8bd 100644 --- a/src/devices/schwinn170bike/schwinn170bike.h +++ b/src/devices/schwinn170bike/schwinn170bike.h @@ -45,10 +45,11 @@ class schwinn170bike : public bike { minmax resistanceLimits() override {return minmax(1,100);} bool connected() override; + uint16_t wattsFromResistance(resistance_t resistance) override; private: void writeCharacteristic(QLowEnergyService *service, QLowEnergyCharacteristic characteristic, uint8_t *data, uint8_t data_len, QString info, bool disable_log = false, bool wait_for_response = false); - uint16_t wattsFromResistance(double resistance) override; + void startDiscover(); uint16_t watts() override; diff --git a/src/devices/schwinnic4bike/schwinnic4bike.cpp b/src/devices/schwinnic4bike/schwinnic4bike.cpp index 5a8b12b1f..ade4ae68f 100644 --- a/src/devices/schwinnic4bike/schwinnic4bike.cpp +++ b/src/devices/schwinnic4bike/schwinnic4bike.cpp @@ -586,7 +586,7 @@ resistance_t schwinnic4bike::pelotonToBikeResistance(int pelotonResistance) { } } -uint16_t schwinnic4bike::wattsFromResistance(double resistance) { +uint16_t schwinnic4bike::wattsFromResistance(resistance_t resistance) { QSettings settings; double ac = 0.01243107769; diff --git a/src/devices/schwinnic4bike/schwinnic4bike.h b/src/devices/schwinnic4bike/schwinnic4bike.h index 921c0f1e0..f53b9ccf9 100644 --- a/src/devices/schwinnic4bike/schwinnic4bike.h +++ b/src/devices/schwinnic4bike/schwinnic4bike.h @@ -43,10 +43,11 @@ class schwinnic4bike : public bike { minmax resistanceLimits() override {return minmax(1,100);} bool connected() override; + uint16_t wattsFromResistance(resistance_t resistance) override; private: void writeCharacteristic(uint8_t *data, uint8_t data_len, QString info, bool disable_log = false, bool wait_for_response = false); - uint16_t wattsFromResistance(double resistance); + void startDiscover(); uint16_t watts() override; diff --git a/src/devices/sportsplusbike/sportsplusbike.cpp b/src/devices/sportsplusbike/sportsplusbike.cpp index 597a3153e..38d82083e 100644 --- a/src/devices/sportsplusbike/sportsplusbike.cpp +++ b/src/devices/sportsplusbike/sportsplusbike.cpp @@ -518,7 +518,7 @@ void sportsplusbike::controllerStateChanged(QLowEnergyController::ControllerStat } } -uint16_t sportsplusbike::wattsFromResistance(double resistance) { +uint16_t sportsplusbike::wattsFromResistance(resistance_t resistance) { const int wattTableFirstDimension = 24; const int wattTableSecondDimension = 6; double wattTable[wattTableFirstDimension][wattTableSecondDimension] = { diff --git a/src/devices/sportsplusbike/sportsplusbike.h b/src/devices/sportsplusbike/sportsplusbike.h index 27ada5ebd..090f7676c 100644 --- a/src/devices/sportsplusbike/sportsplusbike.h +++ b/src/devices/sportsplusbike/sportsplusbike.h @@ -36,6 +36,7 @@ class sportsplusbike : public bike { bool connected() override; minmax resistanceLimits() override {return minmax(0,24);} + uint16_t wattsFromResistance(resistance_t resistance) override; private: double GetSpeedFromPacket(const QByteArray &packet); @@ -47,7 +48,7 @@ class sportsplusbike : public bike { void btinit(bool startTape); void writeCharacteristic(uint8_t *data, uint8_t data_len, const QString &info, bool disable_log, bool wait_for_response); - uint16_t wattsFromResistance(double resistance); + void startDiscover(); uint16_t watts() override; double GetWattFromPacket(const QByteArray &packet); diff --git a/src/devices/sportstechbike/sportstechbike.cpp b/src/devices/sportstechbike/sportstechbike.cpp index 9a1f44595..76d0ea2ab 100644 --- a/src/devices/sportstechbike/sportstechbike.cpp +++ b/src/devices/sportstechbike/sportstechbike.cpp @@ -413,7 +413,7 @@ void sportstechbike::controllerStateChanged(QLowEnergyController::ControllerStat } } -uint16_t sportstechbike::wattsFromResistance(double resistance) { +uint16_t sportstechbike::wattsFromResistance(resistance_t resistance) { // Coefficients from the polynomial regression double intercept = 14.4968; double b1 = -4.1878; diff --git a/src/devices/sportstechbike/sportstechbike.h b/src/devices/sportstechbike/sportstechbike.h index 5731ef1e1..8e79fc059 100644 --- a/src/devices/sportstechbike/sportstechbike.h +++ b/src/devices/sportstechbike/sportstechbike.h @@ -32,14 +32,15 @@ class sportstechbike : public bike { public: sportstechbike(bool noWriteResistance, bool noHeartService); bool connected() override; - minmax resistanceLimits() override {return minmax(0,24);} + minmax resistanceLimits() override {return minmax(0,23);} + uint16_t wattsFromResistance(resistance_t resistance) override; private: double GetSpeedFromPacket(const QByteArray &packet); double GetResistanceFromPacket(const QByteArray &packet); double GetKcalFromPacket(const QByteArray &packet); double GetDistanceFromPacket(QByteArray packet); uint16_t GetElapsedFromPacket(const QByteArray &packet); - uint16_t wattsFromResistance(double resistance); + void forceResistance(resistance_t requestResistance); void updateDisplay(uint16_t elapsed); void btinit(bool startTape); diff --git a/src/devices/stagesbike/stagesbike.cpp b/src/devices/stagesbike/stagesbike.cpp index 0a4de1bdc..5491bd975 100644 --- a/src/devices/stagesbike/stagesbike.cpp +++ b/src/devices/stagesbike/stagesbike.cpp @@ -130,7 +130,7 @@ resistance_t stagesbike::pelotonToBikeResistance(int pelotonResistance) { } } -uint16_t stagesbike::wattsFromResistance(double resistance) { +uint16_t stagesbike::wattsFromResistance(resistance_t resistance) { QSettings settings; double ac = 0.01243107769; diff --git a/src/devices/stagesbike/stagesbike.h b/src/devices/stagesbike/stagesbike.h index c0f29ae4e..9b2857cdf 100644 --- a/src/devices/stagesbike/stagesbike.h +++ b/src/devices/stagesbike/stagesbike.h @@ -40,11 +40,12 @@ class stagesbike : public bike { bool connected() override; minmax resistanceLimits() override {return minmax(1,100);} bool ergManagedBySS2K() override { return true; } + uint16_t wattsFromResistance(resistance_t resistance) override; private: void writeCharacteristic(uint8_t *data, uint8_t data_len, QString info, bool disable_log = false, bool wait_for_response = false); - uint16_t wattsFromResistance(double resistance); + metric ResistanceFromFTMSAccessory; uint64_t ResistanceFromFTMSAccessoryLastTime = 0; void startDiscover(); diff --git a/src/devices/trxappgateusbbike/trxappgateusbbike.cpp b/src/devices/trxappgateusbbike/trxappgateusbbike.cpp index 866ac82bf..b7b1f0abb 100644 --- a/src/devices/trxappgateusbbike/trxappgateusbbike.cpp +++ b/src/devices/trxappgateusbbike/trxappgateusbbike.cpp @@ -1156,7 +1156,7 @@ void trxappgateusbbike::controllerStateChanged(QLowEnergyController::ControllerS } } -uint16_t trxappgateusbbike::wattsFromResistance(double resistance) { +uint16_t trxappgateusbbike::wattsFromResistance(resistance_t resistance) { QSettings settings; bool toorx_srx_3500 = settings.value(QZSettings::toorx_srx_3500, QZSettings::default_toorx_srx_3500).toBool(); if(toorx_srx_3500) { diff --git a/src/devices/trxappgateusbbike/trxappgateusbbike.h b/src/devices/trxappgateusbbike/trxappgateusbbike.h index c8951fa40..7bdf03672 100644 --- a/src/devices/trxappgateusbbike/trxappgateusbbike.h +++ b/src/devices/trxappgateusbbike/trxappgateusbbike.h @@ -39,7 +39,7 @@ class trxappgateusbbike : public bike { double bikeResistanceGain); bool connected() override; minmax resistanceLimits() override {return minmax(1,32);} - + uint16_t wattsFromResistance(resistance_t resistance) override; private: double GetSpeedFromPacket(const QByteArray &packet); double GetResistanceFromPacket(const QByteArray &packet); @@ -56,7 +56,6 @@ class trxappgateusbbike : public bike { double GetWattFromPacket(const QByteArray &packet); double GetWattFromPacketFytter(const QByteArray &packet); double GetCadenceFromPacket(const QByteArray &packet); - uint16_t wattsFromResistance(double resistance) override; QTimer *refresh; diff --git a/src/devices/wahookickrsnapbike/wahookickrsnapbike.cpp b/src/devices/wahookickrsnapbike/wahookickrsnapbike.cpp index 3f9c7cc79..1983d3c8c 100644 --- a/src/devices/wahookickrsnapbike/wahookickrsnapbike.cpp +++ b/src/devices/wahookickrsnapbike/wahookickrsnapbike.cpp @@ -300,7 +300,7 @@ resistance_t wahookickrsnapbike::pelotonToBikeResistance(int pelotonResistance) } } -uint16_t wahookickrsnapbike::wattsFromResistance(double resistance) { +uint16_t wahookickrsnapbike::wattsFromResistance(resistance_t resistance) { QSettings settings; double ac = 0.01243107769; diff --git a/src/devices/wahookickrsnapbike/wahookickrsnapbike.h b/src/devices/wahookickrsnapbike/wahookickrsnapbike.h index b7dc9394c..65c5bcc05 100644 --- a/src/devices/wahookickrsnapbike/wahookickrsnapbike.h +++ b/src/devices/wahookickrsnapbike/wahookickrsnapbike.h @@ -56,6 +56,8 @@ class wahookickrsnapbike : public bike { _setWheelCircumference = 72, }; + uint16_t wattsFromResistance(resistance_t resistance) override; + private: QByteArray unlockCommand(); QByteArray setResistanceMode(double resistance); @@ -70,7 +72,7 @@ class wahookickrsnapbike : public bike { bool writeCharacteristic(uint8_t *data, uint8_t data_len, QString info, bool disable_log = false, bool wait_for_response = false); - uint16_t wattsFromResistance(double resistance); + metric ResistanceFromFTMSAccessory; void startDiscover(); uint16_t watts() override; From 6e018a1e81afda168bc4f3aee65f01b4fc7d1eb5 Mon Sep 17 00:00:00 2001 From: David Mason Date: Wed, 27 Mar 2024 23:17:49 +0000 Subject: [PATCH 11/13] #2174 added tests for conversion to and from resistance and Peloton resistance --- tst/Devices/biketestsuite.cpp | 39 +++++++++++++++++++++++++++++++++++ tst/Devices/biketestsuite.h | 7 +++++++ tst/Erg/bikeergfunctions.cpp | 6 ++++++ tst/Erg/bikeergfunctions.h | 3 +++ tst/Erg/erginterface.h | 13 ++++++++++++ 5 files changed, 68 insertions(+) diff --git a/tst/Devices/biketestsuite.cpp b/tst/Devices/biketestsuite.cpp index 501ba2bf8..340ed0cff 100644 --- a/tst/Devices/biketestsuite.cpp +++ b/tst/Devices/biketestsuite.cpp @@ -191,6 +191,45 @@ void BikeTestSuite::test_powerFunctions_resistancePowerConversion() { ASSERT_TRUE(errors.empty()) << errors.join('\n').toStdString(); } +template +void BikeTestSuite::test_powerFunctions_resistancePelotonConversion() { + const auto erg = this->ergInterface; + QStringList errors; + + ASSERT_TRUE(this->testSettings.get_active()) << "TestSettings object should be active."; + this->testSettings.qsettings.setValue(QZSettings::watt_gain, 1.0); + this->testSettings.qsettings.setValue(QZSettings::watt_offset, 0.0); + + // test inverses + QString unexpectedResistance=QStringLiteral("R2P(R:%1)=%2 but P2R(P:%2)=%3 and R2P(R:%3)=%4"); + + int lastPeloton = 0xFFFFFFFF; + + for( resistance_t resistanceToPeloton : this->getResistanceSamples()) + //for(resistance_t resistanceToPower=minResistance; resistanceToPower<=maxResistance; resistanceToPower++) + { + int pelotonFromResistance = erg->toPeloton(resistanceToPeloton); + + // if this resistance reaches a new Peloton level, check the inverse + if(pelotonFromResistance!=lastPeloton) + { + lastPeloton = pelotonFromResistance; + resistance_t resistanceFromPeloton = erg->fromPeloton(pelotonFromResistance); + + if(resistanceToPeloton!=resistanceFromPeloton) { + int newPeloton = erg->toPeloton(resistanceFromPeloton); + + errors.append(unexpectedResistance.arg(resistanceToPeloton).arg(pelotonFromResistance).arg(resistanceFromPeloton).arg(newPeloton)); + } + + } + + } + + + ASSERT_TRUE(errors.empty()) << errors.join('\n').toStdString(); +} + template template QList BikeTestSuite::getSamples(const T0 min, const T0 max) { diff --git a/tst/Devices/biketestsuite.h b/tst/Devices/biketestsuite.h index 3ce2ff941..1c16d0e41 100644 --- a/tst/Devices/biketestsuite.h +++ b/tst/Devices/biketestsuite.h @@ -78,6 +78,10 @@ class BikeTestSuite : public testing::Test { */ void test_powerFunctions_resistancePowerConversion(); + /** + * @brief Test that conversions to and from Peloton levels work. + */ + void test_powerFunctions_resistancePelotonConversion(); }; @@ -106,3 +110,6 @@ TYPED_TEST(BikeTestSuite, TestPowerFunctionsResistancePowerConversion) { this->test_powerFunctions_resistancePowerConversion(); } +TYPED_TEST(BikeTestSuite, TestPowerFunctionsPelotonResistanceConversion) { + this->test_powerFunctions_resistancePelotonConversion(); +} diff --git a/tst/Erg/bikeergfunctions.cpp b/tst/Erg/bikeergfunctions.cpp index 8fa660582..62b864cac 100644 --- a/tst/Erg/bikeergfunctions.cpp +++ b/tst/Erg/bikeergfunctions.cpp @@ -28,3 +28,9 @@ int32_t bikeergfunctions::getResistance(const int32_t cadence, const double powe this->setCadence(originalCadence); return result; } + +int32_t bikeergfunctions::toPeloton(const resistance_t resistance) { return device->bikeResistanceToPeloton(resistance); } + +resistance_t bikeergfunctions::fromPeloton(const int pelotonResistance) { return device->pelotonToBikeResistance(pelotonResistance); } + + diff --git a/tst/Erg/bikeergfunctions.h b/tst/Erg/bikeergfunctions.h index de31f6834..c2271d9a0 100644 --- a/tst/Erg/bikeergfunctions.h +++ b/tst/Erg/bikeergfunctions.h @@ -26,4 +26,7 @@ class bikeergfunctions : public virtual erginterface { int32_t getResistance(const int32_t cadence, const double power) override; + int32_t toPeloton(const resistance_t resistance) override; + resistance_t fromPeloton(const int pelotonResistance) override; + }; diff --git a/tst/Erg/erginterface.h b/tst/Erg/erginterface.h index a60fd9e34..d63af98d5 100644 --- a/tst/Erg/erginterface.h +++ b/tst/Erg/erginterface.h @@ -53,6 +53,19 @@ class erginterface { */ virtual int32_t getResistance(const int32_t cadence, const double power) = 0; + /** + * @brief Converts the specified device resistance to its corresponding Peloton resistance level. + * @return + */ + virtual int32_t toPeloton(const resistance_t resistance) = 0; + + /** + * @brief Converts the specified Peloton resistance level to its corresponding device resistance level. + * @return + */ + virtual resistance_t fromPeloton(const int32_t pelotonResistance) = 0; + + /** * @brief Destructor */ From 55cb8013309cd9a65599df60117ac48971070d91 Mon Sep 17 00:00:00 2001 From: David Mason Date: Fri, 29 Mar 2024 21:19:21 +0000 Subject: [PATCH 12/13] #2174 increase use of minmax in test code. Some work to make Peloton conversions invert. --- src/devices/bike.cpp | 17 +++-- .../computrainerbike/computrainerbike.cpp | 62 +++++-------------- .../computrainerbike/computrainerbike.h | 7 ++- src/devices/domyosbike/domyosbike.cpp | 4 ++ src/devices/domyosbike/domyosbike.h | 2 + .../echelonconnectsport.cpp | 18 ++++-- src/devices/proformbike/proformbike.cpp | 60 ++++-------------- src/devices/proformbike/proformbike.h | 6 ++ .../proformwifibike/proformwifibike.cpp | 60 ++++-------------- src/devices/proformwifibike/proformwifibike.h | 6 ++ src/devices/renphobike/renphobike.h | 3 +- src/devices/schwinn170bike/schwinn170bike.cpp | 4 ++ src/devices/sportsplusbike/sportsplusbike.cpp | 4 ++ src/devices/sportsplusbike/sportsplusbike.h | 1 + tst/Devices/biketestsuite.cpp | 58 ++++++----------- tst/Devices/biketestsuite.h | 7 +-- tst/Erg/bikeergfunctions.cpp | 10 +-- tst/Erg/bikeergfunctions.h | 10 +-- tst/Erg/erginterface.h | 25 ++------ 19 files changed, 128 insertions(+), 236 deletions(-) diff --git a/src/devices/bike.cpp b/src/devices/bike.cpp index 357b954d2..6200ac1da 100644 --- a/src/devices/bike.cpp +++ b/src/devices/bike.cpp @@ -118,15 +118,20 @@ resistance_t bike::pelotonToBikeResistance(int pelotonResistance) { auto minMaxR = this->resistanceLimits(); - for (resistance_t i = minMaxR.min(); i < minMaxR.max(); i++) { - if (bikeResistanceToPeloton(i) <= pelotonResistance && bikeResistanceToPeloton(i + 1) >= pelotonResistance) { + auto pr0 = bikeResistanceToPeloton(minMaxR.min()); + + if(pelotonResistance<=pr0) + return minMaxR.min(); + + for (resistance_t i = 1+minMaxR.min(); i < minMaxR.max(); i++) { + auto pr1 = bikeResistanceToPeloton(i); + if (pr0 <= pelotonResistance && pr1 >= pelotonResistance) { return i; } + pr0 = pr1; } - if (pelotonResistance < bikeResistanceToPeloton(minMaxR.min())) - return minMaxR.min(); - else - return minMaxR.max(); + + return minMaxR.max(); } resistance_t bike::resistanceFromPowerRequest(uint16_t power) { qDebug() << QStringLiteral("resistanceFromPowerRequest") << Cadence.value(); diff --git a/src/devices/computrainerbike/computrainerbike.cpp b/src/devices/computrainerbike/computrainerbike.cpp index b7b7dbd92..2b150acf9 100644 --- a/src/devices/computrainerbike/computrainerbike.cpp +++ b/src/devices/computrainerbike/computrainerbike.cpp @@ -316,55 +316,21 @@ bool computrainerbike::inclinationAvailableByHardware() { return false; } +std::vector computrainerbike::bikeToPeloton({ 10,20,25,30,35,40,45,50,55,60,65,70,75,80,85,100 }); + +double computrainerbike::bikeResistanceToPeloton(double resistance) { + + auto r = this->resistanceLimits().clip(resistance); + + return bikeToPeloton[r-1]; +} + resistance_t computrainerbike::pelotonToBikeResistance(int pelotonResistance) { - if (pelotonResistance <= 10) { - return 1; - } - if (pelotonResistance <= 20) { - return 2; - } - if (pelotonResistance <= 25) { - return 3; - } - if (pelotonResistance <= 30) { - return 4; - } - if (pelotonResistance <= 35) { - return 5; - } - if (pelotonResistance <= 40) { - return 6; - } - if (pelotonResistance <= 45) { - return 7; - } - if (pelotonResistance <= 50) { - return 8; - } - if (pelotonResistance <= 55) { - return 9; - } - if (pelotonResistance <= 60) { - return 10; - } - if (pelotonResistance <= 65) { - return 11; - } - if (pelotonResistance <= 70) { - return 12; - } - if (pelotonResistance <= 75) { - return 13; - } - if (pelotonResistance <= 80) { - return 14; - } - if (pelotonResistance <= 85) { - return 15; - } - if (pelotonResistance <= 100) { - return 16; - } + + for(int i=0; i resistanceLimits() override {return minmax(0,100);} + minmax resistanceLimits() override {return minmax(1,16);} // limits inferred from Peloton conversion bool inclinationAvailableByHardware() override; bool connected() override; uint16_t wattsFromResistance(resistance_t resistance) override; private: + /** + * @brief A mapping of peloton->(resistance-1) + */ + static std::vector bikeToPeloton; double GetDistanceFromPacket(QByteArray packet); QTime GetElapsedFromPacket(QByteArray packet); diff --git a/src/devices/domyosbike/domyosbike.cpp b/src/devices/domyosbike/domyosbike.cpp index 93ed0e0e7..773502c3b 100644 --- a/src/devices/domyosbike/domyosbike.cpp +++ b/src/devices/domyosbike/domyosbike.cpp @@ -665,6 +665,10 @@ resistance_t domyosbike::pelotonToBikeResistance(int pelotonResistance) { return (pelotonResistance * this->resistanceLimits().max()) / 100; } +double domyosbike::bikeResistanceToPeloton(double resistance) { + return (int)(1+resistance * 100.0/this->resistanceLimits().max()); +} + resistance_t domyosbike::resistanceFromPowerRequest(uint16_t power) { qDebug() << QStringLiteral("resistanceFromPowerRequest") << currentCadence().value(); diff --git a/src/devices/domyosbike/domyosbike.h b/src/devices/domyosbike/domyosbike.h index d08ab763b..7c2ef982e 100644 --- a/src/devices/domyosbike/domyosbike.h +++ b/src/devices/domyosbike/domyosbike.h @@ -40,6 +40,8 @@ class domyosbike : public bike { uint8_t bikeResistanceOffset = 4, double bikeResistanceGain = 1.0); resistance_t resistanceFromPowerRequest(uint16_t power) override; resistance_t pelotonToBikeResistance(int pelotonResistance) override; + double bikeResistanceToPeloton(double resistance) override; + minmax resistanceLimits() override {return minmax(1,15);} ~domyosbike() override; diff --git a/src/devices/echelonconnectsport/echelonconnectsport.cpp b/src/devices/echelonconnectsport/echelonconnectsport.cpp index 40215b6e1..76883991e 100644 --- a/src/devices/echelonconnectsport/echelonconnectsport.cpp +++ b/src/devices/echelonconnectsport/echelonconnectsport.cpp @@ -155,15 +155,21 @@ void echelonconnectsport::serviceDiscovered(const QBluetoothUuid &gatt) { resistance_t echelonconnectsport::pelotonToBikeResistance(int pelotonResistance) { auto minMaxR = this->resistanceLimits(); - for (resistance_t i = 1; i < minMaxR.max(); i++) { - if (bikeResistanceToPeloton(i) <= pelotonResistance && bikeResistanceToPeloton(i + 1) > pelotonResistance) { + + auto p0 = bikeResistanceToPeloton(minMaxR.min()); + + if (pelotonResistance <= p0) + return minMaxR.min(); + + for (resistance_t i = 1+minMaxR.min(); i < minMaxR.max(); i++) { + auto p1 = bikeResistanceToPeloton(i); + if (p0 <= pelotonResistance && p1 > pelotonResistance) { return i; } + p0 = p1; } - if (pelotonResistance < bikeResistanceToPeloton(minMaxR.min())) - return 1; - else - return minMaxR.max(); + + return minMaxR.max(); } resistance_t echelonconnectsport::resistanceFromPowerRequest(uint16_t power) { diff --git a/src/devices/proformbike/proformbike.cpp b/src/devices/proformbike/proformbike.cpp index 00e6e2c79..39306c86a 100644 --- a/src/devices/proformbike/proformbike.cpp +++ b/src/devices/proformbike/proformbike.cpp @@ -781,55 +781,19 @@ bool proformbike::inclinationAvailableByHardware() { return false; } +std::vector proformbike::bikeToPeloton({ 10,20,25,30,35,40,45,50,55,60,65,70,75,80,85,100 }); + +double proformbike::bikeResistanceToPeloton(double resistance) { + + auto r = this->resistanceLimits().clip(resistance); + + return bikeToPeloton[r-1]; +} + resistance_t proformbike::pelotonToBikeResistance(int pelotonResistance) { - if (pelotonResistance <= 10) { - return 1; - } - if (pelotonResistance <= 20) { - return 2; - } - if (pelotonResistance <= 25) { - return 3; - } - if (pelotonResistance <= 30) { - return 4; - } - if (pelotonResistance <= 35) { - return 5; - } - if (pelotonResistance <= 40) { - return 6; - } - if (pelotonResistance <= 45) { - return 7; - } - if (pelotonResistance <= 50) { - return 8; - } - if (pelotonResistance <= 55) { - return 9; - } - if (pelotonResistance <= 60) { - return 10; - } - if (pelotonResistance <= 65) { - return 11; - } - if (pelotonResistance <= 70) { - return 12; - } - if (pelotonResistance <= 75) { - return 13; - } - if (pelotonResistance <= 80) { - return 14; - } - if (pelotonResistance <= 85) { - return 15; - } - if (pelotonResistance <= 100) { - return 16; - } + for(int i=0; i resistanceLimits() override {return this->bikeResistanceLimits;} bool inclinationAvailableByHardware() override; @@ -44,7 +45,12 @@ class proformbike : public bike { uint16_t wattsFromResistance(resistance_t resistance) override; + private: + /** + * @brief A mapping of peloton->(resistance-1) + */ + static std::vector bikeToPeloton; double GetDistanceFromPacket(QByteArray packet); QTime GetElapsedFromPacket(QByteArray packet); diff --git a/src/devices/proformwifibike/proformwifibike.cpp b/src/devices/proformwifibike/proformwifibike.cpp index d7eb704d9..e757b0546 100644 --- a/src/devices/proformwifibike/proformwifibike.cpp +++ b/src/devices/proformwifibike/proformwifibike.cpp @@ -323,55 +323,19 @@ void proformwifibike::update() { bool proformwifibike::inclinationAvailableByHardware() { return max_incline_supported > 0; } +std::vector proformwifibike::bikeToPeloton({ 10,20,25,30,35,40,45,50,55,60,65,70,75,80,85,100 }); + +double proformwifibike::bikeResistanceToPeloton(double resistance) { + + auto r = this->resistanceLimits().clip(resistance); + + return bikeToPeloton[r-1]; +} + resistance_t proformwifibike::pelotonToBikeResistance(int pelotonResistance) { - if (pelotonResistance <= 10) { - return 1; - } - if (pelotonResistance <= 20) { - return 2; - } - if (pelotonResistance <= 25) { - return 3; - } - if (pelotonResistance <= 30) { - return 4; - } - if (pelotonResistance <= 35) { - return 5; - } - if (pelotonResistance <= 40) { - return 6; - } - if (pelotonResistance <= 45) { - return 7; - } - if (pelotonResistance <= 50) { - return 8; - } - if (pelotonResistance <= 55) { - return 9; - } - if (pelotonResistance <= 60) { - return 10; - } - if (pelotonResistance <= 65) { - return 11; - } - if (pelotonResistance <= 70) { - return 12; - } - if (pelotonResistance <= 75) { - return 13; - } - if (pelotonResistance <= 80) { - return 14; - } - if (pelotonResistance <= 85) { - return 15; - } - if (pelotonResistance <= 100) { - return 16; - } + for(int i=0; i resistanceLimits() override {return minmax(0,100);} bool inclinationAvailableByHardware() override; bool connected() override; uint16_t wattsFromResistance(resistance_t resistance) override; + private: + /** + * @brief A mapping of peloton->(resistance-1) + */ + static std::vector bikeToPeloton; QWebSocket websocket; double max_incline_supported = 20; void connectToDevice(); diff --git a/src/devices/renphobike/renphobike.h b/src/devices/renphobike/renphobike.h index 89b648acc..94756f0ef 100644 --- a/src/devices/renphobike/renphobike.h +++ b/src/devices/renphobike/renphobike.h @@ -37,12 +37,13 @@ class renphobike : public bike { public: renphobike(bool noWriteResistance, bool noHeartService); resistance_t pelotonToBikeResistance(int pelotonResistance) override; + double bikeResistanceToPeloton(double resistance) override; // uint8_t resistanceFromPowerRequest(uint16_t power); bool connected() override; minmax resistanceLimits() override {return minmax(1,80);} private: - double bikeResistanceToPeloton(double resistance); + void writeCharacteristic(uint8_t *data, uint8_t data_len, QString info, bool disable_log = false, bool wait_for_response = false); void startDiscover(); diff --git a/src/devices/schwinn170bike/schwinn170bike.cpp b/src/devices/schwinn170bike/schwinn170bike.cpp index 33acd7bcd..43add61b1 100644 --- a/src/devices/schwinn170bike/schwinn170bike.cpp +++ b/src/devices/schwinn170bike/schwinn170bike.cpp @@ -28,6 +28,7 @@ schwinn170bike::schwinn170bike(bool noWriteResistance, bool noHeartService, uint this->bikeResistanceGain = bikeResistanceGain; this->bikeResistanceOffset = bikeResistanceOffset; initDone = false; + connect(refresh, &QTimer::timeout, this, &schwinn170bike::update); refresh->start(200ms); } @@ -504,6 +505,7 @@ resistance_t schwinn170bike::pelotonToBikeResistance(int pelotonResistance) { QSettings settings; bool schwinn_bike_resistance_v2 = settings.value(QZSettings::schwinn_bike_resistance_v2, QZSettings::default_schwinn_bike_resistance_v2).toBool(); + if (!schwinn_bike_resistance_v2) { if (pelotonResistance > 54) return pelotonResistance; @@ -520,6 +522,8 @@ resistance_t schwinn170bike::pelotonToBikeResistance(int pelotonResistance) { } } + + uint16_t schwinn170bike::wattsFromResistance(resistance_t resistance) { QSettings settings; diff --git a/src/devices/sportsplusbike/sportsplusbike.cpp b/src/devices/sportsplusbike/sportsplusbike.cpp index 38d82083e..63eb956d7 100644 --- a/src/devices/sportsplusbike/sportsplusbike.cpp +++ b/src/devices/sportsplusbike/sportsplusbike.cpp @@ -74,6 +74,10 @@ resistance_t sportsplusbike::pelotonToBikeResistance(int pelotonResistance) { return (pelotonResistance * this->resistanceLimits().max()) / 100; } +double sportsplusbike::bikeResistanceToPeloton(double resistance) { + return (int)(1+resistance * 100.0/this->resistanceLimits().max()); +} + void sportsplusbike::update() { // qDebug() << bike.isValid() << m_control->state() << gattCommunicationChannelService << // gattWriteCharacteristic.isValid() << gattNotifyCharacteristic.isValid() << initDone; diff --git a/src/devices/sportsplusbike/sportsplusbike.h b/src/devices/sportsplusbike/sportsplusbike.h index 090f7676c..b6460ccca 100644 --- a/src/devices/sportsplusbike/sportsplusbike.h +++ b/src/devices/sportsplusbike/sportsplusbike.h @@ -33,6 +33,7 @@ class sportsplusbike : public bike { public: sportsplusbike(bool noWriteResistance, bool noHeartService); resistance_t pelotonToBikeResistance(int pelotonResistance) override; + double bikeResistanceToPeloton(double resistance) override; bool connected() override; minmax resistanceLimits() override {return minmax(0,24);} diff --git a/tst/Devices/biketestsuite.cpp b/tst/Devices/biketestsuite.cpp index 340ed0cff..30c7b7ae9 100644 --- a/tst/Devices/biketestsuite.cpp +++ b/tst/Devices/biketestsuite.cpp @@ -3,12 +3,12 @@ template QList BikeTestSuite::getResistanceSamples() { - return this->getSamples(this->minResistance, this->maxResistance); + return this->getSamples(this->ergInterface->getResistanceLimits()); } template -QList BikeTestSuite::getCadenceSamples() { - return this->getSamples(this->minRPM, this->maxRPM); +QList BikeTestSuite::getCadenceSamples() { + return this->getSamples(this->ergInterface->getCadenceLimits()); } template @@ -23,11 +23,6 @@ void BikeTestSuite::SetUp() { this->device =this->typeParam.createInstance(options); this->ergInterface = new bikeergfunctions(this->device); - - this->maxRPM = this->ergInterface->getMaxCadence().value_or(120); - this->minRPM = this->ergInterface->getMinCadence().value_or(1); - this->maxResistance = this->ergInterface->getMaxResistance().value_or(255); - this->minResistance = this->ergInterface->getMinResistance().value_or(0); } template @@ -46,16 +41,12 @@ void BikeTestSuite::test_powerFunctions_minResistance() { QStringList errors; QString powerBeyondResistanceLimit = QStringLiteral("Power at C:%1 RPM not bounded at %6 resistance (R:%2, P:%3W), (R:%4, P:%5W)"); - if(!erg->getMinResistance().has_value()) - { - GTEST_SKIP() << "No minimum resistance defined"; - } + r0 = erg->getResistanceLimits().min(); + r1 = r0-1; // traverse the cadence edges checking the power is clipped to the values for the max and min resistance for( uint32_t cadenceRPM : this->getCadenceSamples()) - { - r0 = minResistance; - r1 = minResistance-1; + { p0 = erg->getPower(cadenceRPM, r0); p1 = erg->getPower(cadenceRPM, r1); @@ -75,16 +66,13 @@ void BikeTestSuite::test_powerFunctions_maxResistance() { QStringList errors; QString powerBeyondResistanceLimit = QStringLiteral("Power at C:%1 RPM not bounded at %6 resistance (R:%2, P:%3W), (R:%4, P:%5W)"); - if(!erg->getMaxResistance().has_value()) - { - GTEST_SKIP() << "No maximum resistance defined."; - } + r0 = erg->getResistanceLimits().max(); + r1 = r0+1; // traverse the cadence edges checking the power is clipped to the values for the max and min resistance for(uint16_t cadenceRPM : this->getCadenceSamples()) { - r0 = maxResistance; - r1 = maxResistance+1; + p0 = erg->getPower(cadenceRPM, r0); p1 = erg->getPower(cadenceRPM, r1); @@ -101,18 +89,14 @@ void BikeTestSuite::test_powerFunctions_minCadence() { uint16_t p0, p1; QStringList errors; - if(!erg->getMinCadence().has_value()) - { - GTEST_SKIP() << "No minimum cadence defined."; - } + const int32_t c0 = erg->getCadenceLimits().min(), c1=c0-1; // traverse the resistance edge checking the power is clipped to the values for the max and min cadence QString powerBeyondCadenceLimit = QStringLiteral("Power at R:%1 not bounded at %6 cadence (C:%2 RPM, P:%3W), (C:%4 RPM, P:%5W)"); for( resistance_t r : this->getResistanceSamples()) - { - const int32_t c0 = minRPM, c1=minRPM-1; + { p0 = erg->getPower(c0, r); p1 = erg->getPower(c1, r); @@ -129,18 +113,14 @@ void BikeTestSuite::test_powerFunctions_maxCadence() { uint16_t p0, p1; QStringList errors; - if(!erg->getMaxCadence().has_value()) - { - GTEST_SKIP() << "No maximum cadence defined"; - } + const int32_t c0 = erg->getCadenceLimits().max(), c1=c0+1; // traverse the resistance edge checking the power is clipped to the values for the max and min cadence QString powerBeyondCadenceLimit = QStringLiteral("Power at R:%1 not bounded at %6 cadence (C:%2 RPM, P:%3W), (C:%4 RPM, P:%5W)"); for( resistance_t r : this->getResistanceSamples()) - { - const int32_t c0 = maxRPM, c1=maxRPM+1; + { p0 = erg->getPower(c0, r); p1 = erg->getPower(c1, r); @@ -217,6 +197,8 @@ void BikeTestSuite::test_powerFunctions_resistancePelotonConversion() { resistance_t resistanceFromPeloton = erg->fromPeloton(pelotonFromResistance); if(resistanceToPeloton!=resistanceFromPeloton) { + // do it again for debugging + resistanceFromPeloton = erg->fromPeloton(pelotonFromResistance); int newPeloton = erg->toPeloton(resistanceFromPeloton); errors.append(unexpectedResistance.arg(resistanceToPeloton).arg(pelotonFromResistance).arg(resistanceFromPeloton).arg(newPeloton)); @@ -232,17 +214,17 @@ void BikeTestSuite::test_powerFunctions_resistancePelotonConversion() { template template -QList BikeTestSuite::getSamples(const T0 min, const T0 max) { +QList BikeTestSuite::getSamples(minmax range) { QList result; - T0 d = max-min; + T0 d = range.max()-range.min(); T0 inc = d/10; if(inc<1) inc = 1; - for(T0 v=min; v<=max; v+=inc) + for(T0 v=range.min(); v<=range.max(); v+=inc) result.append(v); - if(result.last()!=max) - result.append(max); + if(result.last()!=range.max()) + result.append(range.max()); return result; } diff --git a/tst/Devices/biketestsuite.h b/tst/Devices/biketestsuite.h index 1c16d0e41..4db8ec5e9 100644 --- a/tst/Devices/biketestsuite.h +++ b/tst/Devices/biketestsuite.h @@ -14,9 +14,6 @@ class BikeTestSuite : public testing::Test { protected: T typeParam; - uint32_t maxRPM, minRPM; - resistance_t maxResistance, minResistance; - erginterface * ergInterface = nullptr; /** @@ -29,7 +26,7 @@ class BikeTestSuite : public testing::Test { * @return A QList containing min, max and some, or sometimes all values in between. */ template - QList getSamples(const T0 min, const T0 max); + QList getSamples(minmax range); /** * @brief Determines from provided or estimated minimum and maximum resistance, which values to test, to avoid testing all. @@ -41,7 +38,7 @@ class BikeTestSuite : public testing::Test { * @brief Determines from provided or estimated minimum and maximum cadence, which values to test, to avoid testing all. * @return */ - virtual QList getCadenceSamples(); + virtual QList getCadenceSamples(); public: BikeTestSuite(); diff --git a/tst/Erg/bikeergfunctions.cpp b/tst/Erg/bikeergfunctions.cpp index 62b864cac..50038d85b 100644 --- a/tst/Erg/bikeergfunctions.cpp +++ b/tst/Erg/bikeergfunctions.cpp @@ -4,14 +4,6 @@ void bikeergfunctions::setCadence(int32_t cadence) { this->device->cadenceSensor bikeergfunctions::bikeergfunctions(bike *device) : device(device) {} -std::optional bikeergfunctions::getMaxCadence() const { return this->device->cadenceLimits().max();} - -std::optional bikeergfunctions::getMinCadence() const { return this->device->cadenceLimits().min(); } - -std::optional bikeergfunctions::getMaxResistance() const { return this->device->resistanceLimits().max(); } - -std::optional bikeergfunctions::getMinResistance() const { return this->device->resistanceLimits().min(); } - double bikeergfunctions::getPower(const int32_t cadence, resistance_t resistance) { auto originalCadence = this->device->currentCadence().value(); @@ -29,7 +21,7 @@ int32_t bikeergfunctions::getResistance(const int32_t cadence, const double powe return result; } -int32_t bikeergfunctions::toPeloton(const resistance_t resistance) { return device->bikeResistanceToPeloton(resistance); } +double bikeergfunctions::toPeloton(const resistance_t resistance) { return device->bikeResistanceToPeloton(resistance); } resistance_t bikeergfunctions::fromPeloton(const int pelotonResistance) { return device->pelotonToBikeResistance(pelotonResistance); } diff --git a/tst/Erg/bikeergfunctions.h b/tst/Erg/bikeergfunctions.h index c2271d9a0..00fabb09b 100644 --- a/tst/Erg/bikeergfunctions.h +++ b/tst/Erg/bikeergfunctions.h @@ -12,13 +12,9 @@ class bikeergfunctions : public virtual erginterface { bikeergfunctions(bike *device); - std::optional getMaxCadence() const override; + minmax getCadenceLimits() const override { return this->device->cadenceLimits(); } - std::optional getMinCadence() const override; - - std::optional getMaxResistance() const override; - - std::optional getMinResistance() const override; + minmax getResistanceLimits() const override { return this->device->resistanceLimits(); } double getPower(const int32_t cadence, const resistance_t resistance) override; @@ -26,7 +22,7 @@ class bikeergfunctions : public virtual erginterface { int32_t getResistance(const int32_t cadence, const double power) override; - int32_t toPeloton(const resistance_t resistance) override; + double toPeloton(const resistance_t resistance) override; resistance_t fromPeloton(const int pelotonResistance) override; }; diff --git a/tst/Erg/erginterface.h b/tst/Erg/erginterface.h index d63af98d5..a06e60ae8 100644 --- a/tst/Erg/erginterface.h +++ b/tst/Erg/erginterface.h @@ -1,6 +1,6 @@ #pragma once -#include +#include "minmax.h" #include "definitions.h" /** @@ -12,29 +12,16 @@ class erginterface { erginterface(const erginterface&) {} public: /** - * @brief The maximum cadence the object understands. + * @brief The cadence domain of the power functions. * @return */ - virtual std::optional getMaxCadence() const = 0; + virtual minmax getCadenceLimits() const = 0; /** - * @brief The minimum cadence the object understands. + * @brief The inclusive bounds of resistance the device provides. * @return */ - virtual std::optional getMinCadence() const = 0; - - /** - * @brief The maximum resistance the device accepts. - * @return - */ - virtual std::optional getMaxResistance() const = 0; - - /** - * @brief The minimum resistance level. - * @return - */ - virtual std::optional getMinResistance() const = 0; - + virtual minmax getResistanceLimits() const = 0; /** * @brief Gets the power in watts for the given cadence and resistance level. @@ -57,7 +44,7 @@ class erginterface { * @brief Converts the specified device resistance to its corresponding Peloton resistance level. * @return */ - virtual int32_t toPeloton(const resistance_t resistance) = 0; + virtual double toPeloton(const resistance_t resistance) = 0; /** * @brief Converts the specified Peloton resistance level to its corresponding device resistance level. From 2ca364474eb4634ee8f117026f3092cf6a7f6497 Mon Sep 17 00:00:00 2001 From: David Mason Date: Tue, 2 Apr 2024 21:26:29 +0100 Subject: [PATCH 13/13] #2174 replaced powerFromResistanceRequest with wattsFromResistance --- src/devices/bike.cpp | 8 ++++---- src/devices/bike.h | 5 ++--- tst/Erg/bikeergfunctions.cpp | 2 +- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/devices/bike.cpp b/src/devices/bike.cpp index 6200ac1da..0895db2a9 100644 --- a/src/devices/bike.cpp +++ b/src/devices/bike.cpp @@ -40,9 +40,9 @@ void bike::changeInclination(double grade, double percentage) { } // originally made for renphobike, but i guess it could be very generic -uint16_t bike::powerFromResistanceRequest(resistance_t requestResistance) { +uint16_t bike::wattsFromResistance(resistance_t resistance) { auto minMaxR = this->resistanceLimits(); - if(requestResistance<=minMaxR.min()) + if(resistance<=minMaxR.min()) return 0; // this bike has resistance level to N.m so the formula is Power (kW) = Torque (N.m) x Speed (RPM) / 9.5488 @@ -53,9 +53,9 @@ uint16_t bike::powerFromResistanceRequest(resistance_t requestResistance) { if(cadence <= this->cadenceLimits().min()) return 0; - requestResistance = minMaxR.clip(requestResistance); + resistance = minMaxR.clip(resistance); - return (requestResistance * this->cadenceLimits().clip(cadence)) / 9.5488; + return (resistance * this->cadenceLimits().clip(cadence)) / 9.5488; } void bike::changeRequestedPelotonResistance(int8_t resistance) { RequestedPelotonResistance = resistance; } diff --git a/src/devices/bike.h b/src/devices/bike.h index 08332de39..3e5f0d23d 100644 --- a/src/devices/bike.h +++ b/src/devices/bike.h @@ -27,9 +27,8 @@ class bike : public bluetoothdevice { virtual resistance_t pelotonToBikeResistance(int pelotonResistance); virtual double bikeResistanceToPeloton(double resistance) { return resistance; } virtual resistance_t resistanceFromPowerRequest(uint16_t power); - uint16_t wattsFromResistance(double resistance) { return this->wattsFromResistance((resistance_t)resistance); } - virtual uint16_t wattsFromResistance(resistance_t resistance) { return this->powerFromResistanceRequest(resistance); } - virtual uint16_t powerFromResistanceRequest(resistance_t requestResistance); + virtual uint16_t wattsFromResistance(resistance_t resistance); + virtual bool ergManagedBySS2K() { return false; } bluetoothdevice::BLUETOOTH_TYPE deviceType() override; metric pelotonResistance(); diff --git a/tst/Erg/bikeergfunctions.cpp b/tst/Erg/bikeergfunctions.cpp index 50038d85b..c814dd503 100644 --- a/tst/Erg/bikeergfunctions.cpp +++ b/tst/Erg/bikeergfunctions.cpp @@ -8,7 +8,7 @@ double bikeergfunctions::getPower(const int32_t cadence, resistance_t resistance auto originalCadence = this->device->currentCadence().value(); this->setCadence(cadence); - auto result = this->device->powerFromResistanceRequest(resistance); + auto result = this->device->wattsFromResistance(resistance); this->setCadence(originalCadence); return result; }