mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-10 17:21:10 +00:00
M104/M109 address a heater, but every caller of the instance GCodeWriter::set_temperature overload addresses filaments by logical id, so on a printer whose physical_extruder_map is not the identity the emitted T named the wrong head -- or, where the logical id exceeds the head count, no head at all. With a map of 0,0,0,0,1,2,3 a toolchange to filament 5 emitted "M109 S265 T4" and "M104 S190 T4 ;cooldown" while the head it meant was T1. Upstream already treats these commands as physical: the preheat it injects in GCodeProcessor maps through the same map before emitting, and BBS's own wipe tower does likewise. Emitting logical is the half that never got the memo. That mismatch also disabled the cooldown suppression beside the preheat, which compares the line's T against pem[tool_number] and so never matched a logical one -- 171 cooldowns survived in a two-head print where none should have. Worse, it could match the wrong line: a cooldown for filament 1 emitted T1, and a toolchange to filament 5 gives pem[4] == 1, so a legitimate cooldown for head 0 was deleted because the incoming head happened to be numbered 1. Translate once, in the instance overload every logical-space caller passes through. The static overload is already physical-in and is left alone. Gated on is_imex. physical_extruder_map carries two readings in this tree: the BBS paths index it by extruder id, the IMEX paths by filament id, and the two coincide only when the filament and nozzle counts match. Mapping unconditionally would impose the IMEX reading on profiles that mean the other one -- fdm_bbl_3dp_002_common ships a non-identity [1,0], spared today only because single_extruder_multi_material suppresses the T qualifier entirely. The wipe tower's interface-temperature pass has to move with it. It strips the M109 that post_toolchange emits by searching for that filament's tool index, so it now searches for the mapped one; left alone it would have stopped matching, and the surviving blocking M109 would have silently defeated the interface temperature. Its sibling pass reads WipeTower2 output, which emits no T at all, and is deliberately unchanged. The bare T<n> toolchange stays logical -- it selects an AFC lane, not a heater. Test slices two objects across a head boundary, the only case that reaches this emission: the same-physical short-circuit in set_extruder suppresses the cooldown entirely for lane swaps within one head. It scans every M104/M109 rather than matching fixed strings, so it catches any unmapped emission and not just the two sites changed here. With the mapping neutered it reports 101 offending lines; with it in place, none. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
OrcaSlicer tests
Building, running and writing tests is documented on the wiki, under How to Test.
Two files here rather than there, because coding agents only read what is in the repository: