Skip to content

Add allSectionsFollowFirst: drive every implement section from AOG section 1 - #130

Closed
gunicsba wants to merge 2 commits into
developfrom
feature/all-sections-follow-first
Closed

gunicsba wants to merge 2 commits into
developfrom
feature/all-sections-follow-first

Conversation

@gunicsba

@gunicsba gunicsba commented Nov 11, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Adds a settings.json option, allSectionsFollowFirst (default false). With it on, every implement section follows AOG's section 1, and the TC tells AOG the implement has one section.

It's for implements that declare several sections which are really one. For example, an RDS Artemis seeder controller with three dispensers on one working width uploads three sections, while AOG should drive them as one.

  • The PGN 229 handler copies AOG's section 1 to every section before passing the states to the TC server. The section demand diagnostics still log what AOG sent.
  • The heartbeat (PGN 0xF0) reports 1 section, on while any implement section is on. AOG should be set to 1 section.

It's a manual override for one machine at a time. The stacked PR builds automatic grouping from the section geometry on top of it, and keeps this option as a fallback for implements whose geometry can't be relied on.

Testing

  • Release build passes on Windows (MSVC).
  • Field test with an RDS Artemis (sw 003.07) in its "linked" layout (one Function, three Sections) on 2026-11-11: dispensers 2 and 3 followed AOG section 1, and AOG showed one section. Dispenser 1 has a hardware fault on that machine.

🤖 Generated with Claude Code

Summary by Sourcery

Add an optional single-section override for implements whose declared sections represent one physical working width.

New Features:

  • Add the allSectionsFollowFirst setting to make all connected implement sections follow AOG section 1 and present as a single section.

Enhancements:

  • Aggregate section heartbeat status across implements and report one section when the override is enabled.
  • Preserve section-demand diagnostics while applying the single-section demand to every implement section.

Documentation:

  • Document the new setting, its default, and its effect on connected implements.

…ction 1

For implements that declare several sections that really are one, such
as an RDS Artemis with three dispensers on one working width. With the
setting on, every implement section follows AOG's section 1, and the
heartbeat reports a single section to AOG (on while any implement
section is on). Default off.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@sourcery-ai

sourcery-ai Bot commented Nov 11, 2026 •

Copy link
Copy Markdown

Reviewer's Guide

Data structures

Add the default and stored setting that the rest of the system uses to determine whether all implement sections follow AOG section 1.

  • include/settings.hpp L172, L181

API

Expose methods for reading and changing the all-sections-follow-first setting.

  • include/settings.hpp L101-108
  • src/settings.cpp L266-276

Implementation

Apply AOG section 1 to every implement section, report one combined section to AOG, and use only section 1 for demand checks.

  • src/app.cpp L510-515, L751-763, L783-788 (+2 small edits)

Configuration

Load and save the new setting in settings.json, defaulting it to false when it is absent.

  • src/settings.cpp L73, L147

Documentation

Document the setting, its intended use, and its behavior across connected implements.

  • readme.md L67

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 3 issues

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="src/app.cpp" line_range="510-513" />
<code_context>
 				sectionDemand = sectionStates;
 				sectionDemandChangesSinceLog++;
 			}
+			if (settings->is_all_sections_follow_first())
+			{
+				// The implement's sections are really one: all follow AOG's section 1 (sectionDemand above stays as AOG sent it)
+				std::fill(sectionStates.begin(), sectionStates.end(), sectionStates.front());
+			}
 			tcServer->update_section_states(sectionStates);
</code_context>
<issue_to_address>
**Override affects every implement**

When more than one section-bearing implement is connected to the TC, the PGN handler replaces AOG's first section bit before `update_section_states`, which applies that state to every connected client; the heartbeat also reports one section for each client. A separate section-bearing implement is therefore controlled by section 1 too, and AOG receives multiple one-section statuses.

Scope the override to the intended implement, or explicitly combine the connected clients' section states and send one unambiguous heartbeat if the mode is intended to cover them all.

Also at `src/app.cpp:748-758`.
</issue_to_address>

### Comment 2
<location path="src/app.cpp" line_range="756" />
<code_context>
+				{
+					anyOn = anyOn || (state.get_section_actual_state(i) == SectionState::ON);
+				}
+				std::vector<uint8_t> oneSection = { state.is_section_control_enabled(), 1, static_cast<std::uint8_t>(anyOn ? 1 : 0) };
+				udpConnections->send(0x80, 0xF0, oneSection);
+				continue;
</code_context>
<issue_to_address>
**Heartbeat can report the wrong aggregate state**

When more than one sectioned implement client is connected and their actual states differ, `Application::update()` sends a separate one-section heartbeat for each sectioned client, with `anyOn` computed only from that client. With multiple implement clients, AOG receives conflicting reports instead of one report that is on whenever any implement section is on.

Aggregate the actual section states across clients and send one consolidated heartbeat per interval.
</issue_to_address>

### Comment 3
<location path="src/app.cpp" line_range="513" />
<code_context>
+			if (settings->is_all_sections_follow_first())
+			{
+				// The implement's sections are really one: all follow AOG's section 1 (sectionDemand above stays as AOG sent it)
+				std::fill(sectionStates.begin(), sectionStates.end(), sectionStates.front());
+			}
 			tcServer->update_section_states(sectionStates);
</code_context>
<issue_to_address>
**Sections beyond 64 ignore the override**

When an implement declares more than 64 sections, `sectionStates` contains only the 64 bits in PGN 229, so `update_section_states()` skips implement sections whose indices are 64 or greater. Those sections do not follow AOG section 1, contrary to the every-section claim.

In this mode, extend the replicated state vector to cover the largest active implement section count before updating the TC server.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨

Comment thread src/app.cpp Resolved
Comment thread src/app.cpp Resolved
Comment thread src/app.cpp Resolved
…t, demand from bit 1 only

PGN 229 has 64 bits, so sections 65-255 kept their old setpoint; the
follow-first vector now covers every section a DDOP can declare.

With several section-controlled implements the heartbeat sent one
one-section report per implement. It now sends a single report: auto
while any implement is in auto, on while any implement section is on.

check_section_demand looked at AOG's bit for each implement section; in
follow-first mode only AOG's section 1 is demand, so a stray bit can no
longer hide the working-without-demand warning.

Addresses Sourcery's review of #130.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
gunicsba added a commit that referenced this pull request Nov 11, 2026
…o feature/per-boom-section-control

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@gunicsba gunicsba closed this Nov 11, 2026
@gunicsba

Copy link
Copy Markdown
Contributor Author

Superseded by #131: groupOverlappingSections covers this, including implements with two halves.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant