mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-10 17:21:10 +00:00
fix(imex): enumerate no secondary carriages in single-tool primary mode
get_imex_active_tools returned every physical head named by the active mode's tool string, including the one carrying the Primary role. The pressure-advance and nozzle-temperature sites are already gated on the mode not being primary, so only the is_extruder_used supplement was exposed. In primary mode that supplement treated the mode's single declared tool as a secondary carriage and marked its filament slot used, so machine_start_gcode emitted a heat command for an extruder that never prints. The phantom slot appears when the mode's declared tool differs from the head the initial tool routes to through physical_extruder_map -- on an AFC/MMU layout, printing with a filament that lives on any head other than the declared one. Return an empty roster for primary mode, where there are no parallel carriages by definition. This lives in the enumerator rather than at the call site because the mode is already resolved and normalized there, and the two guarded callers cannot reach it in that mode, so their behaviour is unchanged. Scope: this closes the primary-mode instance. The same phantom slot still occurs in a parallel mode when the initial tool's head is not the mode's declared Primary, which turns on which of the two notions of "primary" the three emission sites should skip. That question is unresolved and deliberately left alone here. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
c94e8324d0
commit
ef8d80980d
@@ -2887,7 +2887,9 @@ static BambuBedType to_bambu_bed_type(BedType type)
|
||||
return bambu_bed_type;
|
||||
}
|
||||
|
||||
// Orca IMEX: Returns the tool indices active in the current IMEX mode.
|
||||
// Orca IMEX: Returns the PHYSICAL tool indices the active IMEX mode drives, or an EMPTY
|
||||
// vector in primary mode -- a single tool, so there are no parallel carriages to list.
|
||||
// The mode's Primary head IS included in parallel modes; callers handle it themselves.
|
||||
// In copy/mirror parallel modes, secondary carriages never receive tool-change
|
||||
// commands — the firmware mirrors the primary's moves — so they don't appear in
|
||||
// tool_ordering.all_extruders(). This helper extracts the active mode's tool string
|
||||
@@ -2906,6 +2908,10 @@ static std::vector<int> get_imex_active_tools(const Print& print)
|
||||
const std::string& raw_mode = print.objects().front()->config().imex_parallel_mode.value;
|
||||
const std::string active_mode = raw_mode.empty() ? kImexPrimaryMode : raw_mode;
|
||||
|
||||
// Primary mode drives a single tool, so there are no parallel carriages to list.
|
||||
if (active_mode == kImexPrimaryMode)
|
||||
return active_tools;
|
||||
|
||||
const auto* mode_names_opt = print.config().option<ConfigOptionStrings>("imex_mode_names");
|
||||
const auto* tools_opt = print.config().option<ConfigOptionStrings>("imex_mode_active_tools");
|
||||
|
||||
|
||||
@@ -715,6 +715,7 @@ TEST_CASE("Multi-extruder slice stays in bounds with a short max_layer_height",
|
||||
REQUIRE_FALSE(print.objects().front()->layers().empty());
|
||||
}
|
||||
|
||||
|
||||
// Shared IMEX printer geometry: 7 logical extruders across 4 physical heads.
|
||||
// physical_extruder_map is only honoured when its length matches the nozzle count
|
||||
// (PrintApply feeds effective_physical_extruder_map the nozzle_diameter size), so the
|
||||
@@ -779,6 +780,53 @@ TEST_CASE("Parallel-mode IMEX prints transition the printing head to its second-
|
||||
CHECK(gcode.find("M104 S240 T1") != std::string::npos);
|
||||
}
|
||||
|
||||
// IMEX supplements is_extruder_used for the secondary carriages a parallel mode drives.
|
||||
// `primary` drives exactly one tool, so the supplement must not run: routing every region
|
||||
// to filament 6 puts the initial tool on physical head 2, while the mode's only declared
|
||||
// head is 0, which the unguarded supplement resolved back to filament slot 0.
|
||||
TEST_CASE("Primary-mode IMEX prints mark only the filament slot they print with",
|
||||
"[MultiFilament][IMEX]")
|
||||
{
|
||||
DynamicPrintConfig config = multifilament_config(7);
|
||||
imex_7x4_printer(config);
|
||||
all_regions_on_filament(config, 6); // filament 6 => logical slot 5 => physical head 2
|
||||
config.set_deserialize_strict({
|
||||
{ "imex_parallel_mode", "primary" },
|
||||
{ "machine_start_gcode",
|
||||
";USED0:{if is_extruder_used[0]}1{else}0{endif}\n"
|
||||
";USED5:{if is_extruder_used[5]}1{else}0{endif}\n" },
|
||||
});
|
||||
|
||||
const std::string gcode = slice({ cube(20) }, config);
|
||||
|
||||
CHECK(gcode.find(";USED5:1") != std::string::npos);
|
||||
CHECK(gcode.find(";USED0:0") != std::string::npos);
|
||||
}
|
||||
|
||||
// Guard rail for the fix above: the modes the supplement exists for must keep marking their
|
||||
// secondaries. `copy` declares heads 0 and 1; neither is the initial tool's head (filament 6
|
||||
// routes to head 2), so both are still enumerated. Head 0 -> slot 0, head 1 -> slot 4.
|
||||
TEST_CASE("Copy-mode IMEX prints still mark every secondary carriage's filament slot",
|
||||
"[MultiFilament][IMEX]")
|
||||
{
|
||||
DynamicPrintConfig config = multifilament_config(7);
|
||||
imex_7x4_printer(config);
|
||||
all_regions_on_filament(config, 6);
|
||||
config.set_deserialize_strict({
|
||||
{ "imex_parallel_mode", "copy" },
|
||||
{ "machine_start_gcode",
|
||||
";USED0:{if is_extruder_used[0]}1{else}0{endif}\n"
|
||||
";USED4:{if is_extruder_used[4]}1{else}0{endif}\n"
|
||||
";USED5:{if is_extruder_used[5]}1{else}0{endif}\n" },
|
||||
});
|
||||
|
||||
const std::string gcode = slice({ cube(20) }, config);
|
||||
|
||||
CHECK(gcode.find(";USED5:1") != std::string::npos);
|
||||
CHECK(gcode.find(";USED0:1") != std::string::npos);
|
||||
CHECK(gcode.find(";USED4:1") != std::string::npos);
|
||||
}
|
||||
|
||||
// The two IMEX changes are coupled: get_imex_active_tools() now returns an empty roster in
|
||||
// primary mode, so if the temperature branch ever stopped excluding primary it would enter,
|
||||
// emit nothing, skip the standard path, and silently restore the bug the copy-mode case above
|
||||
|
||||
Reference in New Issue
Block a user