diff --git a/src/slic3r/GUI/DeviceCore/DevMapping.cpp b/src/slic3r/GUI/DeviceCore/DevMapping.cpp index 5dc16f4250..165492c9f6 100644 --- a/src/slic3r/GUI/DeviceCore/DevMapping.cpp +++ b/src/slic3r/GUI/DeviceCore/DevMapping.cpp @@ -162,8 +162,8 @@ namespace Slic3r } //first: left,nozzle=1,map=1 second: right,nozzle=0,map=2 - bool right_ams_valid = ams->second->GetExtruderId() == 0 && map_opt[MappingOption::USE_RIGHT_AMS]; - bool left_ams_valid = ams->second->GetExtruderId() == 1 && map_opt[MappingOption::USE_LEFT_AMS]; + bool right_ams_valid = (ams->second->GetBindedExtruderSet().count(MAIN_EXTRUDER_ID) != 0) && map_opt[MappingOption::USE_RIGHT_AMS]; + bool left_ams_valid = (ams->second->GetBindedExtruderSet().count(DEPUTY_EXTRUDER_ID) != 0) && map_opt[MappingOption::USE_LEFT_AMS]; if (right_ams_valid || left_ams_valid) { tray_filaments.emplace(std::make_pair(tray_index, info)); diff --git a/tests/slic3rutils/CMakeLists.txt b/tests/slic3rutils/CMakeLists.txt index 30f58a9562..0342450109 100644 --- a/tests/slic3rutils/CMakeLists.txt +++ b/tests/slic3rutils/CMakeLists.txt @@ -1,6 +1,7 @@ get_filename_component(_TEST_NAME ${CMAKE_CURRENT_LIST_DIR} NAME) add_executable(${_TEST_NAME}_tests ${_TEST_NAME}_tests_main.cpp + test_dev_mapping.cpp ) if (MSVC) diff --git a/tests/slic3rutils/test_dev_mapping.cpp b/tests/slic3rutils/test_dev_mapping.cpp new file mode 100644 index 0000000000..02ec2abc60 --- /dev/null +++ b/tests/slic3rutils/test_dev_mapping.cpp @@ -0,0 +1,81 @@ +// Match the include environment that libslic3r_gui TUs get from pchheader.hpp: Windows.h with +// WIN32_LEAN_AND_MEAN/NOMINMAX must come first so rpcndr.h's `byte` is processed before +// makes std::byte a competing candidate (otherwise the Windows COM headers pulled in via +// DeviceManager.hpp error with an ambiguous `byte`). wx/timer.h must precede DeviceManager.hpp, +// which includes DeviceErrorDialog.hpp (uses wxTimerEvent) before its own wx/timer.h include. +#ifdef WIN32 + #ifndef WIN32_LEAN_AND_MEAN + #define WIN32_LEAN_AND_MEAN + #endif + #ifndef NOMINMAX + #define NOMINMAX + #endif + #include +#endif + +#include + +#include + +#include "slic3r/GUI/DeviceManager.hpp" +#include "slic3r/GUI/DeviceCore/DevMapping.h" +#include "slic3r/GUI/DeviceCore/DevFilaSystem.h" + +#include + +using json = nlohmann::json; +using namespace Slic3r; + +TEST_CASE("Switch-bound AMS trays map to the left extruder", "[DevMapping]") +{ + MachineObject obj(nullptr, nullptr, "test", "test_dev", "127.0.0.1"); + + // aux bit 29 = Filament Track Switch installed (DevFilaSwitch.cpp:69-77) + obj.GetFilaSwitch()->ParseFilaSwitchInfo(json::parse(R"({"aux":"20000000"})")); + REQUIRE(obj.GetFilaSwitch()->IsInstalled()); + + // info bits: 0-3 type(1=AMS), 8-11 extruder(0xE=switch-bound), 24-27 bind_switch_in(0) + // tray_exist_bits bit 0 marks AMS 0 / tray 0 present so the mapping result survives the + // is_exists check in is_valid_mapping_result (DevFilaSystem.cpp:769). + // tray_info_idx/tray_type are intentionally omitted: the tray parse resolves the display + // filament type via MachineObject::setting_id_to_type(), which reads the GUI preset bundle + // (wxGetApp().preset_bundle) — unavailable in this headless unit test. The tray filament + // type (only needed for the type-match below) is set directly after the parse instead. + json print_push = json::parse(R"({ + "ams": { + "tray_exist_bits": "1", + "ams": [ { + "id": "0", + "info": "00000E01", + "tray": [ { "id": "0", "tray_color": "FF0000FF" } ] + } ] + } + })"); + DevFilaSystemParser::ParseV1_0(print_push, &obj, obj.GetFilaSystem().get(), false); + + const auto& ams_list = obj.GetFilaSystem()->GetAmsList(); + REQUIRE(ams_list.count("0") == 1); + REQUIRE(ams_list.at("0")->GetBindedExtruderSet().count(MAIN_EXTRUDER_ID) == 1); + REQUIRE(ams_list.at("0")->GetBindedExtruderSet().count(DEPUTY_EXTRUDER_ID) == 1); + + DevAmsTray* tray = obj.GetFilaSystem()->GetAmsTray("0", "0"); + REQUIRE(tray != nullptr); + tray->m_fila_type = "PLA"; + + FilamentInfo fila; + fila.id = 0; + fila.type = "PLA"; + fila.color = "FF0000FF"; + + std::vector result; + std::vector map_opt(4, false); // MappingOption: LEFT_AMS,RIGHT_AMS,LEFT_EXT,RIGHT_EXT (DevMapping.h:13-19) + map_opt[MappingOption::USE_LEFT_AMS] = true; + + DevMappingUtil::ams_filament_mapping(&obj, {fila}, result, map_opt, {}, false); + + // A switch-bound AMS feeds BOTH extruders, so a left-only mapping request + // must still land the filament on the AMS tray. + REQUIRE(result.size() == 1); + CHECK(result[0].tray_id == 0); + CHECK(result[0].ams_id == "0"); +}