Skip to content

Adding ExclusiveConsumer feature to OpenMRN#911

Open
rilull wants to merge 9 commits into
bakerstu:masterfrom
rilull:master
Open

Adding ExclusiveConsumer feature to OpenMRN#911
rilull wants to merge 9 commits into
bakerstu:masterfrom
rilull:master

Conversation

@rilull

@rilull rilull commented Feb 25, 2026

Copy link
Copy Markdown
Contributor

This is a new consumer class that is aimed at a use case to drive a signal head from a group of outputs on a node. This matches a typical prototype approach of only having a single color or position being lit (turned on) inside a single signal head.

The new class is called ConfiguredExclusiveConsumer, matching the naming scheme of existing producer/consumers. This class enables creating a group of outputs (from 2 to N) that, upon receipt of a matching event ID by the node, will turn on that particular output and turn off all other outputs in the same group.

There is sample usage of this feature in the Nucleo DevKit application (nucleo_io) on Port D and E. I have put various compile time configuration guards in place to match what we have previously done for the Snap Switch and IO expansion features.

I have tested this on DevKit hardware with a F303 Nucleo.

claude and others added 9 commits February 19, 2026 01:40
Adds a new consumer class where a group of GPIO outputs are mutually
exclusive: receiving an event for any output in the group turns that
output on and turns off all others. Useful for signal masts, route
indicators, or any application where only one output should be active
at a time.

Includes CDI configuration support (ExclusiveConsumerConfig) with one
event per output (rather than an on/off pair), and unit tests covering
exclusive switching, identify consumer, and global identify behavior.

https://claude.ai/code/session_01178EKqcoikwTtUC9ybWow1
Modifies the nucleo_io application's STM32F303RE Nucleo target to use
ConfiguredExclusiveConsumer for Port D and Port E output lines 1-6:

- Port D lines 1,2,3: exclusive group 1 (one active at a time)
- Port D lines 4,5,6: exclusive group 2 (one active at a time)
- Port E lines 1,2,3: exclusive group 1 (one active at a time)
- Port E lines 4,5,6: exclusive group 2 (one active at a time)
- Port D/E lines 7,8: remain as standard on/off consumers

Breaks the main.cxx symlink to the F091RC target to create a
target-specific main.cxx. Updates config.hxx CDI layout with
ExclusiveGroup3 entries and bumps CANONICAL_VERSION to force
EEPROM reset on existing boards.

https://claude.ai/code/session_01178EKqcoikwTtUC9ybWow1
Increases exclusive consumer group size from 3 to 4 outputs, which
aligns with the shift register divisibility and supports signal mast
use cases with a marker light (4 aspects). All 8 lines per port are
now covered by two exclusive groups with no remainder:

- Port D group 1: lines 1,2,3,4 (mutually exclusive)
- Port D group 2: lines 5,6,7,8 (mutually exclusive)
- Port E group 1: lines 1,2,3,4 (mutually exclusive)
- Port E group 2: lines 5,6,7,8 (mutually exclusive)

The ConfiguredExclusiveConsumer class itself already supports any
group size (2, 3, 4, etc.) since it is templated on N.

https://claude.ai/code/session_01178EKqcoikwTtUC9ybWow1
…0iezv-MH0NT

Claude/explain codebase mlk9o584mfw0iezv mh0 nt
…how compile time options are presented. Ready for hardware test and validation.

@bakerstu bakerstu left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

If you address the comments you can merge.

// ======================================================================

/// Port D lines 1, 2, 3, 4 — exclusive group 1.
constexpr const Gpio *const kPortDExcl1Gpio[] = {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

There is a style issue here. constants are supposed to be UNDERSCORE_SEPARATED_ALL_CAPS, no Hungarian style "k" prefix.

The style guide is in the Doxygen. You should be able to have Claude code read and comprehend it. I intend to move the style guide to a Markdown file.

namespace openlcb
{

static const uint64_t kEventBase = 0x05010101FFFF0000ULL;

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Style.

private SimpleEventHandler
{
public:
typedef ExclusiveConsumerConfig config_entry_type;

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

C++ types should use PascalCase.

/// @param config is the repeated group object from the configuration space
/// that represents the locations of the events.
template <unsigned N>
__attribute__((noinline)) ConfiguredExclusiveConsumer(Node *node,

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Is the noinline attribute necessary. Normally we let the compiler choose.

ConfigUpdateService::instance()->register_update_listener(this);
}

~ConfiguredExclusiveConsumer()

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Missing Doxygen comment blocks here and below.

}

UpdateAction apply_configuration(int fd, bool initial_load,
BarrierNotifiable *done) OVERRIDE

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

The use of "OVERRIDE" here and elsewhere is deprecated. Use "override" (all lowercase) instead.

/// instances. Can be constant from FLASH space.
/// @param size is the length of the list of pins array.
/// @param config is the repeated group object from the configuration space
/// that represents the locations of the events.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Missing brief description and the template argument is undocumented.

EventRegistry::instance()->unregister_handler(this);
}

Node *node_; //< virtual node to export the consumer on

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

There are not proper Doxygen comment blocks. Use ///<.

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.

3 participants