From 4bca7b30080e783f6a746db0d0a57661ad5cb245 Mon Sep 17 00:00:00 2001 From: SoftFever Date: Fri, 17 Jul 2026 00:49:04 +0800 Subject: [PATCH] Resync the DeviceCore state models --- src/slic3r/GUI/DeviceCore/DevConfig.cpp | 15 ++- src/slic3r/GUI/DeviceCore/DevConfig.h | 5 +- src/slic3r/GUI/DeviceCore/DevConfigUtil.cpp | 126 ++++++++++++++---- src/slic3r/GUI/DeviceCore/DevConfigUtil.h | 90 +++++++------ src/slic3r/GUI/DeviceCore/DevDefs.h | 56 ++++---- src/slic3r/GUI/DeviceCore/DevFan.cpp | 12 +- src/slic3r/GUI/DeviceCore/DevFan.h | 9 +- src/slic3r/GUI/DeviceCore/DevFilaAmsSetting.h | 5 +- src/slic3r/GUI/DeviceCore/DevFilaSwitch.cpp | 33 +++-- src/slic3r/GUI/DeviceCore/DevFilaSwitch.h | 14 +- src/slic3r/GUI/DeviceCore/DevFilaSystem.h | 8 +- .../GUI/DeviceCore/DevFilaSystemCtrl.cpp | 8 +- src/slic3r/GUI/DeviceCore/DevFirmware.h | 17 ++- src/slic3r/GUI/DeviceCore/DevHMS.cpp | 1 + src/slic3r/GUI/DeviceCore/DevInfo.h | 4 + .../GUI/DeviceCore/DevMappingNozzle.cpp | 32 +---- src/slic3r/GUI/DeviceCore/DevMappingNozzle.h | 2 +- src/slic3r/GUI/DeviceCore/DevStorage.cpp | 25 ++-- src/slic3r/GUI/DeviceCore/DevStorage.h | 13 +- src/slic3r/GUI/DeviceCore/DevUtil.cpp | 73 ++++++++++ src/slic3r/GUI/DeviceCore/DevUtil.h | 105 ++++++++++++++- src/slic3r/GUI/DeviceCore/DevUtilBackend.cpp | 47 ++++++- src/slic3r/GUI/DeviceCore/DevUtilBackend.h | 29 ++-- 23 files changed, 529 insertions(+), 200 deletions(-) diff --git a/src/slic3r/GUI/DeviceCore/DevConfig.cpp b/src/slic3r/GUI/DeviceCore/DevConfig.cpp index 5b8776ad23..9833731040 100644 --- a/src/slic3r/GUI/DeviceCore/DevConfig.cpp +++ b/src/slic3r/GUI/DeviceCore/DevConfig.cpp @@ -8,17 +8,30 @@ using namespace nlohmann; namespace Slic3r { +bool DevConfig::SupportChamberTempDisplay() const +{ + if (!m_support_chamber_temp_display.has_value()) { + return m_has_chamber; + } + + return m_support_chamber_temp_display.value(); +} + void DevConfig::ParseConfig(const json& print_json) { ParseChamberConfig(print_json); ParsePrintOptionsConfig(print_json); ParseCalibrationConfig(print_json); - } void DevConfig::ParseChamberConfig(const json& print_json) { DevJsonValParser::ParseVal(print_json, "support_chamber", m_has_chamber); + + if (print_json.contains("support_chamber_temp_display")) { + m_support_chamber_temp_display = DevJsonValParser::GetVal(print_json, "support_chamber_temp_display"); + } + DevJsonValParser::ParseVal(print_json, "support_chamber_temp_edit", m_support_chamber_edit); if (m_support_chamber_edit) { diff --git a/src/slic3r/GUI/DeviceCore/DevConfig.h b/src/slic3r/GUI/DeviceCore/DevConfig.h index bc9cb78cd1..449b5a7253 100644 --- a/src/slic3r/GUI/DeviceCore/DevConfig.h +++ b/src/slic3r/GUI/DeviceCore/DevConfig.h @@ -3,8 +3,9 @@ #include "slic3r/Utils/json_diff.hpp" #include -#include +#include +#include namespace Slic3r { @@ -22,6 +23,7 @@ public: public: // chamber bool HasChamber() const { return m_has_chamber; } + bool SupportChamberTempDisplay() const; bool SupportChamberEdit() const { return m_support_chamber_edit; } int GetChamberTempEditMin() const { return m_chamber_temp_edit_min; } int GetChamberTempEditMax() const { return m_chamber_temp_edit_max; } @@ -57,6 +59,7 @@ private: /*configure vals*/ // chamber bool m_has_chamber = false; // whether the machine has a chamber + std::optional m_support_chamber_temp_display; bool m_support_chamber_edit = false; int m_chamber_temp_edit_min = 0; int m_chamber_temp_edit_max = 60; diff --git a/src/slic3r/GUI/DeviceCore/DevConfigUtil.cpp b/src/slic3r/GUI/DeviceCore/DevConfigUtil.cpp index 03c5c0587d..c8e08e00fa 100644 --- a/src/slic3r/GUI/DeviceCore/DevConfigUtil.cpp +++ b/src/slic3r/GUI/DeviceCore/DevConfigUtil.cpp @@ -1,16 +1,41 @@ #include "DevConfigUtil.h" -#include -#include - #include -#include +#include +#include "../I18N.hpp" using namespace nlohmann; namespace Slic3r { +// Translation markers for xgettext extraction. +// These strings are configured in printers/*.json (tool_head_display_names) +// and passed to _L() at runtime. xgettext cannot scan dynamic strings, +// so we mark them here with L() for extraction into .pot file. +// This block is never executed at runtime. +static void _toolhead_translation_markers() +{ + // Dynamic toolhead display names from JSON config — xgettext cannot scan these + L("Main Extruder"); L("Main extruder"); L("main extruder"); + L("Auxiliary Extruder"); L("Auxiliary extruder"); L("auxiliary extruder"); + L("Left Extruder"); L("Left extruder"); L("left extruder"); + L("Right Extruder"); L("Right extruder"); L("right extruder"); + L("Main Nozzle"); L("Main nozzle"); L("main nozzle"); + L("Auxiliary Nozzle"); L("Auxiliary nozzle"); L("auxiliary nozzle"); + L("Left Nozzle"); L("Left nozzle"); L("left nozzle"); + L("Right Nozzle"); L("Right nozzle"); L("right nozzle"); + L("Main Hotend"); L("Main hotend"); L("main hotend"); + L("Auxiliary Hotend"); L("Auxiliary hotend"); L("auxiliary hotend"); + L("Left Hotend"); L("Left hotend"); L("left hotend"); + L("Right Hotend"); L("Right hotend"); L("right hotend"); + // standalone position words (short_name=true runtime results) + L("main"); L("auxiliary"); + L("Main"); L("Auxiliary"); + L("left"); L("right"); + L("Left"); L("Right"); +} + std::string DevPrinterConfigUtil::m_resource_file_path = ""; @@ -36,8 +61,6 @@ std::map DevPrinterConfigUtil::get_all_model_id_with_n for (wxString file : m_files) { - if (!file.Lower().ends_with(".json")) continue; - std::string config_file = m_resource_file_path + "/printers/" + file.ToStdString(); boost::nowide::ifstream json_file(config_file.c_str()); @@ -91,7 +114,7 @@ std::string DevPrinterConfigUtil::get_filament_load_img(const std::string &type_ { if (has_nozzle_rack) { - const auto &rack_vec = get_value_from_config>(type_str, "filament_load_image_nozzle_rack"); + const auto &rack_vec = get_value_from_config>(type_str, "filament_load_image_nozzle_rack") ; if (!rack_vec.empty()) { if (ext_id >= 0 && static_cast(ext_id) < rack_vec.size()) @@ -111,7 +134,6 @@ std::string DevPrinterConfigUtil::get_filament_load_img(const std::string &type_ std::string DevPrinterConfigUtil::get_fan_text(const std::string& type_str, const std::string& key) { - std::vector filaments; std::string config_file = m_resource_file_path + "/printers/" + type_str + ".json"; boost::nowide::ifstream json_file(config_file.c_str()); try @@ -134,6 +156,25 @@ std::string DevPrinterConfigUtil::get_fan_text(const std::string& type_str, cons return std::string(); } +std::vector DevPrinterConfigUtil::get_fan_text_params(const std::string& type_str, const std::string& key) +{ + std::string config_file = m_resource_file_path + "/printers/" + type_str + ".json"; + boost::nowide::ifstream json_file(config_file.c_str()); + try { + json jj; + if (json_file.is_open()) { + json_file >> jj; + if (jj.contains("00.00.00.00")) { + json const& printer = jj["00.00.00.00"]; + if (printer.contains("fan") && printer["fan"].contains(key)) { + return printer["fan"][key].get>(); + } + } + } + } catch (...) {} + return std::vector(); +} + std::string DevPrinterConfigUtil::get_fan_text(const std::string& type_str, int airduct_mode, int airduct_func, int submode) { std::vector filaments; @@ -181,6 +222,36 @@ std::string DevPrinterConfigUtil::get_fan_text(const std::string& type_str, int return std::string(); } +std::string DevPrinterConfigUtil::get_fan_mode_text(const std::string& type_str, int airduct_mode, const std::string& key) +{ + std::vector filaments; + std::string config_file = m_resource_file_path + "/printers/" + type_str + ".json"; + boost::nowide::ifstream json_file(config_file.c_str()); + try { + json jj; + if (json_file.is_open()) { + json_file >> jj; + if (jj.contains("00.00.00.00")) { + json const& printer = jj["00.00.00.00"]; + if (!printer.contains("fan")) { + return std::string(); + } + + json const& fan_item = printer["fan"]; + const auto& airduct_mode_str = std::to_string(airduct_mode); + if (!fan_item.contains(airduct_mode_str)) { + return std::string(); + } + + if (fan_item[airduct_mode_str].contains(key)) { + return fan_item[airduct_mode_str][key].get(); + } + } + } + } catch (...) {} + return std::string(); +} + std::map> DevPrinterConfigUtil::get_all_subseries(std::string type_str) { std::map> subseries; @@ -284,36 +355,45 @@ std::string DevPrinterConfigUtil::get_toolhead_display_name( { ToolHeadComponent::Hotend, "hotend" } }; - const int case_index = static_cast(name_case); - const std::string role_key = std::to_string(ext_id); + int case_index = static_cast(name_case); // 0, 1, 2 + + // Try to read from printer config json + auto names_json = get_value_from_config(type_str, "tool_head_display_names"); + std::string role_key = std::to_string(ext_id); // "0" or "1" const std::string& comp_key = comp_keys.at(component); std::string result; - auto names_json = get_value_from_config(type_str, "tool_head_display_names"); - if (!names_json.is_null() && names_json.contains(role_key) && names_json[role_key].contains(comp_key)) { + + if (!names_json.is_null() + && names_json.contains(role_key) + && names_json[role_key].contains(comp_key)) + { auto& arr = names_json[role_key][comp_key]; - if (arr.is_array() && case_index < static_cast(arr.size())) + if (arr.is_array() && case_index < static_cast(arr.size())) { result = arr[case_index].get(); + } } + // Fallback: all dual-extruder printers should have tool_head_display_names configured. + // This is a safety net only — return a generic name. if (result.empty()) { - const std::string side = ext_id == DEPUTY_EXTRUDER_ID ? "Left" : "Right"; - const std::string component_name = component == ToolHeadComponent::Extruder ? "Extruder" : - component == ToolHeadComponent::Hotend ? "Hotend" : "Nozzle"; - result = side + " " + component_name; - if (name_case == ToolHeadNameCase::SentenceCase && result.size() > side.size() + 1) - result[side.size() + 1] = static_cast(std::tolower(static_cast(result[side.size() + 1]))); - else if (name_case == ToolHeadNameCase::LowerCase) - std::transform(result.begin(), result.end(), result.begin(), [](unsigned char c) { return static_cast(std::tolower(c)); }); + static const std::map fallback_names = { + { ToolHeadComponent::Extruder, "Extruder" }, + { ToolHeadComponent::Nozzle, "Nozzle" }, + { ToolHeadComponent::Hotend, "Hotend" } + }; + result = fallback_names.at(component); } + // short_name: return only the role prefix (e.g. "Main" from "Main Nozzle") if (short_name) { auto sp = result.find(' '); - if (sp != std::string::npos) + if (sp != std::string::npos) { result = result.substr(0, sp); + } } return result; } -}; +}; \ No newline at end of file diff --git a/src/slic3r/GUI/DeviceCore/DevConfigUtil.h b/src/slic3r/GUI/DeviceCore/DevConfigUtil.h index 1cb8e97a6e..2b4af44061 100644 --- a/src/slic3r/GUI/DeviceCore/DevConfigUtil.h +++ b/src/slic3r/GUI/DeviceCore/DevConfigUtil.h @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include #include @@ -23,6 +25,20 @@ namespace Slic3r { +/// Toolhead component type (extruder / nozzle / hotend) +enum class ToolHeadComponent { + Extruder, + Nozzle, + Hotend +}; + +/// Name case style for toolhead display names +enum class ToolHeadNameCase { + TitleCase = 0, // [0] "Main Extruder" — panel titles, section headers + SentenceCase = 1, // [1] "Main extruder" — static box labels + LowerCase = 2 // [2] "main extruder" — inline text, sentence concatenation +}; + class dePrinterConfigFactory { public: @@ -30,17 +46,6 @@ public: ~dePrinterConfigFactory() = default; }; -enum class ToolHeadComponent { - Extruder, - Nozzle, - Hotend -}; - -enum class ToolHeadNameCase { - TitleCase = 0, - SentenceCase = 1, - LowerCase = 2 -}; class DevPrinterConfigUtil { @@ -74,14 +79,19 @@ public: static std::string get_printer_use_ams_type(std::string type_str) { return get_value_from_config(type_str, "use_ams_type"); } static std::string get_printer_ams_img(const std::string& type_str) { return get_value_from_config(type_str, "printer_use_ams_image"); } static std::string get_printer_ext_img(const std::string& type_str, int pos);//printer_ext_image + static bool support_ams_fila_change_abort(std::string type_str) { return get_value_from_config(type_str, "print", "support_ams_filament_change_abort"); } static std::string get_filament_load_img(const std::string &type_str, int ext_id, bool has_nozzle_rack = false); /*fan*/ - static std::string get_fan_text(const std::string& type_str, const std::string& key); + static std::string get_fan_text(const std::string& type_str, const std::string& key); + static std::vector get_fan_text_params(const std::string& type_str, const std::string& key); static std::string get_fan_text(const std::string& type_str, int airduct_mode, int airduct_func, int submode); + static std::string get_fan_mode_text(const std::string& type_str, int airduct_mode, const std::string& key); /*extruder*/ static bool get_printer_can_set_nozzle(std::string type_str) { return get_value_from_config(type_str, "enable_set_nozzle_info"); }// can set nozzle from studio + + /*toolhead display names (extruder / nozzle / hotend)*/ static std::string get_toolhead_display_name( const std::string& type_str, int ext_id, @@ -90,10 +100,15 @@ public: bool short_name = false); /*print job*/ + static bool support_print_check_firmware_for_tpu_left(std::string type_str){ return get_value_from_config(type_str, "print", "support_print_check_firmware_for_tpu_left"); } + static bool support_user_first_setup_tpu_check(std::string type_str){ return get_value_from_config(type_str, "print", "support_user_first_setup_tpu_check"); } + static std::string support_user_first_setup_tpu_check_url(std::string type_str){ return get_value_from_config(type_str, "print", "support_user_first_setup_tpu_check_url"); } static bool support_ams_ext_mix_print(std::string type_str) { return get_value_from_config(type_str, "print", "support_ams_ext_mix_print"); } + static bool support_print_time_estimate_warning(std::string type_str) { return get_value_from_config(type_str, "print", "support_print_time_estimate_warning"); } /*calibration*/ static std::vector get_unsupport_auto_cali_filaments(std::string type_str) { return get_value_from_config>(type_str, "auto_cali_not_support_filaments"); } + static bool support_disable_cali_flow_type(std::string type_str) { return get_value_from_config(type_str,"support_disable_cali_flow_type"); } /*detection*/ static bool support_wrapping_detection(const std::string& type_str) { return get_value_from_config(type_str, "support_wrapping_detection"); } @@ -103,7 +118,10 @@ public: /*print check*/ static bool support_print_check_extension_fan_f000_mounted(const std::string& type_str) { return get_value_from_config(type_str, "print", "support_print_check_extension_fan_f000_mounted"); } - static bool support_print_check_firmware_for_tpu_left(const std::string& type_str) { return get_value_from_config(type_str, "print", "support_print_check_firmware_for_tpu_left"); } + static std::string air_print_detection_position(const std::string &type_str) { return get_value_from_config(type_str, "air_print_detection_position"); } + + /*bed*/ + static int get_bed_temperature_limit(const std::string &type_str) { return get_value_from_config(type_str, "print", "bed_temperature_limit"); } public: template @@ -127,7 +145,7 @@ public: } } } - catch (...) { assert(0 && "get_value_from_config failed"); BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " failed"; }// there are file errors + catch (...) { assert(0 && "get_value_from_config failed"); BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " failed"; }// there are file errors return T(); }; @@ -179,7 +197,7 @@ public: } } } - catch (...) { assert(0 && "get_json_from_config failed"); BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " failed"; }// there are file errors + catch (...) { assert(0 && "get_json_from_config failed"); BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " failed"; }// there are file errors return nlohmann::json(); } @@ -188,35 +206,25 @@ private: }; /*special transform*/ -static std::string _parse_printer_type(const std::string& type_str) +static std::string _parse_printer_type(const std::string &type_str) { - if (type_str.compare("3DPrinter-X1") == 0) - { - return "BL-P002"; - } - else if (type_str.compare("3DPrinter-X1-Carbon") == 0) - { - return "BL-P001"; - } - else if (type_str.compare("BL-P001") == 0) - { - return type_str; - } - else if (type_str.compare("BL-P002") == 0) - { - return type_str; - } - else - { - std::string result = DevPrinterConfigUtil::get_printer_type(type_str); - if (!result.empty()) - { - return result; - } - } + static std::unordered_map s_printer_type_lazy_cache; + if (type_str == "3DPrinter-X1") return "BL-P002"; + if (type_str == "3DPrinter-X1-Carbon") return "BL-P001"; + if (type_str == "BL-P001" || type_str == "BL-P002") return type_str; + + auto cache_it = s_printer_type_lazy_cache.find(type_str); + if (cache_it != s_printer_type_lazy_cache.end()) { + return cache_it->second; + } + std::string result = DevPrinterConfigUtil::get_printer_type(type_str); + if (!result.empty()) { + s_printer_type_lazy_cache[type_str] = result; + return result; + } BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " Unsupported printer type: " << type_str; return type_str; } -};// namespace Slic3r +};// namespace Slic3r \ No newline at end of file diff --git a/src/slic3r/GUI/DeviceCore/DevDefs.h b/src/slic3r/GUI/DeviceCore/DevDefs.h index 640f984024..f5e3f1e380 100644 --- a/src/slic3r/GUI/DeviceCore/DevDefs.h +++ b/src/slic3r/GUI/DeviceCore/DevDefs.h @@ -10,12 +10,21 @@ #pragma once #include -#include +#include + +// Reserved for future usage +#define DEV_RESERVED_FOR_FUTURE(...) /* stripped */ + +// Previous definitions +namespace Slic3r +{ + class MachineObject; +} enum PrinterArch { - ARCH_CORE_XY, - ARCH_I3, + ARCH_CORE_XY,// move hotbed + ARCH_I3,//move z }; enum PrinterSeries @@ -36,6 +45,7 @@ enum AmsStatusMain AMS_STATUS_MAIN_RFID_IDENTIFYING = 0x02, AMS_STATUS_MAIN_ASSIST = 0x03, AMS_STATUS_MAIN_CALIBRATION = 0x04, + AMS_STATUS_MAIN_COLD_PULL = 0x07, AMS_STATUS_MAIN_SELF_CHECK = 0x10, AMS_STATUS_MAIN_DEBUG = 0x20, AMS_STATUS_MAIN_UNKNOWN = 0xFF, @@ -51,10 +61,6 @@ enum DevAmsType : int AMS_LITE_MIXED = 5, // AMS-Lite for N9 }; -// Device-numbered filament-change step codes. Newer firmware reports the exact change-step -// sequence through the AMS (ams.cfs), keyed by these codes, instead of the client hardcoding -// steps per model. Distinct from the legacy GUI-side Slic3r::GUI::FilamentStep enum. -// STEP_CHECK_POSITION and STEP_CONFIRM_EXTRUDED share code 0x08 by device design. enum DevFilamentStep { STEP_IDLE = 0x00, @@ -83,37 +89,35 @@ enum DevFilamentStep #define VIRTUAL_AMS_MAIN_ID_STR "255" #define VIRTUAL_AMS_DEPUTY_ID_STR "254" -// Tray index offset for the AMS-Lite-mixed unit (A2L / N9). Its 4 trays occupy -// global tray indices 24..27. -#define AMS_LITE_MIXED_TRAY_INDEX_OFFSET 24 +// Tray index offsets for different AMS types +#define AMS_LITE_MIXED_TRAY_INDEX_OFFSET 24 // Offset for AMS_LITE_MIXED tray index (24) #define INVALID_AMS_TEMPERATURE std::numeric_limits::min() -// (ams_id, slot_id) pair. -using DevAmsSlotId = std::pair; - /* Extruder*/ #define MAIN_EXTRUDER_ID 0 #define DEPUTY_EXTRUDER_ID 1 #define UNIQUE_EXTRUDER_ID MAIN_EXTRUDER_ID #define INVALID_EXTRUDER_ID -1 -/* Logical extruder ids (multi-nozzle). */ +// see PartPlate::get_physical_extruder_by_logical_extruder #define LOGIC_UNIQUE_EXTRUDER_ID 0 #define LOGIC_L_EXTRUDER_ID 0 #define LOGIC_R_EXTRUDER_ID 1 +// +using DevAmsSlotId = std::pair; /* Nozzle*/ -enum NozzleFlowType +enum NozzleFlowType : int { NONE_FLOWTYPE, S_FLOW, H_FLOW, - U_FLOW, // TPU 1.75 High Flow (device-reported; maps to nvtTPUHighFlow) + U_FLOW, // TPU 1.75 High Flow + E_FLOW, // E3D High Flow }; - -// Discrete nozzle diameters reported by the device. +/* 0.2mm 0.4mm 0.6mm 0.8mm */ enum NozzleDiameterType : int { NONE_DIAMETER_TYPE, @@ -135,7 +139,7 @@ enum DevPrintingSpeedLevel }; /*Upgrade*/ -enum class DevFirmwareUpgradingState : int +enum class DevFirmwareUpgradeState : int { DC = -1, UpgradingUnavaliable = 0, @@ -144,6 +148,10 @@ enum class DevFirmwareUpgradingState : int UpgradingFinished = 3 }; +// Orca: transitional shim (removed in resync cluster 8) — DeviceManager/UpgradePanel still use the +// pre-resync name; alias keeps them compiling until they are resynced to the reference name. +using DevFirmwareUpgradingState = DevFirmwareUpgradeState; + class devPrinterUtil { public: @@ -157,9 +165,6 @@ public: namespace GUI { -// Print source. Defined here (rather than in SelectMachine.hpp) so the shared device-mapping -// GUI headers — AmsMappingPopup, wgtDeviceNozzleSelect — can name it without pulling in -// SelectMachine.hpp, which would create an include cycle. enum PrintFromType { FROM_NORMAL, @@ -169,8 +174,6 @@ enum PrintFromType };// namespace Slic3r -// A nozzle requirement of the sliced plate (or an installed nozzle's identity), compared in the -// pre-print slicing-vs-installed nozzle checks. struct NozzleDef { float nozzle_diameter; @@ -190,4 +193,7 @@ template<> struct std::hash size_t h2 = std::hash{}(v.nozzle_flow_type); return h1 ^ (h2 + 0x9e3779b9 + (h1 << 6) + (h1 >> 2)); }; -}; \ No newline at end of file +}; + +// key(extruder_id) -> { key1(nozzle type info), val1( number of the nozzle type)} +using ExtruderNozzleInfos = std::unordered_map>; \ No newline at end of file diff --git a/src/slic3r/GUI/DeviceCore/DevFan.cpp b/src/slic3r/GUI/DeviceCore/DevFan.cpp index 106c3389bd..35cbaae2da 100644 --- a/src/slic3r/GUI/DeviceCore/DevFan.cpp +++ b/src/slic3r/GUI/DeviceCore/DevFan.cpp @@ -61,6 +61,14 @@ static std::string _get_string_from_fantype(int type) int Slic3r::DevFan::command_control_fan(int fan_type, int val) { std::string gcode = (boost::format("M106 P%1% S%2% \n") % (int) fan_type % (val)).str(); + try { + json j; + j["ctrl_type"] = _get_string_from_fantype(fan_type); + j["value"] = val; + + NetworkAgent *agent = GUI::wxGetApp().getAgent(); + if (agent) agent->track_event("printer_control", j.dump()); + } catch (...) {} return m_owner->publish_gcode(gcode); } @@ -166,8 +174,6 @@ void Slic3r::DevFan::ParseV3_0(const json &device) m_air_duct_data.modes.clear(); m_air_duct_data.parts.clear(); - m_air_duct_data.curren_mode = device["airduct"]["modeCur"].get(); - const json &airduct = device["airduct"]; if (airduct.contains("modeCur")) { m_air_duct_data.curren_mode = airduct["modeCur"].get(); } if (airduct.contains("subMode")) { m_air_duct_data.m_sub_mode = airduct["subMode"].get(); } @@ -193,7 +199,7 @@ void Slic3r::DevFan::ParseV3_0(const json &device) } } - if (AIR_DUCT(mode.id) == AIR_DUCT::AIR_DUCT_EXHAUST) { continue; } /*STUDIO-12796*/ + if (AIR_DUCT(mode.id) == AIR_DUCT::AIR_DUCT_EXHAUST) { continue; } m_air_duct_data.modes[mode.id] = mode; } } diff --git a/src/slic3r/GUI/DeviceCore/DevFan.h b/src/slic3r/GUI/DeviceCore/DevFan.h index 120db4da38..ca029e0005 100644 --- a/src/slic3r/GUI/DeviceCore/DevFan.h +++ b/src/slic3r/GUI/DeviceCore/DevFan.h @@ -11,8 +11,6 @@ class MachineObject; enum AirDuctType { AIR_FAN_TYPE, AIR_DOOR_TYPE }; typedef std::function CommandCallBack; - - enum AIR_FUN : int { FAN_HEAT_BREAK_0_IDX = 0, FAN_COOLING_0_AIRDOOR = 1, @@ -91,6 +89,13 @@ public: bool IsSupportCoolingFilter() const { return m_support_cooling_filter; } bool IsCoolingFilerOn() const { return m_sub_mode == 1; } + bool IsExaustFanExit() const + { + for (auto &p : parts) { + if (p.id == int(AIR_FUN::FAN_CHAMBER_0_IDX)) return true; + } + return false; + } }; class DevFan diff --git a/src/slic3r/GUI/DeviceCore/DevFilaAmsSetting.h b/src/slic3r/GUI/DeviceCore/DevFilaAmsSetting.h index 5cecbd5507..793f7757a9 100644 --- a/src/slic3r/GUI/DeviceCore/DevFilaAmsSetting.h +++ b/src/slic3r/GUI/DeviceCore/DevFilaAmsSetting.h @@ -1,5 +1,6 @@ #pragma once #include +#include // Orca: for m_firmwares (kept unordered for not-yet-resynced AMSSetting.cpp) #include #include "DevCtrl.h" @@ -75,7 +76,7 @@ public: DevAmsSystemIdx GetCurrentFirmwareIdxSel() const { return m_current_firmware_sel.m_firmare_idx; }; DevAmsSystemIdx GetCurrentFirmwareIdxRun() const { return m_current_firmware_run.m_firmare_idx; }; - std::unordered_map GetSuppotedFirmwares() const { return m_firmwares;}; + std::unordered_map GetSuppotedFirmwares() const { return m_firmwares;}; // Orca: unordered (AMSSetting.cpp, cluster 8) bool IsSwitching() const { return m_status == "SWITCHING";}; bool IsIdle() const { return m_status == "IDLE";}; @@ -94,7 +95,7 @@ private: DevAmsSystemFirmware m_current_firmware_run; DevAmsSystemFirmware m_current_firmware_sel; - std::unordered_map m_firmwares; + std::unordered_map m_firmwares; // Orca: unordered (AMSSetting.cpp, cluster 8) DevCtrlInfo m_ctrl_switching; }; diff --git a/src/slic3r/GUI/DeviceCore/DevFilaSwitch.cpp b/src/slic3r/GUI/DeviceCore/DevFilaSwitch.cpp index 1f7a9a7623..11034ccfcd 100644 --- a/src/slic3r/GUI/DeviceCore/DevFilaSwitch.cpp +++ b/src/slic3r/GUI/DeviceCore/DevFilaSwitch.cpp @@ -9,19 +9,6 @@ namespace Slic3r { DevFilaSwitch::DevFilaSwitch(MachineObject *owner) { m_owner = owner; } -bool DevFilaSwitch::IsReady() const -{ - if (!m_is_installed) { return false; } - - const auto& ams_list = m_owner->GetFilaSystem()->GetAmsList(); - for (const auto& ams_item : ams_list) { - if (ams_item.second->GetBindedExtruderSet().empty()) { return false; } - if (!ams_item.second->GetSwitcherPos().has_value()) { return false; } - } - - return true; -} - void DevFilaSwitch::Reset() { m_is_installed = false; @@ -34,6 +21,24 @@ void DevFilaSwitch::Reset() m_cali_status = CaliStatus::CALI_IDLE; } +bool DevFilaSwitch::IsReady() const +{ + if (!m_is_installed) { + BOOST_LOG_TRIVIAL(debug) << "[FilaSwitch] IsReady: not installed"; + return false; + } + + const auto& ams_list = m_owner->GetFilaSystem()->GetAmsList(); + for (const auto& ams_item : ams_list) { + if (ams_item.second->GetBindedExtruderSet().size() == 0) { return false; } + if (!ams_item.second->GetSwitcherPos().has_value()) { + return false; + } + } + + return true; +} + std::optional DevFilaSwitch::GetInA_Slot() const { auto ams_id_opt = GetInA_SlotId(); @@ -128,4 +133,4 @@ void DevFilaSwitch::ParseFilaSwitchInfo(const nlohmann::json &print_jj) } } -}; // namespace Slic3r +}; // namespace Slic3r \ No newline at end of file diff --git a/src/slic3r/GUI/DeviceCore/DevFilaSwitch.h b/src/slic3r/GUI/DeviceCore/DevFilaSwitch.h index e18dea338c..48ada5ede1 100644 --- a/src/slic3r/GUI/DeviceCore/DevFilaSwitch.h +++ b/src/slic3r/GUI/DeviceCore/DevFilaSwitch.h @@ -1,7 +1,6 @@ #pragma once #include "DevDefs.h" #include -#include namespace Slic3r { @@ -10,16 +9,11 @@ class MachineObject; class DevExtder; class DevAmsTray; -// Filament Track Switch (H2-family hardware). -// The filament blacklist consumes IsInstalled() for the `has_filament_switch` -// rule (e.g. PLA Silk). m_is_installed defaults to false and is only raised when -// the device reports the switch over MQTT (aux bit 29), so the rule stays inert on -// every printer that does not report an installed switch. class DevFilaSwitch { public: enum class CaliStatus : int - { + { CALI_IDLE = 0, CALI_STEPING = 1, }; @@ -48,10 +42,6 @@ public: public: bool IsInstalled() const { return m_is_installed; }; - - // Ready once installed and every AMS has resolved both its extruder binding and its - // switcher track position from the device. The send dialog and sidebar sync UX only - // treat the switch as usable when this is true. bool IsReady() const; std::optional IsInA_HasFilament() const { return m_in_a_has_filament; }; @@ -88,4 +78,4 @@ private: CaliStatus m_cali_status = CaliStatus::CALI_IDLE; }; -}; +}; \ No newline at end of file diff --git a/src/slic3r/GUI/DeviceCore/DevFilaSystem.h b/src/slic3r/GUI/DeviceCore/DevFilaSystem.h index 27c59183c1..d57686536e 100644 --- a/src/slic3r/GUI/DeviceCore/DevFilaSystem.h +++ b/src/slic3r/GUI/DeviceCore/DevFilaSystem.h @@ -270,10 +270,10 @@ private: AmsType m_ams_type = AmsType::AMS; std::string m_ams_id; int m_ext_id;//extruder id - // Orca: keeps the legacy single m_ext_id for existing consumers and carries the - // switch-aware binding alongside it (BambuStudio stores only the set). Without a Filament - // Track Switch the set is {m_ext_id}; with one installed the device binds both extruders and - // records which input track (A/B) feeds this AMS. + // Orca: pull-mode / multi-vendor agent model — keeps the legacy single m_ext_id for existing + // consumers and carries the switch-aware binding alongside it. Without a Filament Track Switch + // the set is {m_ext_id}; with one installed the device binds both extruders and records which + // input track (A/B) feeds this AMS. std::set m_binded_extruder_set; std::optional m_binded_switcher_pos; bool m_exist = false; diff --git a/src/slic3r/GUI/DeviceCore/DevFilaSystemCtrl.cpp b/src/slic3r/GUI/DeviceCore/DevFilaSystemCtrl.cpp index acdc81dd8c..9a8a3a68d2 100644 --- a/src/slic3r/GUI/DeviceCore/DevFilaSystemCtrl.cpp +++ b/src/slic3r/GUI/DeviceCore/DevFilaSystemCtrl.cpp @@ -28,8 +28,8 @@ int DevFilaSystem::CtrlAmsStartDryingHour(int ams_id, jj_command["print"]["command"] = "ams_filament_drying"; jj_command["print"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++); jj_command["print"]["ams_id"] = ams_id; - jj_command["print"]["mode"] = static_cast(DevAms::DryCtrlMode::OnTime); - jj_command["print"]["filament"] = filament_type; + jj_command["print"]["mode"] = static_cast(DevAms::DryCtrlMode::OnTime); // Orca: cast scoped enum for json + jj_command["print"]["filament"] = filament_type; // Orca: fix comma-operator typo jj_command["print"]["temp"] = tag_temp; jj_command["print"]["duration"] = tag_duration_hour; jj_command["print"]["humidity"] = 0; @@ -45,8 +45,8 @@ int DevFilaSystem::CtrlAmsStopDrying(int ams_id) const jj_command["print"]["command"] = "ams_filament_drying"; jj_command["print"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++); jj_command["print"]["ams_id"] = ams_id; - jj_command["print"]["mode"] = static_cast(DevAms::DryCtrlMode::Off); - jj_command["print"]["filament"] = ""; + jj_command["print"]["mode"] = static_cast(DevAms::DryCtrlMode::Off); // Orca: cast scoped enum for json + jj_command["print"]["filament"] = ""; // Orca: fix comma-operator typo jj_command["print"]["temp"] = 0; jj_command["print"]["duration"] = 0; jj_command["print"]["humidity"] = 0; diff --git a/src/slic3r/GUI/DeviceCore/DevFirmware.h b/src/slic3r/GUI/DeviceCore/DevFirmware.h index eff34db0ea..9dae603702 100644 --- a/src/slic3r/GUI/DeviceCore/DevFirmware.h +++ b/src/slic3r/GUI/DeviceCore/DevFirmware.h @@ -1,4 +1,7 @@ #pragma once +#include "DevFirmware.h" +#include "slic3r/Utils/json_diff.hpp" + #include #include #include "slic3r/Utils/json_diff.hpp" @@ -8,6 +11,7 @@ namespace Slic3r { //Previous definitions class MachineObject; +// Orca: firmware-type enum consumed by DeviceManager/UpgradePanel; no reference-side equivalent yet enum PrinterFirmwareType { FIRMWARE_TYPE_ENGINEER = 0, @@ -15,7 +19,6 @@ enum PrinterFirmwareType FIRMEARE_TYPE_UKNOWN, }; - class FirmwareInfo { public: @@ -40,12 +43,18 @@ public: public: bool isValid() const { return !sn.empty(); } + + /*type check*/ bool isAirPump() const { return product_name.Contains("Air Pump"); } bool isLaszer() const { return product_name.Contains("Laser"); } bool isCuttingModule() const { return product_name.Contains("Cutting Module"); } - bool isExtinguishSystem() const { return product_name.Contains("Extinguishing System"); } - bool isWTM() const { return name.find("wtm") != std::string::npos; } // nozzle (rack hotend) module firmware - bool isFilaTrackSwitch() const { return product_name.Contains("Filament Track"); } + bool isRotary() const { return product_name.Contains("Rotary"); }// Rotary Attachment + bool isExtinguishSystem() const { return product_name.Contains("Extinguishing System"); }// Auto Fire Extinguishing System + bool isWTM() const { return name.find("wtm") != string::npos; } // nozzle + bool isExhaustFan() const { return product_name.Contains("Exhaust Fan"); } + bool isHmshub() const { return product_name.find("Filament Buffer") != string::npos; } + bool isFilaTrackSwitch() const { return product_name.find("Filament Track") != string::npos; } + }; diff --git a/src/slic3r/GUI/DeviceCore/DevHMS.cpp b/src/slic3r/GUI/DeviceCore/DevHMS.cpp index 639421c815..f6ba592c6d 100644 --- a/src/slic3r/GUI/DeviceCore/DevHMS.cpp +++ b/src/slic3r/GUI/DeviceCore/DevHMS.cpp @@ -29,6 +29,7 @@ bool DevHMSItem::parse_hms_info(unsigned attr, unsigned code) std::string DevHMSItem::get_long_error_code() const { char buf[64]; + // Orca: HMS long-error-code format excludes the reserved byte and keys the Orca HMS wiki lookups ::sprintf(buf, "%02X%02X%02X00000%1X%04X", this->m_module_id, this->m_module_num, diff --git a/src/slic3r/GUI/DeviceCore/DevInfo.h b/src/slic3r/GUI/DeviceCore/DevInfo.h index bc48e6cf1d..50a060c0b2 100644 --- a/src/slic3r/GUI/DeviceCore/DevInfo.h +++ b/src/slic3r/GUI/DeviceCore/DevInfo.h @@ -8,6 +8,10 @@ namespace Slic3r { class MachineObject; /* some static info of machine*/ /*TODO*/ +// Orca: kept as a stub — connection_type/is_lan_mode_printer/is_cloud_mode_printer live inline on +// MachineObject (DeviceManager.hpp). Adopting the reference's full DevInfo would duplicate those +// definitions and require an m_dev_info member MachineObject does not have; that consolidation is +// deferred to the DeviceManager resync (cluster 2). class DevInfo { public: diff --git a/src/slic3r/GUI/DeviceCore/DevMappingNozzle.cpp b/src/slic3r/GUI/DeviceCore/DevMappingNozzle.cpp index 405a7c4171..76bfa8364c 100644 --- a/src/slic3r/GUI/DeviceCore/DevMappingNozzle.cpp +++ b/src/slic3r/GUI/DeviceCore/DevMappingNozzle.cpp @@ -16,10 +16,6 @@ #include "slic3r/GUI/GUI_App.hpp" -#include -#include - -#include #include #include using namespace nlohmann; @@ -33,30 +29,6 @@ void MachineObject::clear_auto_nozzle_mapping() } } -static std::string s_get_diameter_str(float diameter) -{ - return (boost::format("%.2f") % diameter).str(); -} - -static std::string s_get_diameter_str(const std::string& diameter) -{ - try { - float dia = boost::lexical_cast(diameter); - return s_get_diameter_str(dia); - } catch (...) { - BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " failed to boost::lexical_cast: " << diameter; - return diameter; - } - - try { - float dia = std::stof(diameter); - return s_get_diameter_str(dia); - } catch (...) { - BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " std::stof: " << diameter; - return diameter; - } -} - // get auto nozzle mapping through AP // warnings: @@ -268,7 +240,7 @@ int DevNozzleMappingCtrl::CtrlGetAutoNozzleMappingV1(Slic3r::GUI::Plater* plater void DevNozzleMappingCtrl::ParseAutoNozzleMapping(const json& print_jj) { - if (print_jj.contains("command") && print_jj["command"].get() == "get_auto_nozzle_mapping") { + if (print_jj.contains("command") && print_jj["command"].get() == "get_auto_nozzle_mapping") { if (print_jj.contains("sequence_id") && print_jj["sequence_id"] == m_sequence_id) { Clear(); DevJsonValParser::ParseVal(print_jj, "result", m_result); @@ -482,4 +454,4 @@ float DevNozzleMappingCtrl::GetFlushWeight(Slic3r::MachineObject* obj) const return total_flush_volume * 1.26 * 0.001; } -} // namespace Slic3r +} // namespace Slic3r \ No newline at end of file diff --git a/src/slic3r/GUI/DeviceCore/DevMappingNozzle.h b/src/slic3r/GUI/DeviceCore/DevMappingNozzle.h index 9ca306eec9..7b0f9d0e25 100644 --- a/src/slic3r/GUI/DeviceCore/DevMappingNozzle.h +++ b/src/slic3r/GUI/DeviceCore/DevMappingNozzle.h @@ -18,7 +18,7 @@ namespace GUI class Plater; } -struct FilamentInfo; // libslic3r/ProjectTask.hpp +struct FilamentInfo; // Orca: libslic3r/ProjectTask.hpp — forward-decl for CtrlGetAutoNozzleMappingV0 signature class MachineObject; class DevNozzleMappingCtrl diff --git a/src/slic3r/GUI/DeviceCore/DevStorage.cpp b/src/slic3r/GUI/DeviceCore/DevStorage.cpp index de4d007e46..0c60b096bd 100644 --- a/src/slic3r/GUI/DeviceCore/DevStorage.cpp +++ b/src/slic3r/GUI/DeviceCore/DevStorage.cpp @@ -19,17 +19,17 @@ DevStorage::SdcardState Slic3r::DevStorage::set_sdcard_state(int state) { if (system) { - if (print_json.contains("sdcard")) { - if (print_json["sdcard"].get()) - system->m_sdcard_state = DevStorage::SdcardState::HAS_SDCARD_NORMAL; - else - system->m_sdcard_state = DevStorage::SdcardState::NO_SDCARD; - } else { - system->m_sdcard_state = DevStorage::SdcardState::NO_SDCARD; - } - - // parse timelapse storage space from cam push data try { + if (print_json.contains("sdcard")) { + if (print_json["sdcard"].get()) + system->m_sdcard_state = DevStorage::SdcardState::HAS_SDCARD_NORMAL; + else + system->m_sdcard_state = DevStorage::SdcardState::NO_SDCARD; + } else { + system->m_sdcard_state = DevStorage::SdcardState::NO_SDCARD; + } + + // parse timelapse storage space from cam push data if (print_json.contains("device") && print_json["device"].is_object()) { const auto& device_json = print_json["device"]; if (device_json.contains("cam") && device_json["cam"].is_object()) { @@ -45,17 +45,16 @@ DevStorage::SdcardState Slic3r::DevStorage::set_sdcard_state(int state) } } } catch (...) {} - } + } } bool DevStorage::is_timelapse_storage_low(const std::string& storage) const { - const int THRESHOLD_KB = 20480; // 20MB + const int THRESHOLD_KB = 20480; // Orca: 20MB (20480 KB; corrected mislabeled comment) if (storage == "internal") return tl_internal_free_kb >= 0 && tl_internal_free_kb < THRESHOLD_KB; else return tl_external_free_kb >= 0 && tl_external_free_kb < THRESHOLD_KB; } - } // namespace Slic3r \ No newline at end of file diff --git a/src/slic3r/GUI/DeviceCore/DevStorage.h b/src/slic3r/GUI/DeviceCore/DevStorage.h index d3c03e7fe6..537665f778 100644 --- a/src/slic3r/GUI/DeviceCore/DevStorage.h +++ b/src/slic3r/GUI/DeviceCore/DevStorage.h @@ -26,7 +26,7 @@ public: SdcardState get_sdcard_state() const { return m_sdcard_state; }; SdcardState set_sdcard_state(int state); - static void ParseV1_0(const json &print_json, DevStorage *system); + static void ParseV1_0(const json &print_json, DevStorage *system); bool is_timelapse_storage_low(const std::string& storage) const; @@ -34,10 +34,13 @@ private: MachineObject *m_owner; SdcardState m_sdcard_state { NO_SDCARD }; // timelapse storage space info (from device push cam data) - int tl_internal_free_kb { -1 }; - int tl_internal_total_kb { -1 }; - int tl_external_free_kb { -1 }; - int tl_external_total_kb { -1 }; + int tl_internal_free_kb{-1}; + int tl_internal_total_kb{-1}; + int tl_external_free_kb{-1}; + int tl_external_total_kb{-1}; + + + }; } // namespace Slic3r \ No newline at end of file diff --git a/src/slic3r/GUI/DeviceCore/DevUtil.cpp b/src/slic3r/GUI/DeviceCore/DevUtil.cpp index 27cec11160..19296d5773 100644 --- a/src/slic3r/GUI/DeviceCore/DevUtil.cpp +++ b/src/slic3r/GUI/DeviceCore/DevUtil.cpp @@ -24,6 +24,79 @@ int DevUtil::get_flag_bits(std::string str, int start, int count) return 0; } +uint32_t DevUtil::get_flag_bits_no_border(std::string str, int start_idx, int count) +{ + if (start_idx < 0 || count <= 0) return 0; + + try { + // --- 1) trim --- + auto ltrim = [](std::string &s) { s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) { return !std::isspace(ch); })); }; + auto rtrim = [](std::string &s) { s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) { return !std::isspace(ch); }).base(), s.end()); }; + ltrim(str); + rtrim(str); + + // --- 2) remove 0x/0X prefix --- + if (str.size() >= 2 && str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) { str.erase(0, 2); } + + // --- 3) keep only hex digits --- + std::string hex; + hex.reserve(str.size()); + for (char c : str) { + if (std::isxdigit(static_cast(c))) hex.push_back(c); + } + if (hex.empty()) return 0; + + // --- 4) use size_t for all index/bit math --- + const size_t total_bits = hex.size() * 4ULL; + + const size_t ustart = static_cast(start_idx); + if (ustart >= total_bits) return 0; + + const int int_bits = std::numeric_limits::digits; // typically 32 + const size_t need_bits = static_cast(std::min(count, int_bits)); + + // [first_bit, last_bit] + const size_t first_bit = ustart; + const size_t last_bit = std::min(ustart + need_bits, total_bits) - 1ULL; + if (last_bit < first_bit) return 0; + + const size_t right_index = hex.size() - 1ULL; + + const size_t first_nibble = first_bit / 4ULL; + const size_t last_nibble = last_bit / 4ULL; + + const size_t start_idx = right_index - last_nibble; + const size_t end_idx = right_index - first_nibble; + if (end_idx < start_idx) return 0; + + const size_t sub_len = end_idx - start_idx + 1ULL; + if (end_idx >= hex.size()) return 0; + + const std::string sub_hex = hex.substr(start_idx, sub_len); + + unsigned long long chunk = std::stoull(sub_hex, nullptr, 16); + + const unsigned nibble_offset = static_cast(first_bit % 4ULL); + const unsigned long long shifted = (nibble_offset == 0U) ? chunk : (chunk >> nibble_offset); + + uint32_t mask; + if (need_bits >= static_cast(std::numeric_limits::digits)) { + mask = std::numeric_limits::max(); + } else { + mask = static_cast((1ULL << need_bits) - 1ULL); + } + + const uint32_t val = static_cast(shifted & mask); + return val; + } catch (const std::invalid_argument &) { + return 0; + } catch (const std::out_of_range &) { + return 0; + } catch (...) { + return 0; + } +} + int DevUtil::get_flag_bits(int num, int start, int count, int base) { diff --git a/src/slic3r/GUI/DeviceCore/DevUtil.h b/src/slic3r/GUI/DeviceCore/DevUtil.h index fcf912b622..0b02dd25a9 100644 --- a/src/slic3r/GUI/DeviceCore/DevUtil.h +++ b/src/slic3r/GUI/DeviceCore/DevUtil.h @@ -12,8 +12,15 @@ #include #include +#include + #include "nlohmann/json.hpp" + /* Sequence Id*/ +#define STUDIO_START_SEQ_ID 20000 +#define STUDIO_END_SEQ_ID 30000 +#define CLOUD_SEQ_ID 0 + namespace Slic3r { @@ -27,14 +34,18 @@ public: public: static int get_flag_bits(std::string str, int start, int count = 1); static int get_flag_bits(int num, int start, int count = 1, int base = 10); + static uint32_t get_flag_bits_no_border(std::string str, int start_idx, int count = 1); - // Extract the hex digit at position `pos` (0 = least-significant). // eg. get_hex_bits(16, 1, 10) = 1 - static int get_hex_bits(int num, int pos, int input_num_base = 10) { return get_flag_bits(num, pos * 4, 4, input_num_base); } + static int get_hex_bits(int num, int pos, int input_num_base = 10) { return get_flag_bits(num, pos * 4, 4, input_num_base);}; static float string_to_float(const std::string& str_value); static std::string convertToIp(long long ip); + + // sequence id check + static bool is_studio_cmd(int seq) { return seq >= STUDIO_START_SEQ_ID && seq < STUDIO_END_SEQ_ID;}; + static bool is_cloud_cmd(int seq) { return seq == CLOUD_SEQ_ID;}; }; @@ -108,4 +119,94 @@ struct NumericStrCompare } }; +enum class DirtyMode{ + COUNTER, + TIMER +}; + +template +class DevDirtyHandler{ +public: + DevDirtyHandler(T init_value, int setting_threshold, DirtyMode mode): m_value(init_value), m_setting_threshold(setting_threshold), m_mode(mode) + { + m_threshold = setting_threshold; + } + ~DevDirtyHandler(){}; + + T GetValue() const { return m_value; }; + + void SetOptimisticValue(const T& data) + { + m_value = data; + m_start_time = time(nullptr); + m_threshold = m_setting_threshold; + } + + void UpdateValue(const T& data) + { + if (m_mode == DirtyMode::COUNTER) + { + if (m_threshold > 0) + m_threshold--; + else + m_value = data; + } + else if (m_mode == DirtyMode::TIMER) + { + if (time(nullptr) - m_start_time > m_threshold) + m_value = data; + } + } + +private: + T m_value; + DirtyMode m_mode; + int m_setting_threshold{0}; + + int m_start_time{0}; + int m_threshold{0}; +}; + + +static std::string s_get_diameter_str(float diameter) +{ + return (boost::format("%.2f") % diameter).str(); +} + +static std::string s_get_diameter_str(const std::string& diameter) +{ + try { + float dia = boost::lexical_cast(diameter); + return s_get_diameter_str(dia); + } catch (...) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " failed to boost::lexical_cast: " << diameter; + return diameter; + } + + try { + float dia = std::stof(diameter); + return s_get_diameter_str(dia); + } catch (...) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " std::stof: " << diameter; + return diameter; + } +} + +static float s_get_diameter(const std::string& diameter) +{ + try { + return boost::lexical_cast(diameter); + } catch (...) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " failed to boost::lexical_cast: " << diameter; + } + + try { + return std::stof(diameter); + } catch (...) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " std::stof: " << diameter; + } + + return 0.0; +} + }; // namespace Slic3r \ No newline at end of file diff --git a/src/slic3r/GUI/DeviceCore/DevUtilBackend.cpp b/src/slic3r/GUI/DeviceCore/DevUtilBackend.cpp index 32d30379f6..5d051dc876 100644 --- a/src/slic3r/GUI/DeviceCore/DevUtilBackend.cpp +++ b/src/slic3r/GUI/DeviceCore/DevUtilBackend.cpp @@ -2,15 +2,28 @@ #include "slic3r/GUI/BackgroundSlicingProcess.hpp" +#include "slic3r/GUI/PartPlate.hpp" #include "slic3r/GUI/Plater.hpp" #include "slic3r/GUI/GUI_App.hpp" -#include +#include +#include namespace Slic3r { -std::shared_ptr DevUtilBackend::GetNozzleGroupResult(Slic3r::GUI::Plater* plater) + +Slic3r::MultiNozzleUtils::NozzleInfo DevUtilBackend::GetNozzleInfo(const DevNozzle& dev_nozzle) +{ + MultiNozzleUtils::NozzleInfo info; + info.diameter = dev_nozzle.GetNozzleDiameterStr().ToStdString(); + info.volume_type = DevNozzle::ToNozzleVolumeType(dev_nozzle.GetNozzleFlowType()); + info.extruder_id = dev_nozzle.GetLogicExtruderId(); + + return info; +} + +std::shared_ptr DevUtilBackend::GetNozzleGroupResult(Slic3r::GUI::Plater *plater) { if (plater && plater->background_process().get_current_gcode_result()) { return plater->background_process().get_current_gcode_result()->nozzle_group_result; @@ -19,6 +32,29 @@ std::shared_ptr DevUtilBackend::GetNozz return nullptr; } +std::unordered_map DevUtilBackend::CollectNozzleInfo(MultiNozzleUtils::NozzleGroupResultBase *nozzle_group_res, int logic_ext_id) +{ + std::unordered_map need_nozzle_map; + if (!nozzle_group_res) { + return need_nozzle_map; + } + + const std::vector& nozzle_vec = nozzle_group_res->get_used_nozzles_in_extruder(logic_ext_id); + for (auto slicing_nozzle : nozzle_vec) { + try { + NozzleDef data; + data.nozzle_diameter = boost::lexical_cast(slicing_nozzle.diameter); + data.nozzle_flow_type = DevNozzle::ToNozzleFlowType(slicing_nozzle.volume_type); + need_nozzle_map[data]++; + } catch (const std::exception& e) { + assert(0); + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << "exception: " << e.what(); + } + } + + return need_nozzle_map; +} + static std::unordered_map s_ams_type_map = { {"0", DevAmsType::N3F}, {"1", DevAmsType::N3S}, @@ -41,6 +77,7 @@ std::optional DevUtilBackend::GetFilamentDrying std::vector types = config.option("filament_dev_ams_drying_ams_limitations")->values; for (auto type : types) { if (s_ams_type_map.count(type) == 0) { + // assert(0); continue; } info.ams_limitations.insert(s_ams_type_map[type]); @@ -62,10 +99,10 @@ std::optional DevUtilBackend::GetFilamentDrying } if (config.has("filament_dev_drying_softening_temperature")) { - info.filament_dev_drying_softening_temperature = config.option("filament_dev_drying_softening_temperature")->get_at(0); + info.filament_dev_drying_softening_temperature = config.option("filament_dev_drying_softening_temperature")->get_at(0); } - if (config.has("filament_dev_ams_drying_heat_distortion_temperature")) { + if (config.has("filament_dev_ams_drying_heat_distortion_temperature")){ info.filament_dev_ams_drying_heat_distortion_temperature = config.option("filament_dev_ams_drying_heat_distortion_temperature")->get_at(0); } @@ -83,4 +120,4 @@ std::optional DevUtilBackend::GetFilamentDrying return std::nullopt; } -}; // namespace Slic3r +};// namespace Slic3r \ No newline at end of file diff --git a/src/slic3r/GUI/DeviceCore/DevUtilBackend.h b/src/slic3r/GUI/DeviceCore/DevUtilBackend.h index 5c7869f1e4..ffcfc5fa2e 100644 --- a/src/slic3r/GUI/DeviceCore/DevUtilBackend.h +++ b/src/slic3r/GUI/DeviceCore/DevUtilBackend.h @@ -1,19 +1,32 @@ /** * @file DevUtilBackend.h * @brief Provides common static utility methods for backend (preset/slicing). + * + * This class offers a collection of static helper functions such as string manipulation, + * file operations, and other frequently used utilities. */ #pragma once #include "DevDefs.h" +#include "DevNozzleSystem.h" #include "DevFilaSystem.h" #include "libslic3r/MultiNozzleUtils.hpp" -#include -#include +#include + + // Forward declarations +namespace Slic3r +{ +class MachineObject; + +namespace GUI +{ +class Plater; +} +}; // namespace Slic3r::GUI namespace Slic3r { -namespace GUI { class Plater; } class DevUtilBackend { @@ -21,14 +34,14 @@ public: DevUtilBackend() = delete; public: + static MultiNozzleUtils::NozzleInfo GetNozzleInfo(const DevNozzle& dev_nozzle); - // for rack: the slicer's per-filament -> logical-nozzle grouping for the current plate, read off - // the post-slice GCodeProcessorResult (plater->background_process().get_current_gcode_result()). - // Returns nullptr when there is no plater / no current result. - static std::shared_ptr GetNozzleGroupResult(Slic3r::GUI::Plater* plater); + // for rack + static std::shared_ptr GetNozzleGroupResult(Slic3r::GUI::Plater *plater); + static std::unordered_map CollectNozzleInfo(MultiNozzleUtils::NozzleGroupResultBase *nozzle_group_res, int logic_ext_id); // for filament preset static std::optional GetFilamentDryingPreset(const std::string& fila_id); }; -}; // namespace Slic3r +}; // namespace Slic3r \ No newline at end of file