Skip to content

Commit e91c252

Browse files
torvaldsdirkhh
authored andcommitted
BLE: add list of known good/bad BLE GATT services
We've tried to do this "automagic" service discovery, and it mostly works, but then occasionally it doesn't. Making things worse, I think different platforms end up enumerating services differently, so our "pick the first service that looks like it might be a serial service" ends up working on some platforms, but not necessarily on others. Because "first" might be different. So start a list of known good/bad services - and fall back to the old logic when you can't decide reliably. This fills in juat a few cases that I can easily check myself, and the "details" field for them may be incomplete. For example, I know Nordic Semiconductor has their vendor-specific UUIDs, and they can be found in different devices, so calling them "Nordic UART" and "Nordic Flash" services makes sense. But the "Scubapro i770R" service? It might indeed be specific to the Scubapro i770R. Or it might be a general service UUID that Pelagic uses. Or it might be the service UUID of a particular chip, and found in dive computers from other designs too (and not necessarily in all i770R's either). So this is a preliminary first stab at this, and I'm sure we'll extend the list and possibly improve on the explanations. Signed-off-by: Linus Torvalds <[email protected]>
1 parent a7440ce commit e91c252

File tree

1 file changed

+97
-10
lines changed

1 file changed

+97
-10
lines changed

core/qt-ble.cpp

Lines changed: 97 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -101,31 +101,118 @@ void BLEObject::writeCompleted(const QLowEnergyDescriptor&, const QByteArray&)
101101
desc_written++;
102102
}
103103

104+
struct uud_match {
105+
const char *uuid, *details;
106+
};
107+
108+
static const char *match_service(const QBluetoothUuid &service, const struct uud_match *array)
109+
{
110+
const char *uuid;
111+
112+
while ((uuid = array->uuid) != NULL) {
113+
if (service == QUuid(uuid))
114+
return array->details;
115+
array++;
116+
}
117+
return NULL;
118+
}
119+
120+
//
121+
// Known BLE GATT service UUID's that we should prefer for the serial
122+
// emulation.
123+
//
124+
// The Bluetooth SIG is a disgrace, and never standardized any serial
125+
// communication over BLE. They should just have specified a standard
126+
// UUID for serial service, but preferred their idiotic model of
127+
// "vendor specific" garbage instead. So everybody has made their own
128+
// serial protocol over BLE GATT, which all look fairly similar, but
129+
// with pointless and stupid differences just because the BLE SIG
130+
// couldn't be arsed to do their job properly.
131+
//
132+
// Am I bitter? Just a bit. I know that "standards bodies" is just a
133+
// fancy way of saying "incompetent tech politics", but still.. It's
134+
// not like legacy BT didn't have a standard serial encapsulation.
135+
// Oh. It did, didn't it?
136+
//
137+
static const struct uud_match serial_service_uuids[] = {
138+
{ "0000fefb-0000-1000-8000-00805f9b34fb", "Heinrichs-Weikamp" },
139+
{ "544e326b-5b72-c6b0-1c46-41c1bc448118", "Mares BlueLink Pro" },
140+
{ "cb3c4555-d670-4670-bc20-b61dbc851e9a", "Aqualung i770R" },
141+
{ "6e400001-b5a3-f393-e0a9-e50e24dcca9e", "Nordic Semi UART" },
142+
{ "98ae7120-e62e-11e3-badd-0002a5d5c51b", "Suunto EON Steel" },
143+
{ NULL, }
144+
};
145+
146+
//
147+
// Sometimes we don't know which is the good service, but we can tell
148+
// that a service is NOT a serial service because we've seen that
149+
// people use it for firmware upgrades.
150+
//
151+
static const struct uud_match upgrade_service_uuids[] = {
152+
{ "9e5d1e47-5c13-43a0-8635-82ad38a1386f", "Flash Upgrade" },
153+
{ "00001530-1212-efde-1523-785feabcd123", "Nordic Upgrade" },
154+
{ NULL, }
155+
};
156+
157+
static const char *is_known_serial_service(const QBluetoothUuid &service)
158+
{
159+
return match_service(service, serial_service_uuids);
160+
}
161+
162+
static const char *is_known_bad_service(const QBluetoothUuid &service)
163+
{
164+
return match_service(service, upgrade_service_uuids);
165+
}
166+
104167
void BLEObject::addService(const QBluetoothUuid &newService)
105168
{
169+
const char *details;
170+
106171
qDebug() << "Found service" << newService;
107172

108-
if (IS_HW(device)) {
109-
/* The HW BT/BLE piece or hardware uses, what we
110-
* call here, "a Standard UUID. It is standard because the Telit/Stollmann
111-
* manufacturer applied for an own UUID for its product, and this was granted
112-
* by the Bluetooth SIG.
113-
*/
114-
if (newService != QUuid("{0000fefb-0000-1000-8000-00805f9b34fb}"))
115-
return; // skip all services except the right one
173+
//
174+
// Known bad service that we should ignore?
175+
// (typically firmware update service).
176+
//
177+
details = is_known_bad_service(newService);
178+
if (details) {
179+
qDebug () << " .. ignoring service" << details;
180+
return;
181+
}
182+
183+
//
184+
// If it's a known serial service, clear any other previous
185+
// services we've found - we'll use this one.
186+
//
187+
// Note that if it's not _known_ to be good, we'll ignore
188+
// any standard services. They are usually things like battery
189+
// status or device name services.
190+
//
191+
// But Heinrich-Weicamp actually has a standard service ID in the
192+
// known good category, because Telit/Stollmann (the manufacturer)
193+
// applied for a UUID for its product.
194+
//
195+
// If it's not a known service, and not a standard one, we'll just
196+
// add it to the list and then we'll try our heuristics on that
197+
// list.
198+
//
199+
details = is_known_serial_service(newService);
200+
if (details) {
201+
qDebug () << " .. recognized service" << details;
202+
services.clear();
116203
} else {
117204
bool isStandardUuid = false;
118205

119206
newService.toUInt16(&isStandardUuid);
120207
if (isStandardUuid) {
121-
qDebug () << " .. ignoring standard service" << newService;
208+
qDebug () << " .. ignoring standard service";
122209
return;
123210
}
124211
}
125212

126213
auto service = controller->createServiceObject(newService, this);
127-
qDebug() << " .. created service object" << service;
128214
if (service) {
215+
qDebug() << " .. starting discovery";
129216
services.append(service);
130217
service->discoverDetails();
131218
}

0 commit comments

Comments
 (0)