Skip to content

Cycling Power Measurement parser fails on valid variable-length packets (expected 35 bytes) while FTMS and CSC parses correctly #51

Description

@Abasz

Summary

Simplicity Connect fails to parse valid Cycling Power Measurement (0x2A63) notifications when only a subset of optional fields are present.

The app reports:

expected data length is 280-bit (35 bytes), read data length is 112-bit (14 bytes)

However, the exact same packet structure is accepted by Garmin devices and conforms to the Bluetooth CPS specification.

Interestingly, FTMS Rower Data parsing works correctly with dynamic optional fields, which suggests the issue is specific to the CPS XML metadata / conditional field handling rather than the generic parser itself.


Reproduction

CPS Measurement packet

Stationary:

30 00 00 00 00 00 00 00 00 00 00 00 00 00

Active:

30 00 1B 00 2B 09 00 00 93 6D 04 00 D1 12

Flags

0x0030

Which means:

  • Bit 4: Wheel Revolution Data Present
  • Bit 5: Crank Revolution Data Present

No other optional fields are present.

This produces a valid 14-byte payload:

Field Size
Flags 2
Instantaneous Power 2
Wheel Revolution Data 6
Crank Revolution Data 4
Total 14

Expected behavior

The packet should parse correctly, similarly to FTMS variable-length characteristics.


Actual behavior

The parser throws:

expected data length is 280-bit (35 bytes), read data length is 112-bit (14 bytes)

and falls back to raw-byte rendering.


Investigation

The issue appears to originate from the XML-driven conditional field parser.

Relevant code:

  • BluetoothXmlParser
  • FieldViewHelper.isFieldPresent()
  • FragmentCharacteristicDetail

The FTMS rower_data.xml contains requires="C1" style metadata on flag enumerations and dependent fields, allowing the parser to correctly determine which optional fields are present.

However, org.bluetooth.characteristic.cycling_power_measurement.xml in this repository appears not to expose the conditional metadata in the same way, so the parser cannot correctly map CPS flags to optional fields.

As a result, the parser appears to assume the maximum possible CPS payload size (35 bytes) instead of the actual dynamic size derived from the flags.


Reference

The CPS XML from the oesmith/gatt-xml project includes the required conditional metadata and appears to model the characteristic correctly:

https://github.com/oesmith/gatt-xml/blob/master/org.bluetooth.characteristic.cycling_power_measurement.xml

Specifically, that XML includes the requires="C1" / requires="C2" style requirement tags used by the parser logic.

This is consistent with how FTMS rower data XML is structured in this repository.


Suggested fix

Either:

  1. Update the CPS XML metadata to expose conditional requirements similarly to FTMS, or
  2. Make the generic parser more tolerant of CPS optional-field resolution failures.

Additional note

The CPS Feature characteristic is correctly exposed as a 32-bit value and parses properly in the app, so this issue seems isolated to the Measurement characteristic decoder.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions