Skip to content
Open
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
1 change: 1 addition & 0 deletions src/devices/bluetooth.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2808,6 +2808,7 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
this->signalBluetoothDeviceConnected(snodeBike);
} else if (((b.name().startsWith(QStringLiteral("FS-")) && fitplus_bike) ||
(b.name().toUpper().startsWith("H9110 OSAKA")) ||
(b.name().toUpper().startsWith("BUREVER BE1")) ||
b.name().startsWith(QStringLiteral("MRK-"))) &&
!fitPlusBike && !ftmsBike && !ftmsRower && !snodeBike && !horizonTreadmill && !trxappgateusbRower && filter) {
this->setLastBluetoothDevice(b);
Expand Down
75 changes: 73 additions & 2 deletions src/devices/fitplusbike/fitplusbike.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ void fitplusbike::forceResistance(resistance_t requestResistance) {
bool virtufit_etappe = settings.value(QZSettings::virtufit_etappe, QZSettings::default_virtufit_etappe).toBool();
bool sportstech_sx600 = settings.value(QZSettings::sportstech_sx600, QZSettings::default_sportstech_sx600).toBool();
requestResistanceCompleted = false;
if (virtufit_etappe || merach_MRK || H9110_OSAKA) {
if (virtufit_etappe || merach_MRK || H9110_OSAKA || burever_BE1) {
if (requestResistance == 1) {
uint8_t res[] = {0x02, 0x44, 0x05, 0x01, 0xf9, 0xb9, 0x03};
writeCharacteristic(res, sizeof(res), "force resistance", false, true);
Expand Down Expand Up @@ -189,6 +189,13 @@ void fitplusbike::forceResistance(resistance_t requestResistance) {
uint8_t res[] = {0x02, 0x44, 0x05, 0x20, 0x00, 0x61, 0x03};
writeCharacteristic(res, sizeof(res), "force resistance", false, true);
}

if (burever_BE1) {
requestResistanceCompleted = true;
Resistance = requestResistance;
emit resistanceRead(Resistance.value());
m_pelotonResistance = bikeResistanceToPeloton(Resistance.value());
}
} else if (sportstech_sx600) {
if (requestResistance == 1) {
uint8_t res[] = {0x02, 0x44, 0x05, 0x00, 0x00, 0x41, 0x03};
Expand Down Expand Up @@ -309,7 +316,7 @@ void fitplusbike::update() {
bool sportstech_sx600 =
settings.value(QZSettings::sportstech_sx600, QZSettings::default_sportstech_sx600).toBool();

if (virtufit_etappe || merach_MRK || sportstech_sx600 || H9110_OSAKA) {
if (virtufit_etappe || merach_MRK || sportstech_sx600 || H9110_OSAKA || burever_BE1) {

} else {
m_watt = wattFromHR(false);
Expand Down Expand Up @@ -397,6 +404,62 @@ void fitplusbike::update() {
}
}

bool fitplusbike::parseBureverPacket(const QByteArray &newValue, const QDateTime &now) {
QSettings settings;

if (newValue.length() == 15 && (uint8_t)newValue.at(0) == 0x02 && (uint8_t)newValue.at(1) == 0x42 &&
(uint8_t)newValue.at(2) == 0x02) {
if (settings.value(QZSettings::cadence_sensor_name, QZSettings::default_cadence_sensor_name)
.toString()
.startsWith(QStringLiteral("Disabled"))) {
Cadence = (uint8_t)newValue.at(6);
}

if (settings.value(QZSettings::power_sensor_name, QZSettings::default_power_sensor_name)
.toString()
.startsWith(QStringLiteral("Disabled"))) {
m_watt = (double)((((uint8_t)newValue.at(10)) << 8) | ((uint8_t)newValue.at(9))) / 10.0;
}

if (!settings.value(QZSettings::speed_power_based, QZSettings::default_speed_power_based).toBool()) {
Speed = (double)((((uint8_t)newValue.at(4)) << 8) | ((uint8_t)newValue.at(3))) / 100.0;
} else {
Speed = metric::calculateSpeedFromPower(
watts(), Inclination.value(), Speed.value(),
fabs(now.msecsTo(Speed.lastChanged()) / 1000.0), this->speedLimit());
}

qDebug() << QStringLiteral("Current Speed: ") + QString::number(Speed.value());
qDebug() << QStringLiteral("Current Cadence: ") + QString::number(Cadence.value());
qDebug() << QStringLiteral("Current Watt: ") + QString::number(m_watt.value());
qDebug() << QStringLiteral("Current Resistance: ") + QString::number(Resistance.value());
lastRefreshCharacteristicChanged = now;
return true;
}

if (newValue.length() == 14 && (uint8_t)newValue.at(0) == 0x02 && (uint8_t)newValue.at(1) == 0x43 &&
(uint8_t)newValue.at(2) == 0x01) {
const uint16_t elapsedSeconds = (((uint8_t)newValue.at(4)) << 8) | ((uint8_t)newValue.at(3));
const uint16_t distanceRaw = (((uint8_t)newValue.at(6)) << 8) | ((uint8_t)newValue.at(5));
const uint16_t caloriesRaw = (((uint8_t)newValue.at(8)) << 8) | ((uint8_t)newValue.at(7));
const uint16_t crankRevsRaw = (((uint8_t)newValue.at(10)) << 8) | ((uint8_t)newValue.at(9));

Distance = ((double)distanceRaw) / 1000.0;
KCal = caloriesRaw;
CrankRevs = crankRevsRaw;
LastCrankEventTime = (uint16_t)((elapsedSeconds * 1024U) & 0xffff);

qDebug() << QStringLiteral("Current Calculate Distance: ") + QString::number(Distance.value());
qDebug() << QStringLiteral("Current KCal: ") + QString::number(KCal.value());
qDebug() << QStringLiteral("Current CrankRevs: ") + QString::number(CrankRevs);
qDebug() << QStringLiteral("Last CrankEventTime: ") + QString::number(LastCrankEventTime);
lastRefreshCharacteristicChanged = now;
return true;
}

return false;
}

void fitplusbike::serviceDiscovered(const QBluetoothUuid &gatt) {
qDebug() << QStringLiteral("serviceDiscovered ") + gatt.toString();
}
Expand All @@ -416,6 +479,10 @@ void fitplusbike::characteristicChanged(const QLowEnergyCharacteristic &characte
bool virtufit_etappe = settings.value(QZSettings::virtufit_etappe, QZSettings::default_virtufit_etappe).toBool();
bool sportstech_sx600 = settings.value(QZSettings::sportstech_sx600, QZSettings::default_sportstech_sx600).toBool();

if (burever_BE1 && parseBureverPacket(newValue, now)) {
return;
}

if (sportstech_sx600 && characteristic.uuid() == QBluetoothUuid((quint16)0x2AD2)) {
bool disable_hr_frommachinery =
settings.value(QZSettings::heart_ignore_builtin, QZSettings::default_heart_ignore_builtin).toBool();
Expand Down Expand Up @@ -1018,6 +1085,10 @@ void fitplusbike::deviceDiscovered(const QBluetoothDeviceInfo &device) {
qDebug() << QStringLiteral("H9110 OSAKA workaround enabled!");
max_resistance = 32;
H9110_OSAKA = true;
} else if (device.name().toUpper().startsWith("BUREVER BE1")) {
qDebug() << QStringLiteral("Burever BE1 workaround enabled!");
burever_BE1 = true;
max_resistance = 32;
}

m_control = QLowEnergyController::createCentral(bluetoothDevice, this);
Expand Down
2 changes: 2 additions & 0 deletions src/devices/fitplusbike/fitplusbike.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class fitplusbike : public bike {
void btinit();
void writeCharacteristic(uint8_t *data, uint8_t data_len, const QString &info, bool disable_log = false,
bool wait_for_response = false);
bool parseBureverPacket(const QByteArray &newValue, const QDateTime &now);
void startDiscover();
void forceResistance(resistance_t requestResistance);
void sendPoll();
Expand Down Expand Up @@ -80,6 +81,7 @@ class fitplusbike : public bike {

bool merach_MRK = false;
bool H9110_OSAKA = false;
bool burever_BE1 = false;

#ifdef Q_OS_IOS
lockscreen *h = 0;
Expand Down
Loading