How to get RR intervals from FIT hr messages (Fit file message 132)?

Garmin units write RR intervals to Fit file from Garmin HRM 600 and other Garmin HRM with memory at the end of a offline activity,(like swimming) writing 11 RR intervals per message,

= TYPE=12 NAME=hr NUMBER=132
--- timestamp=1126167485=2025-09-07T08:18:05Z
--- event_timestamp=1778373632=1736693.000 s
--- fractional_timestamp=0=0.0000 s
--- filtered_bpm=71=71 bpm
--- xxx251=0=0
==
= TYPE=11 NAME=hr NUMBER=132
--- filtered_bpm=71=71 bpm,71 bpm,71 bpm,71 bpm,71 bpm,71 bpm,71 bpm,71 bpm
--- event_timestamp_12=0=0.000 s,0.031 s,0.068 s,0.214 s,0.117 s,0.206 s,0.075 s,0.108 s,0.021 s,0.022 s,0.083 s,0.135 s
==

Type‑12 Anchor Processing

  • timestamp (absolute Unix time) and the scalar event_timestamp (a 32‑bit integer in 1/1024‑second units).

  • The anchor’s absolute time is calculated as:
    anchor_abs = timestamp + event_timestamp / 1024.0

  • This event_timestamp scalar is used as the baseline for the first beat of the subsequent Type‑11 message (if present).

Type‑11 Message Processing (The Core RR Extraction)

When a Type‑11 message is encountered, GC processes two fields:

1. Scalar event_timestamp

  • This is a 32‑bit integer representing the cumulative offset (in 1/1024 seconds) of the first beat of this message from the start of the activity (or midnight).

2. Packed event_timestamp_12 (field 10)

  • This field contains 12 bytes (0–255). They are not RR intervals – they are packed 12‑bit cumulative offsets that extend the 32‑bit timestamp for the subsequent 11 beats.

  • Needs unpacking the bytes using a specific bit‑twiddling algorithm (overlapping pairs, alternating extraction).

  • For each pair of bytes, reconstruct a 12‑bit value

  • Result per Type‑11 Message

    • 1 absolute beat time from the scalar event_timestamp.

    • 11 additional absolute beat times from the unpacked bytes.

    • Total: 12 absolute beat times per message.

    • 11 RR intervals (differences between consecutive absolute beat times).