Skip to content
AF
Free Tool

Cycling power and cadence lab: from revolution counts to rpm

Neither Cycling Power Measurement (0x2A63) nor CSC Measurement (0x2A5B) sends cadence or speed. Each sends a cumulative revolution count and the time of the last revolution event, so cadence is the change in crank revolutions divided by the change in event time between two notifications, and speed is the change in wheel revolutions times your wheel’s circumference over the same interval. The Bluetooth SIG’s structures give the tick: 1/1024 s for both CSC event times, but 1/2048 s for the Cycling Power wheel and 1/1024 s for its crank. This lab connects a power meter or speed/cadence sensor over Web Bluetooth and does that arithmetic in the open, or on two hex values you paste.

2100 mm is an example, not your wheel: measure one full roll-out of your tire and enter it. Speed and distance scale with it; cadence does not use it.

Paste two values

Cadence and speed need two consecutive notifications from the same sensor. Paste them as hex, in order. The samples are synthetic, built from the SIG’s structure by the module that decodes them.

Sample: Crank revolutions go 65535 → 1 and the crank event time 0xFC00 → 0x0400: both uint16 counters wrapped, and the step is still 2 revolutions in 2048 ticks.

Crank: +2 rev / 2048 ticks (2 s) 60 rpm

Wheel: +4 rev / 2048 ticks (2 s) 15.12 km/h (120 wheel rpm)

rpm = Δrevolutions ÷ (Δticks × tick) × 60, with both counters wrapped at their own width; km/h = Δwheel revolutions × circumference ÷ Δt × 3.6.

Previous: 03 E8 03 00 00 00 04 FF FF 00 FC

CSC Measurement (0x2A5B) · 11 octets · little-endian

03E80300000004FFFF00FC
FieldPresent whenOctetsRawValue
Flagsboolean[8]alwayspresent0–030x03
Wheel Revolution Datastructbit 0 of Flags is 1present1–61000 / 1024
  • Cumulative Wheel Revolutions: 1000
  • Last Wheel Event Time: 1 second (raw 1024 × 0.000977)
Crank Revolution Datastructbit 1 of Flags is 1present7–1065535 / 64512
  • Cumulative Crank Revolutions: 65535
  • Last Crank Event Time: 63 second (raw 64512 × 0.000977)
Flags bit by bit 0x03
BitValueThe SIG’s description
01Wheel Revolution Data Present
11Crank Revolution Data Present
2–7000000bReserved for Future Use

Next: 03 EC 03 00 00 00 0C 01 00 00 04

CSC Measurement (0x2A5B) · 11 octets · little-endian

03EC030000000C01000004
FieldPresent whenOctetsRawValue
Flagsboolean[8]alwayspresent0–030x03
Wheel Revolution Datastructbit 0 of Flags is 1present1–61004 / 3072
  • Cumulative Wheel Revolutions: 1004
  • Last Wheel Event Time: 3 second (raw 3072 × 0.000977)
Crank Revolution Datastructbit 1 of Flags is 1present7–101 / 1024
  • Cumulative Crank Revolutions: 1
  • Last Crank Event Time: 1 second (raw 1024 × 0.000977)
Flags bit by bit 0x03
BitValueThe SIG’s description
01Wheel Revolution Data Present
11Crank Revolution Data Present
2–7000000bReserved for Future Use

The structures it decodes against

Compiled from the Bluetooth SIG’s GATT Specification Supplement files at commit 408f4a0 of the SIG’s public repository (read 2026-10-17), through this site’s generated copy. The two measurements, then the characteristics the lab reads once after connecting:

Cycling Power Measurement (0x2A63) · 12 fields
FieldTypeSizePresent whenUnit and resolution
Flagsboolean[16]2alwaysflags
Instantaneous Powersint162alwayswatt
Pedal Power Balanceuint80 or 1bit 0 of Flags is 1percentage, × 0.5 (Represented values: M = 1, d = 0, b = -1)
Accumulated Torqueuint160 or 2bit 2 of Flags is 1newton metre, × 0.03125 (Represented values: M = 1, d = 0, b = -5)
Wheel Revolution DataCumulative Wheel Revolutions (uint32); Last Wheel Event Time (uint16, × 0.000488)struct0 or 6bit 4 of Flags is 1—
Crank Revolution DataCumulative Crank Revolutions (uint16); Last Crank Event Time (uint16, × 0.000977)struct0 or 4bit 5 of Flags is 1—
Extreme Force MagnitudesMaximum Force Magnitude (sint16); Minimum Force Magnitude (sint16)struct0 or 4bit 6 of Flags is 1—
Extreme Torque MagnitudesMaximum Torque Magnitude (sint16, × 0.03125); Minimum Torque Magnitude (sint16, × 0.03125)struct0 or 4bit 7 of Flags is 1—
Extreme AnglesMaximum Angle (uint12); Minimum Angle (uint12)struct0 or 3bit 8 of Flags is 1—
Top Dead Spot Angleuint160 or 2bit 9 of Flags is 1degree
Bottom Dead Spot Angleuint160 or 2bit 10 of Flags is 1degree
Accumulated Energyuint160 or 2bit 11 of Flags is 1joule, × 1000 (Represented values: M = 1, d = 3, b = 0)

Cycling Power Measurement on the Bluetooth GATT reference · the SIG’s file gss/org.bluetooth.characteristic.cycling_power_measurement.yaml

CSC Measurement (0x2A5B) · 3 fields
FieldTypeSizePresent whenUnit and resolution
Flagsboolean[8]1alwaysflags
Wheel Revolution DataCumulative Wheel Revolutions (uint32); Last Wheel Event Time (uint16, × 0.000977)struct0 or 6bit 0 of Flags is 1—
Crank Revolution DataCumulative Crank Revolutions (uint16); Last Crank Event Time (uint16, × 0.000977)struct0 or 4bit 1 of Flags is 1—

CSC Measurement on the Bluetooth GATT reference · the SIG’s file gss/org.bluetooth.characteristic.csc_measurement.yaml

Cycling Power Feature (0x2A65) · 1 fields
FieldTypeSizePresent whenUnit and resolution
Cycling Power Featureboolean[32]4alwaysflags

Cycling Power Feature on the Bluetooth GATT reference · the SIG’s file gss/org.bluetooth.characteristic.cycling_power_feature.yaml

CSC Feature (0x2A5C) · 1 fields
FieldTypeSizePresent whenUnit and resolution
CSC Featureboolean[16]2alwaysflags

CSC Feature on the Bluetooth GATT reference · the SIG’s file gss/org.bluetooth.characteristic.csc_feature.yaml

Sensor Location (0x2A5D) · 1 fields
FieldTypeSizePresent whenUnit and resolution
Sensor Locationuint81always—

Sensor Location on the Bluetooth GATT reference · the SIG’s file gss/org.bluetooth.characteristic.sensor_location.yaml

The arithmetic, step by step

  1. Find the struct. In CSC Measurement, Wheel Revolution Data is present when bit 0 of Flags is 1 and Crank Revolution Data when bit 1 is 1. In Cycling Power Measurement they hang on bits 4 and 5 of a two-octet Flags field, after Instantaneous Power, which is always there.
  2. Difference two readings, with the wrap. Cumulative Crank Revolutions is a uint16 and every event time a uint16, so they roll over: a later reading smaller than the earlier one means the counter wrapped, and the step is the difference modulo 216. At 1/1024 s the event time wraps every 64 s; the Cycling Power wheel’s, at 1/2048 s, every 32 s. The synthetic ride wraps both.
  3. Scale the time. CSC’s wheel event time: Represented values: M = 1, d = 0, b = -10, beside Unit is 1/1024th of a second. Cycling Power’s: Represented values: M = 1, d = 0, b = -11, beside Unit is 1/2048 second. The lab multiplies by M × 10d × 2b; a parser that assumes one tick for both reads Cycling Power wheel speed at half or double its value.
  4. Divide. Cadence in rpm is Δcrank revolutions ÷ Δt × 60. Wheel speed is Δwheel revolutions × circumference ÷ Δt; the lab shows km/h (× 3.6 from m/s). The circumference is not in either characteristic, which is why the lab asks for it.
  5. Treat an unchanged event time as no new event. Two notifications with the same event time mean no revolution finished between them (coasting, or a notification interval shorter than one revolution). The lab reports “no new event” and keeps the last cadence on screen labeled as such, rather than dividing by zero or showing 0 rpm.

Where the decoder reads past the SIG’s file

  • Byte order. Little-endian, as the Web Bluetooth specification’s heart-rate example reads every multi-octet field (result.heartRate = data.getUint16(index, /*littleEndian=*/true);, read 2026-10-31); the YAML gives sizes only.
  • Extreme Angles. Two 12-bit members packed into three octets. The SIG’s file gives the example itself (Maximum Angle 0xABC and Minimum Angle 0x123 make 0x123ABC), and the test suite decodes exactly that example.
  • Control points. Cycling Power Control Point and SC Control Point have no member layout for their Parameter in the files this site reads, so the lab neither decodes nor writes them. It writes nothing to a sensor.

Which browsers can connect

Web Bluetooth is a Chromium feature. MDN's compatibility data lists it in Chrome (requestDevice since version 56), Edge, Opera and Samsung Internet, with the note that Chrome's Linux support is not enabled by default, and marks the API experimental. It lists no support in Firefox, in Safari on macOS or iOS, or in Android's WebView.

Source: MDN browser-compat-data, api/Bluetooth.json, read 2026-11-05. Elsewhere the paste boxes and the replay still work.

What the lab cannot tell you

  • Accuracy. Nothing here compares a power meter or sensor with a reference.
  • Which source to trust when a trainer, a power meter and a cadence sensor all report the same pedal stroke. The lab shows each characteristic separately and never merges them; picking one source per metric is covered in reading cycling power, cadence and speed sensors.
  • Smart-trainer data that arrives as FTMS Indoor Bike Data instead: that has its own FTMS lab, and the trainer side is in indoor bike trainer integration.

The radio choice is in ANT+ vs Bluetooth, CI without a sensor in testing BLE fitness devices, and any other characteristic in the BLE GATT explorer.

How this works, and what it sends

Nothing leaves your device. The browser’s own chooser lists devices advertising the Cycling Power or Cycling Speed and Cadence service; the page can reach only the one you pick and only those services. It subscribes to the two measurements, reads Cycling Power Feature, CSC Feature and Sensor Location once where present, and writes nothing. Values stay in this tab’s memory; this site has no server code behind the page and stores nothing.

The synthetic ride and the sample pairs are generated, not recorded from a sensor: the numbers are made up, encoded by the same module that decodes them, with a coasting stretch where the crank event time stops.

The structures come from the Bluetooth SIG’s public repository (https://bitbucket.org/bluetooth-SIG/public), read by this site’s generator on 2026-10-17. The SIG’s text is quoted with attribution: Copyright © Bluetooth SIG, Inc., which describes these files as proprietary to it. This site is not affiliated with Bluetooth SIG.

A free tool from AIFitnessAPI. More at free tools for health-app builders.