Skip to content

demux: bargraph turns on its highest output; man page array ranges (#3519) - #4687

Open
tzuohann wants to merge 1 commit into
LinuxCNC:masterfrom
tzuohann:fix-demux-bargraph-3519
Open

tzuohann wants to merge 1 commit into
LinuxCNC:masterfrom
tzuohann:fix-demux-bargraph-3519

Conversation

@tzuohann

@tzuohann tzuohann commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

BsAtHome provided a cleaner, more readable and instructive fix to the problem.

Fixes #3519.

Problem: with bargraph set, a selection of personality or more should turn every output on, but the top output never came on: the selection was clamped to personality-1, as in one-hot mode. A large sel-uint was also summed into an int and could wrap round to a small selection.

Solution: each mode has its own loop. Bargraph lights every output below the selection, so personality or more lights all of them; one-hot still clamps to the last output. sel-uint is read once into a signed 64-bit value and capped, leaving room for the bit inputs, so it cannot wrap. The description now notes that a 2^N-output bargraph cannot reach its last state with N selection bits.

@BsAtHome

Copy link
Copy Markdown
Contributor

Why is this touching halcompile with such complexity? If you say it should read 0..personality-1 instead of 0..personality, then why isn't it a one-liner? Or am I missing something?

There is an additional problem in the bargraph mode. Using the bit inputs, you cannot select all on with personality at 32 because the bargraph has 33 states but only 5 bits as input. Additionally using the sel-uint input would need to be done as a boolean, but that is very messy. In this light, the bargraph mode should not have personality to bound to 32, but to 31.

But looking at the changes,... The change in demux should also be more structured. The change is rather complicated IMO and the luster casting is unnecessary when the proper types are used (rtapi_u64 is not the right type). In that sense, it would also be better to fix the forced ternary evaluation with bg and to split the loop properly. That should also fix the bad indent style in the if and else if construct.

Why is this adding a test? Are there any suspicions that an unrelated change somewhere in the codebase breaks this? That would be exceptionally bad because then probably everything breaks or is broken.

@BsAtHome

BsAtHome commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

I'd suggest a different approach (without Artificial Inflation):

component demux "Select one of several output pins by integer and/or or individual bits.";

description """
This component creates a number of output bits defined by the 'personality' command-line parameter.
One of these bits will be set based on interpreting the bit-inputs as a binary number and then adding on the integer input.
Most uses will use only one or the other, but it is possible to use the bits as a "shift" if required.
An optional operating mode is enabled by setting the 'bargraph' parameter to true.
In this case all bits up to the selected bit will be set, as might be required for an LED bargraph display.

[NOTE]
====
You cannot select the last bargraph bit when personality is set to 2^N using only N selection bits.
There are 2^N+1 states in a N-bit bargraph and you can only represent 2^N values using N bits ([0..2^N-1]).
This is especially a problem when personality is 32 because you only have five selection bits.

If you need 2^N outputs in the bargraph, then you should probably use the 'sel-uint' input pin.
If you require 'sel-bit-MM' inputs, then the largest functional personality is 31.
====
""";

pin in bool sel-bit-## [5] "Binary-number bit selectors";
pin in uint sel-uint "Integer selection input";
pin out bool out-## [32:personality] "The set of output bits";

option default_personality 32;
param rw bool bargraph = 0;

see_also "select8(9)";
license "GPL 2+";
author "Andy Pugh";

option period no;
function _;

;;

FUNCTION(_){
#define VALMAX 16768  // This is larger than 2^5 and less than 2^30
    rtapi_sint bit = (rtapi_sint)sel_uint;

    // We do not want 'bit' to go negative on read, when someone cleverly
    // set the sel-uint value to something very, very big, and there must
    // be headroom for adding the bit values so it doesn't wrap.
    if (bit < 0 || bit > VALMAX)
        bit = VALMAX;

    // Mix in the bit values.
    bit += (sel_bit(0) << 0);
    bit += (sel_bit(1) << 1);
    bit += (sel_bit(2) << 2);
    bit += (sel_bit(3) << 3);
    bit += (sel_bit(4) << 4);

    if (bargraph) {
        // We don't care if 'bit' was too large. It will just fill out the
        // entire bargraph. Any value larger than or equal to personality
        // will show a full bar.
        // Note that you cannot select the last bit when personality is 32
        // using only five selection bits. There are 33 states in a 32-bit
        // bargraph and you can only represent 32 values using five bits.
        for (int i = 0; i < personality ; i++) {
            out_set(i, bit > i);
        }
    } else {
        // Compatibility with the old version caps the 'bit' at the last
        // position if it is too large.
        if (bit >= personality)
            bit = personality - 1;
        // Set only the bit indicated
        for (int i = 0; i < personality ; i++) {
            out_set(i, bit == i);
        }
    }
}

@tzuohann
tzuohann force-pushed the fix-demux-bargraph-3519 branch from 2b9e550 to b360914 Compare October 16, 2026 14:09
@tzuohann

Copy link
Copy Markdown
Contributor Author

Pushed 92d74da (demux) and b360914 (halcompile).

Types: sel-uint is now read once into an rtapi_uint, which is what hal_get_uint returns. Personality is copied once and the casts are gone. A personality of 0 or less still does nothing.

Loop: split per mode, each with its own clamp, braces throughout.

Cap at 31: right, and it bites in the obvious test: with the default 32 outputs, setting all five bits lights 31, not all. That limit isn't new: before this change all-on was unreachable at any personality. A cap can't follow bargraph, which is a runtime param, so it would also remove 32 outputs in one-hot mode, the default. I've documented it in the description ("with 32 outputs all on needs sel-uint"). A sixth sel-bit would remove it without breaking anything. Your call.

halcompile: '%s-1' % size is correct for every component except logic, whose size personality & 0xff would print as personality & 0xff-1, which reads as personality & 0xfe. comp.adoc doesn't ask authors to bracket size expressions, so I made it handle any expression, which is where the extra lines come from. The alternative is your one-liner plus [16 : (personality & 0xff)] in logic.comp, relying on authors bracketing from now on. I lean towards the general version because the docs don't require brackets, but you know better how components get written. I'll go with whichever you prefer.

Test: it's there to stop this off-by-one coming back, not because of unrelated changes. It is heavier than this component needs. I can cut it to the cases fixed here (bargraph top output, one-hot last output, no wrap), about a quarter of the size, or drop it.

@tzuohann
tzuohann force-pushed the fix-demux-bargraph-3519 branch from b360914 to 3db8a33 Compare October 16, 2026 14:18
@tzuohann

Copy link
Copy Markdown
Contributor Author

Thanks for the rewrite. One follow-up on the NOTE: someone testing a 32-output bargraph will set all five bits and expect all on. A sixth sel-bit would make that just work, and existing configs are unaffected because an unconnected pin reads 0. Happy to add it here or in a separate PR if you think it's worth it.

@BsAtHome

Copy link
Copy Markdown
Contributor

Thanks for the rewrite.

You are welcome.

One follow-up on the NOTE: someone testing a 32-output bargraph will set all five bits and expect all on. A sixth sel-bit would make that just work, and existing configs are unaffected because an unconnected pin reads 0. Happy to add it here or in a separate PR if you think it's worth it.

The point is that you will always have a bad match between "binary input" and "bargraph operation". You need to have that one extra state if you want to include "all off" or "all on". Adding the extra bit is not a good fix IMO. If you need the bargraph, then you should use the sel-uint pin as input. Otherwise, if you need to have the "all on" case and don't need the "all off" case, then set the sel-uint to one (1) and use the bit-sel-MM inputs to select between 1..32 lamps in the on-state. Otherwise you are simply limited to 31 outputs.

BTW, extending by adding one selection bit would also mean you'd want to allow personality > 32 too. And that would give you the same problem case for 63/64. Since no one has asked for more than 32,... well, maybe its not needed ;-)

@tzuohann

Copy link
Copy Markdown
Contributor Author

Understood! But what if someone wants to build a nested 5 axis CNC?

Thanks. Was very instructive to me to compare what claude came up with your solution. I did a lot of stress testing and checking. It really wasn't a single prompt and send sort of thing.

It will take a while before humans process text like machines, and, until then, clarity is king. Cheers.

@BsAtHome

Copy link
Copy Markdown
Contributor

Understood! But what if someone wants to build a nested 5 axis CNC?

You make a new component?

It will take a while before humans process text like machines, and, until then, clarity is king. Cheers.

I think you mean "a while before machines process text like humans". Besides, I can give you the exact answer to that: It will be when the machine has become a true and real human being and the human being has become the true and real machine; they are us and we are them, both biological entities, indistinguishable from each other.

FWIW, programming is no about processing text.

@BsAtHome

Copy link
Copy Markdown
Contributor

BTW, your commit message states "Co-Authored-By: Claude Opus".

My rewrite was most certainly not created or co-authored by a dum[bp] machine.

@tzuohann

Copy link
Copy Markdown
Contributor Author

BTW, your commit message states "Co-Authored-By: Claude Opus".

My rewrite was most certainly not created or co-authored by a dum[bp] machine.

Whoops. Let me get AI to fix that. You can thank it. Him. Her. whatever.

…inuxCNC#3519)

BsAtHome's rewrite of the component.

In bargraph mode the selection was clamped to personality-1 as in one-hot
mode, so the top output never came on. Each mode now has its own loop:
bargraph lights every output below the selection, one-hot still clamps to
the last output. sel-uint is read once into a signed 64-bit value and
capped, leaving headroom for the bit inputs, so a large value cannot wrap.
The description notes that a 2^N-output bargraph cannot reach its last
state with N selection bits.
@tzuohann
tzuohann force-pushed the fix-demux-bargraph-3519 branch from 3db8a33 to a724d61 Compare October 16, 2026 16:52
@tzuohann

tzuohann commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor Author

Understood! But what if someone wants to build a nested 5 axis CNC?

You make a new component?

It will take a while before humans process text like machines, and, until then, clarity is king. Cheers.

I think you mean "a while before machines process text like humans". Besides, I can give you the exact answer to that: It will be when the machine has become a true and real human being and the human being has become the true and real machine; they are us and we are them, both biological entities, indistinguishable from each other.

FWIW, programming is no about processing text.

This is too interesting to not discuss.
So if you outlined a final state where humans are effectively cyborgs, in the sense that we have biological motives, perhaps grounded in DNA transmissions but somehow have the processing power that biological neural nets cannot match. Then, the next question becomes what is the intermediate state between "now" where AI is fledging LLMs and that future amalgamation. There has to be an intermediate state. If it isn't this, what is it?

OK. Tell me what programming is. To me, programming is, anticipate human behavior in response to them pursuing their desires. Where possible, automate, for the average with the programmers own definition for what average means. Basically, I am leave open the metric for what a center means, but I think of programming as removing mechanical burdens faced by that center. I do not program or code to impose my views of how a process should work on other. I view my interaction with AI as that of a translator. I translate what I think the median user wants into something AI can deliver. That has been my guiding principle.

@grandixximo

grandixximo commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

Programming to me is storing the logic that solves a problem or creates capabilities in a way that a machine can execute it.
Good programming is when you do it elegantly, efficiently, in a structured thought out way, keeping in mind how the machine executes it, and foresight about how it interacts with all things it can and will interact.
There is so much more about it, can't really write it in a post, people write books about it, like this one
https://archive.org/details/Structured_Programming__Dahl_Dijkstra_Hoare/page/n3/mode/2up

@BsAtHome

Copy link
Copy Markdown
Contributor

This is too interesting to not discuss. So if you outlined a final state where humans are effectively cyborgs, in the sense that we have biological motives, perhaps grounded in DNA transmissions but somehow have the processing power that biological neural nets cannot match.

No, not cyborgs. That would mean a form where both biological and mechanical are combined as one organism.

To achieve equality you need identity, which means there is no longer a distinction. It is not a merger of two, but a replacement.

Then, the next question becomes what is the intermediate state between "now" where AI is fledging LLMs and that future amalgamation. There has to be an intermediate state. If it isn't this, what is it?

As long as the basis is an LLM, there is no way it can become an equal. It may possess a vast database of "knowledge", larger than most of us feeble humans, but it lacks a step that philosophers have been discussing for centuries. What is it that makes our thought process so successful, relatively speaking, to model the world?

OK. Tell me what programming is. To me, programming is, anticipate human behavior in response to them pursuing their desires. Where possible, automate, for the average with the programmers own definition for what average means.

That would be MMI/HMI and is the mapping of patterns for, primarily, UX design.

Programming is not about desires as such. That is a rationalizing construct. Unless you refer to the desire to solve a problem for the sake of solving a problem. However, that is about motivation and is a small part of the whole story about drives and automatisms.

Programming is, in essence, solving a problem using an algorithmic construct. This is not limited to computer programming, but is a much more universal description.

In case of us feeble biological beings, we are able to program ourselves and possess built-in algorithms to create new algorithms (apparently a part of our genetics). We possess a self-modifying system that is able to adapt and change at rather fundamental levels (the plasticity is extremely high).

"Good programming", while its a difficult assessment, is measuring the algorithmic solution with respect to the problem described and analyzed within a set of given or set contexts and boundaries. And, as remarked, whole books are written about just this topic.

FWIW, "bad programming" is seen throughout in how we perform tasks in our daily lives. Ever noticed how someone else performs a given task while you would perform it differently and/or more efficiently?

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.

demux component bargraph mode never turns on highest output

3 participants