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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,4 @@ src/inner_templates/googlemaps/cesium-key.js
/tst/Devices/.vs
src/inner_templates/googlemaps/cesium-key.js
src/qdomyos-zwift.pro.user.49de507
/.vs
/.vs
34 changes: 30 additions & 4 deletions src/homeform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1590,6 +1590,8 @@ void homeform::trainProgramSignals() {
disconnect(trainProgram, &trainprogram::lap, this, &homeform::Lap);
disconnect(trainProgram, &trainprogram::changeSpeed, ((treadmill *)bluetoothManager->device()),
&treadmill::changeSpeed);
disconnect(trainProgram, &trainprogram::changeSpeed, this,
&homeform::onTrainingProgramSpeedChanged);
disconnect(trainProgram, &trainprogram::changeInclination, ((treadmill *)bluetoothManager->device()),
&treadmill::changeInclination);
disconnect(trainProgram, &trainprogram::changeNextInclination300Meters, bluetoothManager->device(),
Expand Down Expand Up @@ -1647,6 +1649,9 @@ void homeform::trainProgramSignals() {
connect(trainProgram, &trainprogram::stop, this, &homeform::StopFromTrainProgram);
connect(trainProgram, &trainprogram::lap, this, &homeform::Lap);
connect(trainProgram, &trainprogram::toastRequest, this, &homeform::onToastRequested);
// Connect training program speed changes to reset HR PID timer
connect(trainProgram, &trainprogram::changeSpeed, this,
&homeform::onTrainingProgramSpeedChanged);
if (bluetoothManager->device()->deviceType() == TREADMILL) {
connect(trainProgram, &trainprogram::changeSpeed, ((treadmill *)bluetoothManager->device()),
&treadmill::changeSpeed);
Expand Down Expand Up @@ -1738,6 +1743,13 @@ void homeform::onToastRequested(QString message) {
}
}

void homeform::onTrainingProgramSpeedChanged(double speed) {
// Record the timestamp when the training program changed speed
// This is used by the HR PID controller to avoid race conditions
lastTrainingProgramSpeedChange = QDateTime::currentDateTime();
}


QStringList homeform::tile_order() {

QStringList r;
Expand Down Expand Up @@ -7300,6 +7312,12 @@ void homeform::update() {

if (!stopped && !paused && bluetoothManager->device()->currentHeart().value() && zone > 0 &&
bluetoothManager->device()->currentSpeed().value() > 0.0f) {
// Skip HR PID adjustments for a period after training program changes speed
// This prevents race conditions where HR PID overwrites training program speed changes
qint64 msSinceSpeedChange = lastTrainingProgramSpeedChange.msecsTo(QDateTime::currentDateTime());
bool recentSpeedChange = (msSinceSpeedChange < (delta * 1000));

if (!recentSpeedChange) {
if (bluetoothManager->device()->deviceType() == TREADMILL) {

const double step = 0.2;
Expand Down Expand Up @@ -7411,6 +7429,7 @@ void homeform::update() {
((rower *)bluetoothManager->device())->changeResistance(currentResistance + step);
}
}
} // Close the if (!recentSpeedChange) block
}
}
} else if ((settings.value(QZSettings::treadmill_pid_heart_min, QZSettings::default_treadmill_pid_heart_min)
Expand Down Expand Up @@ -7468,6 +7487,12 @@ void homeform::update() {
<< QStringLiteral("HRmin:") << hrmin << QStringLiteral("HRmax:") << hrmax
<< QStringLiteral("fromTrainProgram:") << fromTrainProgram;

// Skip HR PID adjustments for a period after training program changes speed
// This prevents race conditions where HR PID overwrites training program speed changes
qint64 msSinceSpeedChange = lastTrainingProgramSpeedChange.msecsTo(QDateTime::currentDateTime());
bool recentSpeedChange = (msSinceSpeedChange < (delta * 1000));

if (!recentSpeedChange) {
if (bluetoothManager->device()->deviceType() == TREADMILL) {

const double step = 0.2;
Expand Down Expand Up @@ -7589,10 +7614,11 @@ void homeform::update() {
qDebug() << QStringLiteral("ROWING PID HR - HR < HRmin, INCREASING resistance from")
<< currentResistance << QStringLiteral("to") << (currentResistance + step);
((rower *)bluetoothManager->device())->changeResistance(currentResistance + step);
} else {
qDebug() << QStringLiteral("ROWING PID HR - No action taken (in zone or at limits)");
}
}
} else {
qDebug() << QStringLiteral("ROWING PID HR - No action taken (in zone or at limits)");
}
}
} // Close the if (!recentSpeedChange) block
}
}
}
Expand Down
4 changes: 4 additions & 0 deletions src/homeform.h
Original file line number Diff line number Diff line change
Expand Up @@ -974,6 +974,9 @@ class homeform : public QObject {
QTimer *backupTimer;
QTimer *automaticShiftingTimer;

// HR PID controller state - tracks when training program changes speed to prevent race conditions
QDateTime lastTrainingProgramSpeedChange = QDateTime::fromMSecsSinceEpoch(0);

// FIT backup threading
QThread *fitBackupThread;
FitBackupWriter *fitBackupWriter;
Expand Down Expand Up @@ -1089,6 +1092,7 @@ class homeform : public QObject {
void saveSessionAsTrainingProgram();
void strava_connect_clicked();
void trainProgramSignals();
void onTrainingProgramSpeedChanged(double speed);
void refresh_bluetooth_devices_clicked();
void onStravaGranted();
void onStravaAuthorizeWithBrowser(const QUrl &url);
Expand Down
Loading