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
17 changes: 14 additions & 3 deletions src/devices/dircon/dirconmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,15 @@ using namespace std::chrono_literals;
DP_PROCESS_WRITE_NULL, P1, P2, P3) \
OP(FITNESS_MACHINE_CYCLE, 0x2AD6, DPKT_CHAR_PROP_FLAG_READ, DM_BT("\x0A\x00\x96\x00\x0A\x00"), \
DP_PROCESS_WRITE_NULL, P1, P2, P3) \
OP(FITNESS_MACHINE_CYCLE, 0x2AD9, DPKT_CHAR_PROP_FLAG_WRITE | DPKT_CHAR_PROP_FLAG_INDICATE, DM_BT("\x00"), DP_PROCESS_WRITE_2AD9, P1, P2, P3) \
OP(FITNESS_MACHINE_CYCLE, 0x2AD9, DPKT_CHAR_PROP_FLAG_WRITE, DM_BT("\x00"), DP_PROCESS_WRITE_2AD9, P1, P2, P3) \
OP(FITNESS_MACHINE_CYCLE, 0xE005, DPKT_CHAR_PROP_FLAG_WRITE, DM_BT("\x00"), DP_PROCESS_WRITE_E005, P1, P2, P3) \
OP(FITNESS_MACHINE_CYCLE, 0x2AD2, DPKT_CHAR_PROP_FLAG_NOTIFY, DM_BT("\x00"), DP_PROCESS_WRITE_NULL, P1, P2, P3) \
OP(FITNESS_MACHINE_CYCLE, 0x2AD3, DPKT_CHAR_PROP_FLAG_READ, DM_BT("\x00\x01"), DP_PROCESS_WRITE_NULL, P1, P2, P3) \
OP(FITNESS_MACHINE_TREADMILL, 0x2ACC, DPKT_CHAR_PROP_FLAG_READ, DM_BT("\x08\x14\x00\x00\x00\x00\x00\x00"), \
DP_PROCESS_WRITE_NULL, P1, P2, P3) \
OP(FITNESS_MACHINE_TREADMILL, 0x2AD6, DPKT_CHAR_PROP_FLAG_READ, DM_BT("\x0A\x00\x96\x00\x0A\x00"), \
DP_PROCESS_WRITE_NULL, P1, P2, P3) \
OP(FITNESS_MACHINE_TREADMILL, 0x2AD9, DPKT_CHAR_PROP_FLAG_WRITE | DPKT_CHAR_PROP_FLAG_INDICATE, DM_BT("\x00"), DP_PROCESS_WRITE_2AD9T, P1, P2, \
OP(FITNESS_MACHINE_TREADMILL, 0x2AD9, DPKT_CHAR_PROP_FLAG_WRITE, DM_BT("\x00"), DP_PROCESS_WRITE_2AD9T, P1, P2, \
P3) \
OP(FITNESS_MACHINE_TREADMILL, 0x2ACD, DPKT_CHAR_PROP_FLAG_NOTIFY, DM_BT("\x00"), DP_PROCESS_WRITE_NULL, P1, P2, \
P3) \
Expand Down Expand Up @@ -210,7 +210,18 @@ DirconManager::DirconManager(bluetoothdevice *Bike, int8_t bikeResistanceOffset,
} else {
DM_CHAR_OP(DM_CHAR_INIT_OP, services, service, 0, ZWIFT_CHAR_DISABLED_OP);
}


// Add INDICATE flag to 0x2AD9 characteristics only for Rouvy compatibility (Apple TV/Windows support)
if (rouvy_compatibility) {
foreach (DirconProcessorService *s, services) {
foreach (DirconProcessorCharacteristic *c, s->chars) {
if (c->uuid == 0x2AD9 && (c->type & DPKT_CHAR_PROP_FLAG_WRITE)) {
c->type |= DPKT_CHAR_PROP_FLAG_INDICATE;
}
}
}
}

connect(writeP2AD9, SIGNAL(changeInclination(double, double)), this, SIGNAL(changeInclination(double, double)));
connect(writeP2AD9, SIGNAL(ftmsCharacteristicChanged(QLowEnergyCharacteristic, QByteArray)), this,
SIGNAL(ftmsCharacteristicChanged(QLowEnergyCharacteristic, QByteArray)));
Expand Down
25 changes: 16 additions & 9 deletions src/devices/dircon/dirconpacket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ DirconPacket::operator QString() const {
.arg(us);
}

int DirconPacket::parse(const QByteArray &buf, int last_seq_number) {
int DirconPacket::parse(const QByteArray &buf, int last_seq_number, bool rouvy_compatibility) {
if (buf.size() >= DPKT_MESSAGE_HEADER_LENGTH) {
this->MessageVersion = ((quint8)buf.at(0));
this->Identifier = ((quint8)buf.at(1));
Expand Down Expand Up @@ -96,11 +96,14 @@ int DirconPacket::parse(const QByteArray &buf, int last_seq_number) {
} else
return DPKT_PARSE_ERROR - rembuf;
} else if (this->Identifier == DPKT_MSGID_ENABLE_CHARACTERISTIC_NOTIFICATIONS) {
if (this->Length >= 16) {
// Rouvy compatibility: relaxed validation (>=), standard: strict validation (==)
bool length_valid = rouvy_compatibility ? (this->Length >= 16) : (this->Length == 16 || this->Length == 17);
if (length_valid) {
quint16 uuid = ((quint16)buf.at(DPKT_MESSAGE_HEADER_LENGTH + DPKT_POS_SH8)) << 8;
uuid |= ((quint16)buf.at(DPKT_MESSAGE_HEADER_LENGTH + DPKT_POS_SH0)) & 0x00FF;
this->uuid = uuid;
if (this->Length >= 17) {
bool has_data = rouvy_compatibility ? (this->Length >= 17) : (this->Length == 17);
if (has_data) {
this->isRequest = true;
this->additional_data = buf.mid(DPKT_MESSAGE_HEADER_LENGTH + 16, 1);
}
Expand All @@ -118,9 +121,13 @@ int DirconPacket::parse(const QByteArray &buf, int last_seq_number) {
} else
return DPKT_PARSE_ERROR - rembuf;
} else if (this->Identifier == DPKT_MSGID_UNKNOWN_0x07) {
if (this->Length == 0) {
this->isRequest = this->checkIsRequest(last_seq_number);
return DPKT_MESSAGE_HEADER_LENGTH;
// Only handle 0x07 message when Rouvy compatibility is enabled
if (rouvy_compatibility) {
if (this->Length == 0) {
this->isRequest = this->checkIsRequest(last_seq_number);
return DPKT_MESSAGE_HEADER_LENGTH;
} else
return DPKT_PARSE_ERROR - rembuf;
} else
return DPKT_PARSE_ERROR - rembuf;
} else
Expand Down Expand Up @@ -149,7 +156,7 @@ DirconPacket &DirconPacket::operator=(const DirconPacket &cp) {
return *this;
}

QByteArray DirconPacket::encode(int last_seq_number) {
QByteArray DirconPacket::encode(int last_seq_number, bool rouvy_compatibility) {
quint16 u;
int i = 0;
if (this->Identifier == DPKT_MSGID_ERROR)
Expand Down Expand Up @@ -188,8 +195,8 @@ QByteArray DirconPacket::encode(int last_seq_number) {
}
}
}
} else if (this->Identifier == DPKT_MSGID_UNKNOWN_0x07) {
// Unknown message 0x07 - always respond with empty payload
} else if (this->Identifier == DPKT_MSGID_UNKNOWN_0x07 && rouvy_compatibility) {
// Unknown message 0x07 - only encode when Rouvy compatibility enabled
this->Length = 0;
byteout.append(2, 0);
} else if (this->Identifier == DPKT_MSGID_DISCOVER_CHARACTERISTICS && !this->isRequest) {
Expand Down
4 changes: 2 additions & 2 deletions src/devices/dircon/dirconpacket.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ class DirconPacket {
bool isRequest = false;
DirconPacket(const DirconPacket &cp);
DirconPacket &operator=(const DirconPacket &cp);
QByteArray encode(int last_seq_number);
int parse(const QByteArray &buf, int last_seq_number);
QByteArray encode(int last_seq_number, bool rouvy_compatibility = false);
int parse(const QByteArray &buf, int last_seq_number, bool rouvy_compatibility = false);
operator QString() const;

private:
Expand Down
17 changes: 11 additions & 6 deletions src/devices/dircon/dirconprocessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ void DirconProcessor::tcpNewConnection() {
initPkt.ResponseCode = DPKT_RESPCODE_SUCCESS_REQUEST;
initPkt.uuid = 0x2AD2;
initPkt.additional_data = QByteArray(29, 0x00); // Empty data for now
QByteArray initData = initPkt.encode(0);
QByteArray initData = initPkt.encode(0, rouvy_compatibility);
socket->write(initData);
socket->flush();
qDebug() << "Sent initial notification for 0x2AD2 to" << socket->peerAddress().toString();
Expand Down Expand Up @@ -224,7 +224,12 @@ DirconPacket DirconProcessor::processPacket(DirconProcessorClient *client, const
foreach (cc, service->chars) {
if (cc->uuid == pkt.uuid) {
cfound = true;
if (cc->type & (DPKT_CHAR_PROP_FLAG_NOTIFY | DPKT_CHAR_PROP_FLAG_INDICATE)) {
// Check for INDICATE only when Rouvy compatibility is enabled
quint8 notify_flags = DPKT_CHAR_PROP_FLAG_NOTIFY;
if (rouvy_compatibility) {
notify_flags |= DPKT_CHAR_PROP_FLAG_INDICATE;
}
if (cc->type & notify_flags) {
int idx;
char notif = pkt.additional_data.at(0);
out.uuid = pkt.uuid;
Expand Down Expand Up @@ -267,7 +272,7 @@ bool DirconProcessor::sendCharacteristicNotification(quint16 uuid, const QByteAr
client = i.value();
if (client->char_notify.indexOf(uuid) >= 0 || settings.value(QZSettings::zwift_play_emulator, QZSettings::default_zwift_play_emulator).toBool()) {
socket = i.key();
rvs = socket->write(pkt.encode(0)) < 0;
rvs = socket->write(pkt.encode(0, rouvy_compatibility)) < 0;
if (rvs)
rv = false;
qDebug() << serverName << "sending to" << socket->peerAddress().toString() << ":" << socket->peerPort()
Expand All @@ -288,7 +293,7 @@ void DirconProcessor::tcpDataAvailable() {
client->buffer.append(data);
while (1) {
DirconPacket pkt;
buflimit = pkt.parse(client->buffer, client->seq);
buflimit = pkt.parse(client->buffer, client->seq, rouvy_compatibility);
qDebug() << "Pkt for uuid" << serverName << "parsed rv=" << buflimit << " ->" << pkt;
if (buflimit > 0) {
rembuf = buflimit;
Expand All @@ -307,7 +312,7 @@ void DirconProcessor::tcpDataAvailable() {
DirconPacket resp = processPacket(client, pkt);
qDebug() << "Sending resp for uuid" << serverName << ":" << resp;
if (resp.Identifier != DPKT_MSGID_ERROR) {
QByteArray byteout = resp.encode(pkt.SequenceNumber);
QByteArray byteout = resp.encode(pkt.SequenceNumber, rouvy_compatibility);
if (byteout.size() && client && client->sock)
client->sock->write(byteout);
}
Expand All @@ -316,7 +321,7 @@ void DirconProcessor::tcpDataAvailable() {
resp.isRequest = false;
resp.ResponseCode = DPKT_RESPCODE_UNEXPECTED_ERROR;
resp.Identifier = pkt.Identifier;
QByteArray byteout = resp.encode(pkt.SequenceNumber);
QByteArray byteout = resp.encode(pkt.SequenceNumber, rouvy_compatibility);
if (byteout.size() && client && client->sock)
client->sock->write(byteout);
} else
Expand Down
Loading