Ticket Created
over 4 years ago

WERETECH-9123

Connect-IQ Ble advertising layer parsing bug, prevent many devices to function properly. (paired or not paired) Toybox::BluetoothLowEnergy::ScanResult:getRawData(), getServiceData , getServiceUuids are broken

Connect-IQ Ble advertising layer parsing bug, prevent many devices to function properly.
Reproduced on simulator, fenix 6x (9.0), fenix 6s.

Used bluetooth sniffer to confirm that the advertising bytes were correct, and different than what connect IQ returns.

When not paired :

Toybox::BluetoothLowEnergy::ScanResult:getRawData(), getServiceData , getServiceUuids
 are not receiving the proper data bytes from the network layer when **to be confirmed !!**the last advertising data type are :
 Complete List of 16-bit Service Class UUIDs

which is very common !
if the order is changed, and something else is set at the end, there is no problem at all.

In order to demonstrate this, I'm parsing the content of getRaw, using 2 stryd devices (ble indeed), one hardware v4 (last advertising data, is Shortened local name), which is working perfectly.

The parser, read all data, and decode them, now problem on this trace, it is complete, and perfectly good and valid.

devicename:Stryd kl
raw Adverting Data:[2, 1, 6, 7, 3, 24, 24, 20, 24, 10, 24, 9, 255, 170, 170, 210, 91, 0, 81, 82, 41, 9, 8, 83, 116, 114, 121, 100, 32, 107, 108]
--[AD Dump:
----[Record Dump:
    AD Len:2
    AD Type:Flags
    AD Type Integer:1
    AD Data Integer:[6]
    AD Data Hex:06
----[Record Dump:
    AD Len:7
    AD Type:Complete List of 16-bit Service Class UUIDs
    AD Type Integer:3
    AD Data Integer:[24, 24, 20, 24, 10, 24]
    AD Data Hex:181814180a18
    AD Data 16bits Service Class UUIDs:
        UUID: 0x1818
        UUID: 0x1418
        UUID: 0x0A18
----[Record Dump:
    AD Len:9
    AD Type:Manufacturer Specific Data
    AD Type Integer:255
    AD Data Integer:[170, 170, 210, 91, 0, 81, 82, 41]
    AD Data Hex:aaaad25b00515229
    AD Data String:ªªÒ[QR)
----[Record Dump:
    AD Len:9
    AD Type:Shortened Local Name
    AD Type Integer:8
    AD Data Integer:[83, 116, 114, 121, 100, 32, 107, 108]
    AD Data Hex:5374727964206b6c
    AD Data String:Stryd kl
--end of AD Dump]


Now, another generation of stryd (v3), where by lack of lack, advertising data last bytes are ...Complete List of 16-bit Service Class UUIDs

In this case, you can see that the raw data, is not correct, and stop before those advertising data.

If it was only the raw data, it won't be a problem, but getServiceUuids looks to use those bytes... so return none of those services.

devicename:Stryd
raw Adverting Data:[2, 1, 6, 9, 255, 170, 170, 115, 84, 0, 80, 82, 166, 6, 9, 83, 116, 114, 121, 100]
--[AD Dump:
----[Record Dump:
    AD Len:2
    AD Type:Flags
    AD Type Integer:1
    AD Data Integer:[6]
    AD Data Hex:06
----[Record Dump:
    AD Len:9
    AD Type:Manufacturer Specific Data
    AD Type Integer:255
    AD Data Integer:[170, 170, 115, 84, 0, 80, 82, 166]
    AD Data Hex:aaaa7354005052a6
    AD Data String:ªªsTPR¦
----[Record Dump:
    AD Len:6
    AD Type:Complete Local Name
    AD Type Integer:9
    AD Data Integer:[83, 116, 114, 121, 100]
    AD Data Hex:5374727964
    AD Data String:Stryd
--end of AD Dump]


When paired :

Class: Toybox::BluetoothLowEnergy::Device getService() and getServices()

are also affected !

This was confirmed with :
- nrf connect on android
- nrf connect desktop, with the nrf52 dongle I'm using for the simulator (confirmed into the simulator indeed)

Now, if it was only stryd, it would be okay, but my elliptical bike(FTMS profile), also adverstise services at the end... so they are not visible to the watch.

It is the same for many devices I checked, all that was availlable to me.

Is reporting to this forum enough to get it tracked by garmin ? anything else to do ?

Kind Regards.

Klick

  • There are a number of devices where I don't see a name.  Do you see the UUID for the service?  With the app I posted, it's on the summary screen for a scan result

    With the app I posted, I've seen the raw data go as high as 30 bytes, so there is no limit of 20.

    in nRFConnect (this is from the phone version) what do you see from the scan?  Here's an example of one of my devices.  I don't see the name in CIQ, but check the flags on yours:

  • I also see this issue. I am connecting to a Tenergy Solis BTLE meat thermometer. I can find the device via a "heuristic" that makes some guesses based on the ScanResult but the easiest way - looking for the device name "iBBQ" doesn't work. The ScanResult / raw data are truncated and the local name isn't ever included. Both the call to get the name, and looking at the raw data don't work because it's too short. I think the BT stack is either truncating the packet, or is fixed at the 20 byte "normal" MTU and ignores that there is more data.

    I verified that the entire thing is being sent by:

    -nrfConnect desktop

    -nrfConnect mobile

    -Wireshark sniffing traffic when the device is connected to my phone with the Tenergy app, AND when I connect to it with both the simulator and watch

    I have Wireshark logs that are usable with the nordic btle sniffer plugin if that's helpful. It shows clearly that the advertising is all there, every time but the watch and simulator don't ever see the end of it.

  • Displaying stuff like this on the screen can be a bit easier as you don't have to create a log file, and then connect to a pc to see the log file.  As I said in one case, the raw data actually changes over time, so on the screen, that's easy to see.

    In the screen shot I posted, you can easily see the name ("thing17"), and right before that is the UUID, starting with EF, then 68 then 01 and so on.  It's in reverse byte order. 

    here's the function I use for the display.

    y is where you want to start on the screen, font is the font to use, fontH is the high of the font, and the 3 lines comment out are calculated elsewhere (they only need to be done once, and not each time the function is called)

        function hexDump(dc,y,bytes,size) {
        	//hexPerLine=8;
            //twoHex=dc.getTextWidthInPixels("88 ", font);
        	//hexStart=centerW-(twoHex*hexPerLine/2);
        	var i=0;
    		while(i<size) {
    			var j=0;
    			var x=hexStart;
    			while(j<hexPerLine && i<size) {
    				dc.drawText(x,y,font,bytes[i].format("%02x")+" ",Gfx.TEXT_JUSTIFY_LEFT);
    				dc.drawText(x,y+fontH,font,bytes[i].toChar().toString(),Gfx.TEXT_JUSTIFY_LEFT);
    				j++;
    				i++;
    				x+=twoHex;
    			}
    			y+=fontH*2;
    		}
        }

  • I admit that the char is good, but I don't know all the codes from the top of my head, and on some devices, have to count for lenght Slight smile

    that's why I love lazy text decoding :)

  • That's why I display the character under the hex value. Slight smile