Compare commits

...

3 Commits

Author SHA1 Message Date
Roberto Viola
f49ac87ff8 Update wahookickrsnapbike.cpp 2025-09-18 10:19:07 +02:00
Roberto Viola
2aba7ddfe1 adding debug popup 2025-09-18 09:38:30 +02:00
Roberto Viola
d02ca5a934 Wahoo Commands Queue 2025-09-16 15:45:30 +02:00
2 changed files with 95 additions and 12 deletions

View File

@@ -34,6 +34,17 @@ wahookickrsnapbike::wahookickrsnapbike(bool noWriteResistance, bool noHeartServi
refresh->start(settings.value(QZSettings::poll_device_time, QZSettings::default_poll_device_time).toInt());
wheelCircumference::GearTable g;
g.printTable();
// Setup op timeout handler for serialized commands
_opTimeout.setSingleShot(true);
connect(&_opTimeout, &QTimer::timeout, this, [this]() {
// Timeout waiting for ack; clear and try next pending to avoid stall
if (_currentOp != WahooOp::None) {
emit debug(QStringLiteral("Ack timeout; releasing op and continuing queue"));
}
_currentOp = WahooOp::None;
processNextPending();
});
}
void wahookickrsnapbike::restoreDefaultWheelDiameter() {
@@ -305,10 +316,8 @@ void wahookickrsnapbike::update() {
if(KICKR_SNAP) {
inclinationChanged(lastGrade, lastGrade);
} else {
QByteArray a = setWheelCircumference(wheelCircumference::gearsToWheelDiameter(gears()));
uint8_t b[20];
memcpy(b, a.constData(), a.length());
writeCharacteristic(b, a.length(), "setWheelCircumference", false, false);
// Queue wheel circumference change (higher priority)
sendWheelCircumferenceNow(wheelCircumference::gearsToWheelDiameter(gears()));
lastGrade = 999; // to force a change
}
}
@@ -442,6 +451,26 @@ void wahookickrsnapbike::handleCharacteristicValueChanged(const QBluetoothUuid &
qDebug() << QStringLiteral(" << ") << newValue.toHex(' ') << uuid;
// Detect acks for serialized commands (format: 0x01 <cmdId> 0x01 0x00 ...)
if (newValue.size() >= 3 && (uint8_t)newValue.at(0) == 0x01) {
uint8_t cmd = (uint8_t)newValue.at(1);
uint8_t status = (uint8_t)newValue.at(2);
if ((cmd == _setSimGrade || cmd == _setWheelCircumference) && status == 0x01) {
if(cmd == _setWheelCircumference) {
homeform::singleton()->setToastRequested("Gear accepted from the trainer");
}
// Ack received for our tracked op; release and continue
if ((_currentOp == WahooOp::SimGrade && cmd == _setSimGrade) ||
(_currentOp == WahooOp::WheelCircumference && cmd == _setWheelCircumference)) {
_opTimeout.stop();
_currentOp = WahooOp::None;
processNextPending();
}
}
}
if (uuid == QBluetoothUuid::CyclingPowerMeasurement) {
lastPacket = newValue;
@@ -964,10 +993,7 @@ void wahookickrsnapbike::inclinationChanged(double grade, double percentage) {
emit debug(QStringLiteral("writing inclination ") + QString::number(grade));
double g = grade;
g += gears();
QByteArray a = setSimGrade(g);
uint8_t b[20];
memcpy(b, a.constData(), a.length());
writeCharacteristic(b, a.length(), "setSimGrade", false, false);
sendSimGradeNow(g);
} else {
if(lastCommandErgMode) {
lastGrade = grade + 1; // to force a refresh
@@ -987,14 +1013,59 @@ void wahookickrsnapbike::inclinationChanged(double grade, double percentage) {
g += gears() * 0.5;
qDebug() << "adding gear offset so " << g;
}
QByteArray a = setSimGrade(g);
uint8_t b[20];
memcpy(b, a.constData(), a.length());
writeCharacteristic(b, a.length(), "setSimGrade", false, false);
sendSimGradeNow(g);
lastCommandErgMode = false;
}
}
// Send or enqueue: SimGrade
void wahookickrsnapbike::sendSimGradeNow(double grade) {
// If an operation is in flight, store latest grade and return
if (_currentOp != WahooOp::None) {
_pendingSimGrade = true;
_pendingSimGradeValue = grade;
return;
}
QByteArray a = setSimGrade(grade);
uint8_t b[20];
memcpy(b, a.constData(), a.length());
_currentOp = WahooOp::SimGrade;
// Send without blocking; wait for explicit ack in handleCharacteristicValueChanged
writeCharacteristic(b, a.length(), "setSimGrade", false, false);
_opTimeout.start(1000);
}
// Send or enqueue: Wheel Circumference
void wahookickrsnapbike::sendWheelCircumferenceNow(double mm) {
// If an operation is in flight, prefer to hold latest wheel circ (priority for next send)
if (_currentOp != WahooOp::None) {
_pendingWheelCirc = true;
_pendingWheelCircValue = mm;
return;
}
QByteArray a = setWheelCircumference(mm);
uint8_t b[20];
memcpy(b, a.constData(), a.length());
_currentOp = WahooOp::WheelCircumference;
writeCharacteristic(b, a.length(), "setWheelCircumference", false, false);
_opTimeout.start(1000);
}
// Process next pending item, wheel circumference has priority
void wahookickrsnapbike::processNextPending() {
if (_currentOp != WahooOp::None) return;
if (_pendingWheelCirc) {
_pendingWheelCirc = false;
sendWheelCircumferenceNow(_pendingWheelCircValue);
return;
}
if (_pendingSimGrade) {
_pendingSimGrade = false;
sendSimGradeNow(_pendingSimGradeValue);
return;
}
}
bool wahookickrsnapbike::inclinationAvailableByHardware() {
return KICKR_BIKE;
}

View File

@@ -81,6 +81,18 @@ class wahookickrsnapbike : public bike {
bool writeCharacteristic(uint8_t *data, uint8_t data_len, QString info, bool disable_log = false,
bool wait_for_response = false);
// Serialized command handling for setSimGrade and setWheelCircumference
enum class WahooOp { None, SimGrade, WheelCircumference };
WahooOp _currentOp = WahooOp::None;
bool _pendingSimGrade = false;
double _pendingSimGradeValue = 0.0;
bool _pendingWheelCirc = false;
double _pendingWheelCircValue = 0.0;
QTimer _opTimeout;
void processNextPending();
void sendSimGradeNow(double grade);
void sendWheelCircumferenceNow(double mm);
uint16_t wattsFromResistance(double resistance);
metric ResistanceFromFTMSAccessory;
void startDiscover();