From aa75c444aa554fad5f1d98614072c2bee9e4daa6 Mon Sep 17 00:00:00 2001 From: "haolin.tian" Date: Tue, 23 Sep 2025 20:20:06 +0800 Subject: [PATCH] NEW: print with emmc jira: [STUDIO-14427] Change-Id: I8b0c56ce1c2b7b90949b72c49acfdbb31c876df1 (cherry picked from commit 76e45bde2540ee418719e00b999c5fd724baec71) --- src/slic3r/GUI/DeviceManager.cpp | 106 ++++++++++++++++++++++++- src/slic3r/GUI/DeviceManager.hpp | 4 + src/slic3r/GUI/Jobs/PrintJob.cpp | 29 +++++-- src/slic3r/GUI/Jobs/PrintJob.hpp | 1 + src/slic3r/GUI/SelectMachine.cpp | 4 +- src/slic3r/Utils/CalibUtils.cpp | 2 + src/slic3r/Utils/FileTransferUtils.cpp | 6 ++ src/slic3r/Utils/FileTransferUtils.hpp | 3 + 8 files changed, 145 insertions(+), 10 deletions(-) diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index 16005ab83d..826aef08a3 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -4986,6 +4986,18 @@ void MachineObject::parse_new_info(json print) is_support_idelheadingprotect_detection = get_flag_bits(fun, 62); } + /*fun2*/ + std::string fun2; + if (print.contains("fun2") && print["fun2"].is_string()) { + fun2 = print["fun2"].get(); + BOOST_LOG_TRIVIAL(info) << "new print data fun2 = " << fun; + } + + // fun2 may have infinite length, use get_flag_bits_no_border + if (!fun2.empty()) { + is_support_print_with_emmc = get_flag_bits_no_border(fun2, 0) == 1; + } + /*aux*/ std::string aux = print["aux"].get(); @@ -4993,7 +5005,6 @@ void MachineObject::parse_new_info(json print) if (!aux.empty()) { m_storage->set_sdcard_state(get_flag_bits(aux, 12, 2)); - //sdcard_state = MachineObject::SdcardState(get_flag_bits(aux, 12, 2)); } /*stat*/ @@ -5036,6 +5047,10 @@ void MachineObject::parse_new_info(json print) } } +static bool is_hex_digit(char c) { + return std::isxdigit(static_cast(c)) != 0; +} + int MachineObject::get_flag_bits(std::string str, int start, int count) const { try { @@ -5043,7 +5058,94 @@ int MachineObject::get_flag_bits(std::string str, int start, int count) const unsigned long long mask = (1ULL << count) - 1; int flag = (decimal_value >> start) & mask; return flag; - } catch (...) { + } + catch (...) { + return 0; + } +} + +uint32_t MachineObject::get_flag_bits_no_border(std::string str, int start_idx, int count) const +{ + 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; } } diff --git a/src/slic3r/GUI/DeviceManager.hpp b/src/slic3r/GUI/DeviceManager.hpp index 5cf9e27253..60b08997d2 100644 --- a/src/slic3r/GUI/DeviceManager.hpp +++ b/src/slic3r/GUI/DeviceManager.hpp @@ -605,6 +605,9 @@ public: bool is_support_airprinting_detection{false}; bool is_support_idelheadingprotect_detection{false}; + // fun2 + bool is_support_print_with_emmc{false}; + bool installed_upgrade_kit{false}; int bed_temperature_limit = -1; @@ -858,6 +861,7 @@ public: bool check_enable_np(const json& print) const; void parse_new_info(json print); int get_flag_bits(std::string str, int start, int count = 1) const; + uint32_t get_flag_bits_no_border(std::string str, int start_idx, int count = 1) const; int get_flag_bits(int num, int start, int count = 1, int base = 10) const; /* Device Filament Check */ diff --git a/src/slic3r/GUI/Jobs/PrintJob.cpp b/src/slic3r/GUI/Jobs/PrintJob.cpp index 1b63392c6b..c115c8dbbc 100644 --- a/src/slic3r/GUI/Jobs/PrintJob.cpp +++ b/src/slic3r/GUI/Jobs/PrintJob.cpp @@ -12,6 +12,8 @@ #include "slic3r/GUI/DeviceCore/DevManager.h" #include "slic3r/GUI/DeviceCore/DevUtil.h" +#include "slic3r/Utils/FileTransferUtils.hpp" + namespace Slic3r { namespace GUI { @@ -206,13 +208,26 @@ void PrintJob::process(Ctl &ctl) // check access code and ip address if (this->connection_type == "lan" && m_print_type == "from_normal") { - params.dev_id = m_dev_id; - params.project_name = "verify_job"; - params.filename = job_data._temp_path.string(); - params.connection_type = this->connection_type; + bool emmc_ok = false; + bool ftp_ok = false; + if (could_emmc_print) { + std::string devIP = m_dev_ip; + std::string accessCode = m_access_code; + std::string url = "bambu:///local/" + devIP + "?port=6000&user=" + "bblp" + "&passwd=" + accessCode; + std::unique_ptr tunnel = std::make_unique(module(), url); + emmc_ok = tunnel->sync_start_connect(); + } + { + params.dev_id = m_dev_id; + params.project_name = "verify_job"; + params.filename = job_data._temp_path.string(); + params.connection_type = this->connection_type; - result = m_agent->start_send_gcode_to_sdcard(params, nullptr, nullptr, nullptr); - if (result != 0) { + result = m_agent->start_send_gcode_to_sdcard(params, nullptr, nullptr, nullptr); + + ftp_ok = result == 0; + } + if (!emmc_ok && !ftp_ok) { BOOST_LOG_TRIVIAL(error) << "access code is invalid"; m_enter_ip_address_fun_fail(); m_job_finished = true; @@ -563,7 +578,7 @@ void PrintJob::process(Ctl &ctl) } } } else { - if (this->has_sdcard) { + if (this->has_sdcard || this->could_emmc_print) { ctl.update_status(curr_percent, _u8L("Sending print job over LAN")); result = m_agent->start_local_print(params, update_fn, cancel_fn); } else { diff --git a/src/slic3r/GUI/Jobs/PrintJob.hpp b/src/slic3r/GUI/Jobs/PrintJob.hpp index eb81a31176..4359de62a2 100644 --- a/src/slic3r/GUI/Jobs/PrintJob.hpp +++ b/src/slic3r/GUI/Jobs/PrintJob.hpp @@ -82,6 +82,7 @@ public: bool task_layer_inspect; bool cloud_print_only { false }; bool has_sdcard { false }; + bool could_emmc_print { false }; bool task_use_ams { true }; bool task_ext_change_assist { false }; diff --git a/src/slic3r/GUI/SelectMachine.cpp b/src/slic3r/GUI/SelectMachine.cpp index cf57b5c3a2..aa529d6606 100644 --- a/src/slic3r/GUI/SelectMachine.cpp +++ b/src/slic3r/GUI/SelectMachine.cpp @@ -2524,6 +2524,7 @@ void SelectMachineDialog::on_send_print() } m_print_job->has_sdcard = obj_->GetStorage()->get_sdcard_state() == DevStorage::SdcardState::HAS_SDCARD_NORMAL; + m_print_job->could_emmc_print = obj_->is_support_print_with_emmc; bool timelapse_option = m_checkbox_list["timelapse"]->IsShown()?true:false; @@ -3322,7 +3323,8 @@ void SelectMachineDialog::update_show_status(MachineObject* obj_) /*check sdcard when if lan mode printer*/ if (obj_->is_lan_mode_printer()) { - if (obj_->GetStorage()->get_sdcard_state() == DevStorage::SdcardState::NO_SDCARD) { + if (obj_->GetStorage()->get_sdcard_state() == DevStorage::SdcardState::NO_SDCARD + && !obj_->is_support_print_with_emmc) { show_status(PrintDialogStatus::PrintStatusLanModeNoSdcard); return; } else if (obj_->GetStorage()->get_sdcard_state() == DevStorage::SdcardState::HAS_SDCARD_ABNORMAL || obj_->GetStorage()->get_sdcard_state() == DevStorage::SdcardState::HAS_SDCARD_READONLY) { diff --git a/src/slic3r/Utils/CalibUtils.cpp b/src/slic3r/Utils/CalibUtils.cpp index 0f36f91fb3..313ca1ce85 100644 --- a/src/slic3r/Utils/CalibUtils.cpp +++ b/src/slic3r/Utils/CalibUtils.cpp @@ -1832,6 +1832,7 @@ void CalibUtils::send_to_print(const CalibInfo &calib_info, wxString &error_mess print_job->set_calibration_task(true); print_job->has_sdcard = obj_->GetStorage()->get_sdcard_state() == DevStorage::HAS_SDCARD_NORMAL; + print_job->could_emmc_print = obj_->is_support_print_with_emmc; print_job->set_print_config(MachineBedTypeString[bed_type], true, false, false, false, true, false, 0, 0, 0); print_job->set_print_job_finished_event(wxGetApp().plater()->get_send_calibration_finished_event(), print_job->m_project_name); @@ -1948,6 +1949,7 @@ void CalibUtils::send_to_print(const std::vector &calib_infos, wxStri print_job->set_calibration_task(true); print_job->has_sdcard = obj_->GetStorage()->get_sdcard_state() == DevStorage::HAS_SDCARD_NORMAL; + print_job->could_emmc_print = obj_->is_support_print_with_emmc; print_job->set_print_config(MachineBedTypeString[bed_type], true, true, false, false, true, false, 0, 1, 0); print_job->set_print_job_finished_event(wxGetApp().plater()->get_send_calibration_finished_event(), print_job->m_project_name); diff --git a/src/slic3r/Utils/FileTransferUtils.cpp b/src/slic3r/Utils/FileTransferUtils.cpp index 5d0b3e04f2..25fbd4f99a 100644 --- a/src/slic3r/Utils/FileTransferUtils.cpp +++ b/src/slic3r/Utils/FileTransferUtils.cpp @@ -19,6 +19,7 @@ FileTransferModule::FileTransferModule(ModuleHandle networking_module, int requi ft_tunnel_retain = sym_lookup(networking_, "ft_tunnel_retain"); ft_tunnel_release = sym_lookup(networking_, "ft_tunnel_release"); ft_tunnel_start_connect = sym_lookup(networking_, "ft_tunnel_start_connect"); + ft_tunnel_sync_connect = sym_lookup(networking_, "ft_tunnel_sync_connect"); ft_tunnel_set_status_cb = sym_lookup(networking_, "ft_tunnel_set_status_cb"); ft_tunnel_shutdown = sym_lookup(networking_, "ft_tunnel_shutdown"); @@ -69,6 +70,11 @@ void FileTransferTunnel::start_connect() if (m_->ft_tunnel_start_connect(h_, tramp, &conn_cb_) == ft_err::FT_EXCEPTION) { throw std::runtime_error("ft_tunnel_start_connect failed"); } } +bool FileTransferTunnel::sync_start_connect() +{ + return m_->ft_tunnel_sync_connect(h_) == FT_OK; +} + void FileTransferTunnel::on_connection(ConnectionCb cb) { conn_cb_ = std::move(cb); } void FileTransferTunnel::on_status(TunnelStatusCb cb) { status_cb_ = std::move(cb); } diff --git a/src/slic3r/Utils/FileTransferUtils.hpp b/src/slic3r/Utils/FileTransferUtils.hpp index bb2e7d29a7..a7f89cf919 100644 --- a/src/slic3r/Utils/FileTransferUtils.hpp +++ b/src/slic3r/Utils/FileTransferUtils.hpp @@ -76,6 +76,7 @@ using fn_ft_tunnel_create = ft_err(FT_CALL *)(const char *url, FT_TunnelH using fn_ft_tunnel_retain = void(FT_CALL *)(FT_TunnelHandle *); using fn_ft_tunnel_release = void(FT_CALL *)(FT_TunnelHandle *); using fn_ft_tunnel_start_connect = ft_err(FT_CALL *)(FT_TunnelHandle *, void(FT_CALL *)(void *user, int ok, int err, const char *msg), void *user); +using fn_ft_tunnel_sync_connect = ft_err(FT_CALL *)(FT_TunnelHandle *); using fn_ft_tunnel_set_status_cb = ft_err(FT_CALL *)(FT_TunnelHandle *, void(FT_CALL *)(void *user, int old_status, int new_status, int err, const char *msg), void *user); using fn_ft_tunnel_shutdown = ft_err(FT_CALL *)(FT_TunnelHandle *); @@ -107,6 +108,7 @@ struct FileTransferModule fn_ft_tunnel_retain ft_tunnel_retain{}; fn_ft_tunnel_release ft_tunnel_release{}; fn_ft_tunnel_start_connect ft_tunnel_start_connect{}; + fn_ft_tunnel_sync_connect ft_tunnel_sync_connect{}; fn_ft_tunnel_set_status_cb ft_tunnel_set_status_cb{}; fn_ft_tunnel_shutdown ft_tunnel_shutdown{}; @@ -146,6 +148,7 @@ public: FileTransferTunnel &operator=(FileTransferTunnel &&) = delete; void start_connect(); + bool sync_start_connect(); void on_connection(ConnectionCb cb); void on_status(TunnelStatusCb cb);