Repository navigation
feat(firmware): record each ride's effort limits, v6 ride footer - #2199
Merged
Merged
Conversation
Each ride now keeps the rider's max HR and FTP from the moment it starts, so an old ride keeps its own effort zones when the settings change later. - Ride object v6: the footer grows to 154 bytes with the max HR limit, a reserved byte and the FTP limit (0 = not set). The spec states the fixed zone edges a reader applies to them. - The recorder snapshots the limits into the ride origin at a fresh start. The resume image (v4) carries them, so a continued ride keeps its original snapshot. - effort::Limits becomes the shared obc_formats::ride::EffortLimits. - ride-v6.bin replaces ride-v5.bin, regenerated with the obc-vectors generator; the web decoder, the conversion bridge, the UI-frame staging and the flat-engine tests read the new vector. - The seeded demo sensor rides carry max HR 185 and FTP 250. - flat_ride_delta re-pinned at 570 B (+4 B footer). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
RideObjectCodec reads and writes the v6 footer limits. RideSummary carries them as `zoneLimits: RideZoneLimits` (nil = not set on the device at ride time), and `Ride.zoneLimits` reads them. Edits keep them, and the archive manifest stores them; a manifest without the key reads as not set. RideZoneLimits.heartRateZone(bpm:) and .powerZone(watts:) map a value to zone 0...4 with the device's edge rules, and the tests mirror the effort.rs cases. The website and default mock rides carry max HR 185 and FTP 250; Sunday Coffee Spin has none. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The ride-detail sensor page now takes its HR and power zones from the limits the ride recorded, not from today's settings. A ride recorded without limits shows its graphs without zones. - RideInfo and RideSummary carry the footer's EffortLimits into the resident ride catalog. - The UI-frame staging gives the heart-rate trip day the 185 bpm and 250 W limits the ride-detail-hr frame shows; no frame changed. Resource re-pins, from one head build on the pinned host (rustc 1.96.0): - RideEntry 112 B -> 120 B: 4 B of limits, and the u64 object id rounds the entry up by 4 B more. - App allocation 58,184 B -> 58,440 B (+256 B = 32 catalog entries x 8 B). - Board guards pass: 315,736 B linked resident inside the band, residual main stack 43,688 B, poll frame 9,864 B, init_idle frame 1,856 B. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Advanced Run ID: Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
timohueser
force-pushed
the
claude/ride-zone-limits
branch
from
September 25, 2026 09:02
39057f1 to
a557517
Compare
RideObject gains effortLimits (null = not set), so the decoder and the encoder round-trip ride-v6.bin byte for byte. The dev harness rides move to version 6, and the version-mismatch test writes version 7 at the v6 footer offset. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The website fixture is generated, so the Grimsel ride's max HR 185 and FTP 250 move into generate-website-fixture.py, and website.json is regenerated from it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Resolve the demo-ride seeder and its README against the Kandel ride fixture: the seeder keeps both the single-file path and the demo rides' 185 bpm and 250 W limits. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- gpx_to_ride writes the v6 footer with max HR 185 bpm and FTP 250 W by default; two optional arguments set other limits. - kandel-ride package revision 183efc8f (53,219 bytes): the rebuilt v6 kandel.obcr and the updated README, published to the fixture store. - The file seeder replaces a v5 ride of the same name in place (same object, next revision). Both seeders rewrite every other v5 ride on the card as v6 without limits, samples unchanged, because the v6 board rejects v5 rides and one unreadable ride blocks the whole Rides menu. A different current payload with the same name is still refused. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The v5 check and the upgrade opened a store handle per ride and never closed it. The store has five open-object slots, so a card with more rides refused the seed as Busy part-way through the upgrade. The seeded-ride check closes its handle too. The host test now upgrades more v5 rides than there are slots. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Each recorded ride now carries the rider's effort limits that were in force when the ride started: max heart rate and FTP. An old ride therefore keeps its own zones after the rider changes the limits. The app's ride timeline, a separate PR, draws zones from these limits.
App::ride_origin()copiesmax_hrandftp_wfrom the settings when a ride starts. A resumed ride keeps its first copy through the resume image. The limits typeobc_formats::ride::EffortLimitsis shared by the device and the formats code; 0 means "not set".RideZoneLimitssits onRideSummaryand is readable asRide.zoneLimits.heartRateZone(bpm:)andpowerZone(watts:)use the device's edge rules. A parity test checks them against the firmware cases. Older app manifests read as not set.obc-ble-interface-spec.md§7.2 has the footer rows and the zone-edge table.FLAT_Store_Format.md§7.2 has the buffer sizes.ride-v6.binreplacesride-v5.bin.flat_ride_deltais re-pinned from 566 to 570 B.Public docs
Not changed.
Checks
obc test -pfor obc-formats, obc-route, obc-vectors, obc-app, obc-host-core, obc-link and obc-web-convert, with clippy-D warnings. New tests cover the snapshot at start, at resume and when not set, the resume codec, the vector, and the sensor page zones.swift testinPackages/OBCKit, with the vector round-trip, zone parity and old-manifest tests.obc shot --check: all 377 frames match.obc flash build, the board resource checks andobc suites checkpass.Requirements: none
🤖 Generated with Claude Code