Intentional or an aliasing related bug?

I had originally posted this in the general discord, but it wa suggested this might be a better place to post/ask.

The running joke among RailCore owners is that no 2 are alike.

So recently another person and myself started to set up a modular configuration framework using includes, to make it easier for RailCore owners to quickly and easily adopt Klipper.

The basic premise is to set up pin aliases for each board, but use a standardized naming methodology for the aliases. The fan, stepper, probe, etc includes reference the standardized alias names, thus drastically reducing the time that needs to be spent setting up a configuration.

Last night we came across an issue/error that’s kind of limiting. The background is that duets have a shared stepper enable pin , so we set an alias.

    # The shared enable pin for all steppers
    S_EN=PC6,

We were then going to use that to set other name aliases, so we didn’t have to hardcode the pin name 10 times (duet 2 + duex 5 supports 10 steppers).

    # Stepper Motors
    # X & Y
    X_STEP=S0_STEP, X_DIR=S0_DIR, X_EN=S_EN, X_CS=S0_CS,
    Y_STEP=S1_STEP, Y_DIR=S1_DIR, Y_EN=S_EN, Y_CS=S1_CS,
    #....

However this yielded an error

pin Y_EN is an alias for X_EN

and that’s coming from here.

The code allows a 1 to 1 alias mapping, for example.

aliases:
    All_0=PD6, 
    All_1=All_0,

But not a one to many mapping.

aliases:
    All_0=PD6, 
    All_1=All_0,
    All_2=All_0,

Is this as designed, a bug, or just a use case that wasn’t considered?

2 Likes

I had a little time as my work day was winding down and tried hard coding the secondary aliases and got the same error.

    # Stepper Motors
    # X & Y
    X_STEP=S0_STEP, X_DIR=S0_DIR, X_EN=PC6, X_CS=S0_CS,
    Y_STEP=S1_STEP, Y_DIR=S1_DIR, Y_EN=PC6, Y_CS=S1_CS,
pin Y_EN is an alias for X_EN

adding duplicate_pin_override didn’t seem to help.

[duplicate_pin_override]
pins:
    PC6,

That behavior is intentional. Using two different names for the same pin would cause the code to not function as it should (and also has the potential to confuse users reading the config).

So, it’s possible to define multiple aliases for a pin and it is possible to define aliases in terms of other aliases, but ultimately there can be only one name used for a pin in the config.

-Kevin

Do you have an example where the code would not function as intended?

I’m not sure what it would break in klipper directly. However, i assume you could end up incorrectly assigning pins if you weren’t meticulous about how you named, used, and created aliases.

For the abstraction that we were working on, not being able to uses multiple aliases pointing at one pin is a show stopper best explained via an example imo.

Here is a simplified view of a motion component configuration file.

[stepper_x]
# Rear stepper motor
step_pin: X_STEP
dir_pin: !X_DIR
enable_pin: !X_EN
endstop_pin: X_STOP

[stepper_y]
# Front stepper motor
step_pin: Y_STEP 
dir_pin: Y_DIR
enable_pin: !Y_EN
endstop_pin: Y_STOP

Here are two chunks out of the alias section for an octopus pro

# board specific pin aliases
S0_STEP=PF13, S0_DIR=PF12, S0_EN=PF14, S0_CS=PC4,
S1_STEP=PG0, S1_DIR=PG1, S1_EN=PF15, S1_CS=PD11,

# mapping board specific aliases to homogenized component aliases  
X_STEP=S1_STEP, X_DIR=S1_DIR, X_EN=S1_EN, X_UART=S1_CS, X_CS=S1_CS,
Y_STEP=S2_STEP, Y_DIR=S2_DIR, Y_EN=S2_EN, Y_UART=S2_CS, Y_CS=S2_CS,

The above works perfectly fine, because while multiple aliases are pointing to one pin, only one aliases is being used.

However when you have an mcu that has a pin performing multiple duties, using aliases won’t work. For example on duet 2 boards all steppers share a common enable pin.

Both of the following aliasing schemes will yield a pin Y_EN is an alias for X_EN error.

# board specific pin aliases
S0_STEP=PD6, S0_DIR=PD11, S0_CS=PD14,
S1_STEP=PD7, S1_DIR=PD12, S1_CS=PC9,
# The shared enable pin for all steppers
S_EN=PC6,

# mapping board specific aliases to homogenized component aliases 
X_STEP=S0_STEP, X_DIR=S0_DIR, X_EN=S_EN, X_CS=S0_CS,
Y_STEP=S1_STEP, Y_DIR=S1_DIR, Y_EN=S_EN, Y_CS=S1_CS, 
# board specific pin aliases
S0_STEP=PD6, S0_DIR=PD11, S0_CS=PD14,
S1_STEP=PD7, S1_DIR=PD12, S1_CS=PC9,

# mapping board specific aliases to homogenized component aliases 
X_STEP=S0_STEP, X_DIR=S0_DIR, X_EN=PC6, X_CS=S0_CS,
Y_STEP=S1_STEP, Y_DIR=S1_DIR, Y_EN=PC6, Y_CS=S1_CS, 

@koconnor any chance we could get some kind of special flag/setting in the conf that would flip validate_aliases to false?

As an aside, i noticed via some debugging that i did yesterday, this doesn’t seem to work as i would expect.

PWM_1=PC3,

BLT_SERVO=!PWM_1,

self.aliases contained

'BLT_SERVO': '!PWM_1',

when i would have expected, or some kind of error.

'BLT_SERVO': '!PC3',
1 Like

Chiming in here as I’m working with dans on this particular project.

It might be useful to provide a little extra context on what we’re trying to accomplish and the reason for the multiple aliasing we’re doing.

We are working on building a modular configuration that allows users to share a common set of includable cfgs regardless of the underlying controller.

To that end, we have been building a set of pin maps for different controllers that are essentially made up of the two parts dans posted above.

The first part contains pin mappings that are aligned with the physical silkscreen/manufacturer’s labeling on the board. We are then taking these aliases and remapping them to a second set of standardized aliases that we’re using across all controllers.

We can then split up components like motion configuration, probes, temperature sensors, extruders, etc into discrete selectable cfg files using these standardized pin names to allow users to quickly and easily build a configuration simply by choosing the parts that are in their printer.

We currently have a rough proof of concept built and working with a couple of BTT boards with UART stepper drivers. It’s largely undocumented at this point but can be found here:

As dans mentioned, where we’re having this fall apart is with Duet 2 boards with SPI based 2660 drivers. The Duets tie enable for all drivers to a single pin. If a pin can only ever be referenced in the configuration by a single alias, this more or less breaks our abstraction model for Duet boards since other controllers use multiple pins for this function and thus need separate mappings.

X_EN and Y_EN are separate pins on most boards and need to be treated that way in the config, for example, but are the same pin on a duet. The current aliasing requirements as we’re understanding them mean that we can build a config that’s easily dropped in for most boards or one that works on the Duet, but not one that works on both. Being unable to map a single pin to multiple aliases is really the only thing that’s stopping it from working across the board.

From my perspective, this seems like worthwhile functionality. Helping people sort out pin mapping has generally been one of the biggest hurdles for getting them on to Klipper in my experience. We seem to have most of the pieces for a working abstraction layer to simplify this in place, but this particular quirk of Duet boards has been a roadblock for us.

Shared enable lines are fundamentally different from dedicated enable lines. (For example, the code can’t disable a single stepper until all steppers are disabled; it also enables special TMC enable logic via SPI/UART.) The current code determines if an enable line is a shared enable line by checking for identical pin names. Thus, disabling the aliasing check would introduce a defect, as the current code would not correctly identify shared enable lines.

This isn’t something I’ll be working on at all. I don’t even want it in my configs - a shared pin always does something special and I would not want to obfuscate that in my configs.

I understand why you are looking for it. It’s not clear to me that you can reach your goals in general. Many boards are fundamentally different (eg, Duet2 boards use inverse heater pins, some boards use 2200 ohm pullups, etc.).

Separately, using pin aliases to improve configuration layout is something that has been looked at recently - see Reworking example config files to have pin aliases at top of file

Cheers,
-Kevin

Thanks! Is there a reason aliases are resolved right before sending the config (in def _send_config) instead of when the config is parsed?