fix(imex): translate physical→logical when marking is_extruder_used for IMEX active tools

is_extruder_used is a logical-filament-slot indexed bool array — start-gcode
templates use it as `is_extruder_used[N]` where N is a logical filament slot
(matches how the rest of the codebase consumes per-filament arrays like
filament_settings_id, nozzle_temperature_initial_layer, etc.).

`tool_ordering.all_extruders()` returns LOGICAL slots and was correctly
marking those. But the IMEX-secondary marking added in 5aa624b025 was
writing PHYSICAL extruder indices straight into the logical array, mixing
index spaces. On any printer with physical_extruder_map size > 1 (MMU/AFC),
this marks the wrong slots and misses the right ones.

Symptom on the user's Neo XP 0.6 (pem [0,0,0,0,1,2,3,3]) in copy mode
[0:P,1:C] with object on slot 2 (PLA):
  - tool_ordering marks slot 2 (correct: object's filament).
  - IMEX active = [0, 1] (physical T0, T1) → mistakenly marks logical
    slots 0 (ABS) and 1 (ASA), neither of which is used.
  - Slot 4 (PLA on physical T1, the actual filament that loads on the
    secondary in copy mode) is NOT marked.
  - Start-gcode template emits EXTRUDER=ABS_temp EXTRUDER1=ASA_temp
    EXTRUDER2=PLA_temp; no EXTRUDER4.
  - PRINT_START macro reads t4=0, skips heating extruder1 — T1 stays
    cold during the print.

Translate physical → logical via resolve_filament_for_head before marking
(per-plate imex_head_filament_map override consulted, with first-routed
fallback when no override is set). This matches what the firmware actually
loads on each carriage during the parallel-mode print, and what the rest
of the IMEX hot path (PA emission, layer-change temperature) already does.

Result on the user's setup post-fix:
  - is_extruder_used[2]=true (object), is_extruder_used[4]=true (T1 in copy).
  - Start-gcode emits 2 temps for the actually-used filaments.
  - extruder1 heats correctly to slot 4's temp before the print begins.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Clifford Garwood
2026-04-25 05:07:34 -04:00
co-authored by Claude Opus 4.7
parent c8e7c5678b
commit 2b7f438887
+21 -7
View File
@@ -2869,13 +2869,27 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
for (unsigned int extruder : tool_ordering.all_extruders())
is_extruder_used[extruder] = true;
// Orca IMEX: Also mark secondary carriages as used in parallel modes
// so is_extruder_used[N] is true for all physical tools in the active mode.
// Secondary carriages never appear in tool_ordering.all_extruders() because
// the firmware duplicates the primary's moves — no tool-change commands are emitted.
for (int tool_idx : get_imex_active_tools(print))
if (tool_idx < (int)is_extruder_used.size())
is_extruder_used[tool_idx] = true;
// Orca IMEX: also mark the LOGICAL filament slot that each active secondary
// carriage will load during the print. is_extruder_used is logical-slot indexed
// (consumed as `is_extruder_used[N]` in machine_start_gcode templates), but
// get_imex_active_tools returns PHYSICAL extruder indices. On any printer with
// physical_extruder_map size > 1 (MMU/AFC), writing the physical index into a
// logical-indexed array marks the wrong slot — start-gcode templates would emit
// the wrong filament's temp / not emit the correct one.
//
// Translate physical -> logical via the per-plate imex_head_filament_map (set by
// the IMEX ghost picker), with first_filament_for_physical_head as the fallback
// when no override is set.
if (print.config().is_imex.value && !print.objects().empty()) {
const auto plate_head_map = parse_imex_head_filament_map(
print.objects().front()->config().imex_head_filament_map.value);
const ConfigOptionInts& pem = print.config().physical_extruder_map;
for (int phys_tool : get_imex_active_tools(print)) {
const int logical = resolve_filament_for_head(plate_head_map, pem, phys_tool);
if (logical >= 0 && logical < (int)is_extruder_used.size())
is_extruder_used[logical] = true;
}
}
this->placeholder_parser().set("is_extruder_used", new ConfigOptionBools(is_extruder_used));