diff --git a/src/slic3r/GUI/DeviceCore/DevManager.cpp b/src/slic3r/GUI/DeviceCore/DevManager.cpp index b1e1f7266e..8f7953005a 100644 --- a/src/slic3r/GUI/DeviceCore/DevManager.cpp +++ b/src/slic3r/GUI/DeviceCore/DevManager.cpp @@ -14,6 +14,8 @@ #include "libslic3r/Time.hpp" +#include "IPrinterAgent.hpp" + using namespace nlohmann; namespace { diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index 4bfee32879..06f574c8a2 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -51,6 +51,7 @@ #include "DeviceCore/DevStatus.h" #include "DeviceCore/DevUpgrade.h" +#include "IPrinterAgent.hpp" #define CALI_DEBUG #define MINUTE_30 1800000 //ms @@ -1469,26 +1470,29 @@ int MachineObject::command_upgrade_module(std::string url, std::string module_ty int MachineObject::command_xyz_abs() { - return this->publish_gcode("G90 \n"); + if (!m_agent) return -1; + int rtn = m_agent->command_xyz_abs(get_dev_id(), MachineObject::m_sequence_id++, is_lan_mode_printer()); + if (rtn == ORCA_NETWORK_ERR_CMD_NOT_SUPPORTED || rtn == ORCA_NETWORK_ERR_CAP_NOT_AVAILABLE) + show_unsupported_dlg(rtn); + return rtn; } int MachineObject::command_auto_leveling() { - return this->publish_gcode("G29 \n"); + if (!m_agent) return -1; + int rtn = m_agent->command_auto_leveling(get_dev_id(), MachineObject::m_sequence_id++, is_lan_mode_printer()); + if (rtn == ORCA_NETWORK_ERR_CMD_NOT_SUPPORTED || rtn == ORCA_NETWORK_ERR_CAP_NOT_AVAILABLE) + show_unsupported_dlg(rtn); + return rtn; } int MachineObject::command_go_home() { - if (m_support_mqtt_homing) - { - json j; - j["print"]["command"] = "back_to_center"; - j["print"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++); - return this->publish_json(j); - } - - // gcode command - return this->is_in_printing() ? this->publish_gcode("G28 X\n") : this->publish_gcode("G28 \n"); + if (!m_agent) return -1; + int rtn = m_agent->command_go_home(get_dev_id(), this->is_in_printing(), m_support_mqtt_homing, MachineObject::m_sequence_id++, is_lan_mode_printer()); + if (rtn == ORCA_NETWORK_ERR_CMD_NOT_SUPPORTED || rtn == ORCA_NETWORK_ERR_CAP_NOT_AVAILABLE) + show_unsupported_dlg(rtn); + return rtn; } int MachineObject::command_task_partskip(std::vector part_ids) @@ -1610,23 +1614,20 @@ int MachineObject::command_stop_buzzer() int MachineObject::command_set_bed(int temp) { - if (m_support_mqtt_bet_ctrl) - { - json j; - j["print"]["command"] = "set_bed_temp"; - j["print"]["temp"] = temp; - j["print"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++); - return this->publish_json(j); - } - - std::string gcode_str = (boost::format("M140 S%1%\n") % temp).str(); - return this->publish_gcode(gcode_str); + if (!m_agent) return -1; + int rtn = m_agent->command_set_bed(get_dev_id(), temp, m_support_mqtt_bet_ctrl, MachineObject::m_sequence_id++, is_lan_mode_printer()); + if (rtn == ORCA_NETWORK_ERR_CMD_NOT_SUPPORTED || rtn == ORCA_NETWORK_ERR_CAP_NOT_AVAILABLE) + show_unsupported_dlg(rtn); + return rtn; } int MachineObject::command_set_nozzle(int temp) { - std::string gcode_str = (boost::format("M104 S%1%\n") % temp).str(); - return this->publish_gcode(gcode_str); + if (!m_agent) return -1; + int rtn = m_agent->command_set_nozzle(get_dev_id(), temp, MachineObject::m_sequence_id++, is_lan_mode_printer()); + if (rtn == ORCA_NETWORK_ERR_CMD_NOT_SUPPORTED || rtn == ORCA_NETWORK_ERR_CAP_NOT_AVAILABLE) + show_unsupported_dlg(rtn); + return rtn; } int MachineObject::command_set_nozzle_new(int nozzle_id, int temp) @@ -1962,47 +1963,12 @@ int MachineObject::command_ams_air_print_detect(bool air_print_detect) int MachineObject::command_axis_control(std::string axis, double unit, double input_val, int speed) { - if (m_support_mqtt_axis_control) - { - int dir = input_val > 0 ? 1 : -1; - // i3-arch printers move the bed for Y/Z, so the on-screen direction is - // reversed — same negation the g-code fallback below applies. - if (!is_core_xy() && (axis.compare("Y") == 0 || axis.compare("Z") == 0)) { - dir = -dir; - } - - json j; - j["print"]["command"] = "xyz_ctrl"; - j["print"]["axis"] = axis; - j["print"]["dir"] = dir; - j["print"]["mode"] = (std::abs(input_val) >= 10) ? 1 : 0; - j["print"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++); - return this->publish_json(j); - } - - double value = input_val; - if (!is_core_xy()) { - if ( axis.compare("Y") == 0 - || axis.compare("Z") == 0) { - value = -1.0 * input_val; - } - } - - char cmd[256]; - if (axis.compare("X") == 0 - || axis.compare("Y") == 0 - || axis.compare("Z") == 0) { - sprintf(cmd, "M211 S \nM211 X1 Y1 Z1\nM1002 push_ref_mode\nG91 \nG1 %s%0.1f F%d\nM1002 pop_ref_mode\nM211 R\n", axis.c_str(), value * unit, speed); - } - else if (axis.compare("E") == 0) { - sprintf(cmd, "M83 \nG0 %s%0.1f F%d\n", axis.c_str(), value * unit, speed); - } - else { - return -1; - } - - - return this->publish_gcode(cmd); + if (!m_agent) return -1; + int rtn = m_agent->command_axis_control(get_dev_id(), axis, unit, input_val, speed, is_core_xy(), + m_support_mqtt_axis_control, MachineObject::m_sequence_id++, is_lan_mode_printer()); + if (rtn == ORCA_NETWORK_ERR_CMD_NOT_SUPPORTED || rtn == ORCA_NETWORK_ERR_CAP_NOT_AVAILABLE) + show_unsupported_dlg(rtn); + return rtn; } int MachineObject::command_extruder_control(int nozzle_id, double val) @@ -2659,7 +2625,7 @@ void MachineObject::update_print_progress(const json& value) int MachineObject::connect(bool use_openssl) { if (get_dev_ip().empty()) return -1; - std::string username = "bblp"; + std::string username = m_agent ? m_agent->default_lan_username() : std::string(); std::string password = get_access_code(); if (m_agent) { diff --git a/src/slic3r/GUI/DeviceManager.hpp b/src/slic3r/GUI/DeviceManager.hpp index 0408ddee41..6df11d10f5 100644 --- a/src/slic3r/GUI/DeviceManager.hpp +++ b/src/slic3r/GUI/DeviceManager.hpp @@ -18,6 +18,7 @@ #include "boost/bimap/bimap.hpp" #include "libslic3r/calib.hpp" #include "libslic3r/Utils.hpp" +#include "slic3r/Utils/PrinterNetworkTypes.hpp" #include "DeviceCore/DevDefs.h" #include "DeviceCore/DevConfigUtil.h" @@ -100,7 +101,6 @@ struct DevPrintTaskRatingInfo; // given nozzle diameter (mm), bucketed per nozzle size to mirror the printer firmware. bool is_stringing_prone_filament(const std::string& filament_id, float nozzle_diameter); - class MachineObject { private: @@ -549,29 +549,10 @@ public: std::string local_rtsp_url; std::string webcam_stream_url; std::string tutk_state; - enum LiveviewLocal { - LVL_None, - LVL_Disable, - LVL_Local, - LVL_Rtsps, - LVL_Rtsp - } liveview_local{ LVL_None }; - enum LiveviewRemote { - LVR_None, - LVR_Tutk, - LVR_Agora, - LVR_TutkAgora - } liveview_remote{ LVR_None }; - enum FileLocal { - FL_None, - FL_Local - } file_local{ FL_None }; - enum FileRemote { - FR_None, - FR_Tutk, - FR_Agora, - FR_TutkAgora - } file_remote{ FR_None }; + LiveviewLocal liveview_local{ LiveviewLocal::LVL_None }; + LiveviewRemote liveview_remote{ LiveviewRemote::LVR_None}; + FileLocal file_local{ FileLocal::FL_None }; + FileRemote file_remote{ FileRemote::FR_None }; enum PlateMakerDectect : int { diff --git a/src/slic3r/GUI/Jobs/PrintJob.cpp b/src/slic3r/GUI/Jobs/PrintJob.cpp index d79deb955b..1f7cfce708 100644 --- a/src/slic3r/GUI/Jobs/PrintJob.cpp +++ b/src/slic3r/GUI/Jobs/PrintJob.cpp @@ -14,6 +14,7 @@ #include "slic3r/Utils/FileTransferUtils.hpp" #include "slic3r/Utils/BBLNetworkPlugin.hpp" +#include "NetworkAgent.hpp" namespace Slic3r { namespace GUI { @@ -204,7 +205,7 @@ void PrintJob::process(Ctl &ctl) params.dev_ip = m_dev_ip; params.use_ssl_for_ftp = m_local_use_ssl_for_ftp; params.use_ssl_for_mqtt = m_local_use_ssl; - params.username = "bblp"; + params.username = m_agent->default_lan_username(); params.password = m_access_code; // check access code and ip address diff --git a/src/slic3r/GUI/Jobs/SendJob.cpp b/src/slic3r/GUI/Jobs/SendJob.cpp index bb52367188..c4790cf87d 100644 --- a/src/slic3r/GUI/Jobs/SendJob.cpp +++ b/src/slic3r/GUI/Jobs/SendJob.cpp @@ -124,7 +124,7 @@ void SendJob::process(Ctl &ctl) if (m_is_check_mode) { PrintParams verify_params; verify_params.dev_ip = m_dev_ip; - verify_params.username = "bblp"; + verify_params.username = agent->default_lan_username(); verify_params.password = m_access_code; verify_params.use_ssl_for_ftp = m_local_use_ssl_for_ftp; verify_params.use_ssl_for_mqtt = m_local_use_ssl; @@ -209,7 +209,7 @@ void SendJob::process(Ctl &ctl) // local print access params.dev_ip = m_dev_ip; - params.username = "bblp"; + params.username = agent->default_lan_username(); params.password = m_access_code; params.use_ssl_for_ftp = m_local_use_ssl_for_ftp; params.use_ssl_for_mqtt = m_local_use_ssl; diff --git a/src/slic3r/GUI/MediaPlayCtrl.cpp b/src/slic3r/GUI/MediaPlayCtrl.cpp index 90e956be69..0b4b4b9e79 100644 --- a/src/slic3r/GUI/MediaPlayCtrl.cpp +++ b/src/slic3r/GUI/MediaPlayCtrl.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #undef pid_t #include #ifdef __WIN32__ @@ -160,12 +161,12 @@ void MediaPlayCtrl::SetMachineObject(MachineObject* obj) if (DevPrinterConfigUtil::get_printer_series_str(obj->printer_type) == "series_o" && BBLNetworkPlugin::instance().use_legacy_network()) { // Legacy plugin cannot support remote play for H2D, force using local mode - m_remote_proto = MachineObject::LVR_None; + m_remote_proto = LiveviewRemote::LVR_None; } } else { m_camera_exists = false; m_lan_mode = false; - m_lan_proto = MachineObject::LVL_None; + m_lan_proto = LiveviewLocal::LVL_None; m_lan_ip.clear(); m_lan_passwd.clear(); m_dev_ver.clear(); @@ -283,14 +284,14 @@ void MediaPlayCtrl::Play() BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl::Play: " << m_lan_proto << m_remote_proto << m_disable_lan; NetworkAgent *agent = wxGetApp().getAgent(); std::string agent_version = agent ? agent->get_version() : ""; - if (m_lan_proto > MachineObject::LVL_Disable && (m_lan_mode || !m_remote_proto) && !m_disable_lan && !m_lan_ip.empty()) { + if (m_lan_proto > LiveviewLocal::LVL_Disable && (m_lan_mode || !m_remote_proto) && !m_disable_lan && !m_lan_ip.empty()) { m_disable_lan = m_remote_proto && !m_lan_mode; // try remote next time std::string url; - if (m_lan_proto == MachineObject::LVL_Local) + if (m_lan_proto == LiveviewLocal::LVL_Local) url = "bambu:///local/" + m_lan_ip + ".?port=6000&user=" + m_lan_user + "&passwd=" + m_lan_passwd; - else if (m_lan_proto == MachineObject::LVL_Rtsps) + else if (m_lan_proto == LiveviewLocal::LVL_Rtsps) url = "bambu:///rtsps___" + m_lan_user + ":" + m_lan_passwd + "@" + m_lan_ip + "/streaming/live/1?proto=rtsps"; - else if (m_lan_proto == MachineObject::LVL_Rtsp) + else if (m_lan_proto == LiveviewLocal::LVL_Rtsp) url = "bambu:///rtsp___" + m_lan_user + ":" + m_lan_passwd + "@" + m_lan_ip + "/streaming/live/1?proto=rtsp"; url += "&device=" + m_machine; url += "&net_ver=" + agent_version; @@ -312,8 +313,8 @@ void MediaPlayCtrl::Play() // !m_lan_mode && !m_remote_proto && m_lan_proto == LVL_Disable (*) // !m_lan_mode && !m_remote_proto && m_lan_proto == LVL_None (x) - if (m_lan_proto <= MachineObject::LVL_Disable && (m_lan_mode || !m_remote_proto)) { - Stop(m_lan_proto == MachineObject::LVL_None + if (m_lan_proto <= LiveviewLocal::LVL_Disable && (m_lan_mode || !m_remote_proto)) { + Stop(m_lan_proto == LiveviewLocal::LVL_None ? _L("A problem occurred. Please update the printer firmware and try again.") : _L("LAN Only Liveview is off. Please turn on the liveview on printer screen.")); return; @@ -528,13 +529,13 @@ void MediaPlayCtrl::ToggleStream() wxGetApp().app_config->set("not_show_vcamera_stop_prev", "1"); if (res == wxID_CANCEL) return; } - if (m_lan_proto > MachineObject::LVL_Disable && (m_lan_mode || !m_remote_proto) && !m_disable_lan && !m_lan_ip.empty()) { + if (m_lan_proto > LiveviewLocal::LVL_Disable && (m_lan_mode || !m_remote_proto) && !m_disable_lan && !m_lan_ip.empty()) { std::string url; - if (m_lan_proto == MachineObject::LVL_Local) + if (m_lan_proto == LiveviewLocal::LVL_Local) url = "bambu:///local/" + m_lan_ip + ".?port=6000&user=" + m_lan_user + "&passwd=" + m_lan_passwd; - else if (m_lan_proto == MachineObject::LVL_Rtsps) + else if (m_lan_proto == LiveviewLocal::LVL_Rtsps) url = "bambu:///rtsps___" + m_lan_user + ":" + m_lan_passwd + "@" + m_lan_ip + "/streaming/live/1?proto=rtsps"; - else if (m_lan_proto == MachineObject::LVL_Rtsp) + else if (m_lan_proto == LiveviewLocal::LVL_Rtsp) url = "bambu:///rtsp___" + m_lan_user + ":" + m_lan_passwd + "@" + m_lan_ip + "/streaming/live/1?proto=rtsp"; url += "&device=" + into_u8(m_machine); url += "&dev_ver=" + m_dev_ver; diff --git a/src/slic3r/GUI/PartSkipDialog.hpp b/src/slic3r/GUI/PartSkipDialog.hpp index 95eba9f24d..2cc622dae0 100644 --- a/src/slic3r/GUI/PartSkipDialog.hpp +++ b/src/slic3r/GUI/PartSkipDialog.hpp @@ -160,4 +160,4 @@ private: void OnApplyDialog(wxCommandEvent &event); }; -}} // namespace Slic3r::GUI \ No newline at end of file +}} // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/ReleaseNote.cpp b/src/slic3r/GUI/ReleaseNote.cpp index 068896389a..6c9adb015b 100644 --- a/src/slic3r/GUI/ReleaseNote.cpp +++ b/src/slic3r/GUI/ReleaseNote.cpp @@ -2061,6 +2061,11 @@ void InputIpAddressDialog::on_text(wxCommandEvent &evt) auto str_ip = m_input_ip->GetTextCtrl()->GetValue(); auto str_access_code = m_input_access_code->GetTextCtrl()->GetValue(); + if (str_access_code.IsEmpty()) { + str_access_code = "88888888"; + m_input_access_code->GetTextCtrl()->SetValue(str_access_code); + } + auto str_name = m_input_printer_name->GetTextCtrl()->GetValue().Strip(wxString::both); auto str_sn = m_input_sn->GetTextCtrl()->GetValue().Strip(wxString::both); bool invalid_access_code = true; diff --git a/src/slic3r/Utils/BBLPrinterAgent.cpp b/src/slic3r/Utils/BBLPrinterAgent.cpp index 9d422552fe..138cc9463c 100644 --- a/src/slic3r/Utils/BBLPrinterAgent.cpp +++ b/src/slic3r/Utils/BBLPrinterAgent.cpp @@ -1,10 +1,15 @@ #include "BBLPrinterAgent.hpp" #include "BBLNetworkPlugin.hpp" +#include "IPrinterAgent.hpp" #include "NetworkAgentFactory.hpp" +#include "NetworkAgent.hpp" #include #include +#include #include +#include +#include namespace Slic3r { @@ -14,7 +19,7 @@ BBLPrinterAgent::~BBLPrinterAgent() = default; void BBLPrinterAgent::set_cloud_agent(std::shared_ptr cloud) { - m_cloud_agent = cloud; + (void) cloud; // BBL DLL manages tokens internally, so this is just for interface compliance } @@ -70,6 +75,104 @@ int BBLPrinterAgent::command_ams_select_tray(std::string dev_id, std::string tra return publish(dev_id, j, lan_mode); } +int BBLPrinterAgent::command_xyz_abs(std::string dev_id, int sequence_id, bool lan_mode) +{ + nlohmann::json j; + j["print"]["command"] = "gcode_line"; + j["print"]["param"] = "G90 \n"; + j["print"]["sequence_id"] = std::to_string(sequence_id); + return publish(dev_id, j, lan_mode); +} + +int BBLPrinterAgent::command_auto_leveling(std::string dev_id, int sequence_id, bool lan_mode) +{ + nlohmann::json j; + j["print"]["command"] = "gcode_line"; + j["print"]["param"] = "G29 \n"; + j["print"]["sequence_id"] = std::to_string(sequence_id); + return publish(dev_id, j, lan_mode); +} + +int BBLPrinterAgent::command_go_home(std::string dev_id, bool is_printing, bool supports_mqtt_homing, int sequence_id, bool lan_mode) +{ + nlohmann::json j; + j["print"]["sequence_id"] = std::to_string(sequence_id); + if (supports_mqtt_homing) { + j["print"]["command"] = "back_to_center"; + return publish(dev_id, j, lan_mode); + } + + j["print"]["command"] = "gcode_line"; + j["print"]["param"] = is_printing ? "G28 X\n" : "G28 \n"; + return publish(dev_id, j, lan_mode); +} + +int BBLPrinterAgent::command_set_bed(std::string dev_id, int temp, bool supports_mqtt_bed_ctrl, int sequence_id, bool lan_mode) +{ + nlohmann::json j; + j["print"]["sequence_id"] = std::to_string(sequence_id); + if (supports_mqtt_bed_ctrl) { + j["print"]["command"] = "set_bed_temp"; + j["print"]["temp"] = temp; + return publish(dev_id, j, lan_mode); + } + + j["print"]["command"] = "gcode_line"; + j["print"]["param"] = (boost::format("M140 S%1%\n") % temp).str(); + return publish(dev_id, j, lan_mode); +} + +int BBLPrinterAgent::command_set_nozzle(std::string dev_id, int temp, int sequence_id, bool lan_mode) +{ + nlohmann::json j; + j["print"]["command"] = "gcode_line"; + j["print"]["param"] = (boost::format("M104 S%1%\n") % temp).str(); + j["print"]["sequence_id"] = std::to_string(sequence_id); + return publish(dev_id, j, lan_mode); +} + +int BBLPrinterAgent::command_axis_control(std::string dev_id, std::string axis, double unit, double input_val, int speed, + bool is_core_xy, bool supports_mqtt_axis_control, int sequence_id, bool lan_mode) +{ + nlohmann::json j; + j["print"]["sequence_id"] = std::to_string(sequence_id); + + if (supports_mqtt_axis_control) { + int dir = input_val > 0 ? 1 : -1; + // i3-arch printers move the bed for Y/Z, so the on-screen direction is + // reversed -- same negation the g-code fallback below applies. + if (!is_core_xy && (axis == "Y" || axis == "Z")) { + dir = -dir; + } + + j["print"]["command"] = "xyz_ctrl"; + j["print"]["axis"] = axis; + j["print"]["dir"] = dir; + j["print"]["mode"] = (std::abs(input_val) >= 10) ? 1 : 0; + return publish(dev_id, j, lan_mode); + } + + double value = input_val; + if (!is_core_xy && (axis == "Y" || axis == "Z")) { + value = -1.0 * input_val; + } + + std::string value_str = (boost::format("%.1f") % (value * unit)).str(); + std::string gcode; + if (axis == "X" || axis == "Y" || axis == "Z") { + gcode = (boost::format("M211 S \nM211 X1 Y1 Z1\nM1002 push_ref_mode\nG91 \nG1 %1%%2% F%3%\nM1002 pop_ref_mode\nM211 R\n") + % axis % value_str % speed).str(); + } else if (axis == "E") { + gcode = (boost::format("M83 \nG0 %1%%2% F%3%\n") % axis % value_str % speed).str(); + } else { + return -1; + } + + j["print"]["command"] = "gcode_line"; + j["print"]["param"] = gcode; + return publish(dev_id, j, lan_mode); +} + int BBLPrinterAgent::publish(const std::string& dev_id, const nlohmann::json& j, bool lan_mode) { const int rtn = lan_mode ? send_message_to_printer(dev_id, j.dump(), 0, 0) : send_message(dev_id, j.dump(), 0, 0); @@ -410,8 +513,15 @@ int BBLPrinterAgent::start_local_print_with_record(PrintParams params, OnUpdateS int BBLPrinterAgent::start_send_gcode_to_sdcard(PrintParams params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn, OnWaitFn wait_fn) { - return dispatch_start( + int result = dispatch_start( BBLNetworkPlugin::instance().get_start_send_gcode_to_sdcard(), params, update_fn, cancel_fn, wait_fn); + if (result != 0) { + BOOST_LOG_TRIVIAL(error) << "start_send_gcode_to_sdcard failed: result=" << result + << ", try_emmc_print=" << params.try_emmc_print + << ", legacy_mode=" << BBLNetworkPlugin::instance().use_legacy_network() + << ", dev_ip=" << params.dev_ip << ", dev_id=" << params.dev_id; + } + return result; } int BBLPrinterAgent::start_local_print(PrintParams params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn) diff --git a/src/slic3r/Utils/BBLPrinterAgent.hpp b/src/slic3r/Utils/BBLPrinterAgent.hpp index a04cd00175..d1a36eddb8 100644 --- a/src/slic3r/Utils/BBLPrinterAgent.hpp +++ b/src/slic3r/Utils/BBLPrinterAgent.hpp @@ -35,9 +35,17 @@ public: int command_ams_refresh_rfid(std::string dev_id, std::string tray_id, int sequence_id, bool lan_mode) override; int command_ams_calibrate(std::string dev_id, int ams_id, int sequence_id, bool lan_mode) override; int command_ams_select_tray(std::string dev_id, std::string tray_id, int sequence_id, bool lan_mode) override; + int command_xyz_abs(std::string dev_id, int sequence_id, bool lan_mode) override; + int command_auto_leveling(std::string dev_id, int sequence_id, bool lan_mode) override; + int command_go_home(std::string dev_id, bool is_printing, bool supports_mqtt_homing, int sequence_id, bool lan_mode) override; + int command_set_bed(std::string dev_id, int temp, bool supports_mqtt_bed_ctrl, int sequence_id, bool lan_mode) override; + int command_set_nozzle(std::string dev_id, int temp, int sequence_id, bool lan_mode) override; + int command_axis_control(std::string dev_id, std::string axis, double unit, double input_val, int speed, + bool is_core_xy, bool supports_mqtt_axis_control, int sequence_id, bool lan_mode) override; int connect_printer(std::string dev_id, std::string dev_ip, std::string username, std::string password, bool use_ssl) override; int disconnect_printer() override; int send_message_to_printer(std::string dev_id, std::string json_str, int qos, int flag) override; + std::string default_lan_username() const override { return "bblp"; } // Certificates int check_cert() override; @@ -94,8 +102,6 @@ public: private: // why: the lan/cloud DECISION stays machine-side; keep this mechanical branch in sync with publish_json. int publish(const std::string& dev_id, const nlohmann::json& j, bool lan_mode); - - std::shared_ptr m_cloud_agent; }; } // namespace Slic3r diff --git a/src/slic3r/Utils/FileTransferUtils.cpp b/src/slic3r/Utils/FileTransferUtils.cpp index ebca741af5..822ccdf09d 100644 --- a/src/slic3r/Utils/FileTransferUtils.cpp +++ b/src/slic3r/Utils/FileTransferUtils.cpp @@ -224,4 +224,4 @@ void FileTransferJob::solve_result(ft_job_result result) res_json_.assign(result.json ? result.json : ""); } -} // namespace Slic3r \ No newline at end of file +} // namespace Slic3r diff --git a/src/slic3r/Utils/FileTransferUtils.hpp b/src/slic3r/Utils/FileTransferUtils.hpp index 037a1bef0c..ba91621a91 100644 --- a/src/slic3r/Utils/FileTransferUtils.hpp +++ b/src/slic3r/Utils/FileTransferUtils.hpp @@ -252,4 +252,4 @@ inline FileTransferModule &module() return *detail::g_mod; } -} // namespace Slic3r \ No newline at end of file +} // namespace Slic3r diff --git a/src/slic3r/Utils/IPrinterAgent.hpp b/src/slic3r/Utils/IPrinterAgent.hpp index 269c2a337b..b77a27276f 100644 --- a/src/slic3r/Utils/IPrinterAgent.hpp +++ b/src/slic3r/Utils/IPrinterAgent.hpp @@ -11,6 +11,9 @@ #define ORCA_NETWORK_ERR_CAP_NOT_AVAILABLE -7020 // a translation exists; this printer lacks the capability #include #include +#include +#include +#include #if 1 @@ -131,6 +134,26 @@ public: virtual int command_start_camera(std::string) { return ORCA_NETWORK_ERR_CMD_NOT_SUPPORTED; } + virtual int command_xyz_abs(std::string dev_id, int sequence_id, bool lan_mode) + { return ORCA_NETWORK_ERR_CMD_NOT_SUPPORTED; } + virtual int command_auto_leveling(std::string dev_id, int sequence_id, bool lan_mode) + { return ORCA_NETWORK_ERR_CMD_NOT_SUPPORTED; } + virtual int command_go_home(std::string dev_id, bool is_printing, bool supports_mqtt_homing, int sequence_id, bool lan_mode) + { return ORCA_NETWORK_ERR_CMD_NOT_SUPPORTED; } + virtual int command_set_bed(std::string dev_id, int temp, bool supports_mqtt_bed_ctrl, int sequence_id, bool lan_mode) + { return ORCA_NETWORK_ERR_CMD_NOT_SUPPORTED; } + virtual int command_set_nozzle(std::string dev_id, int temp, int sequence_id, bool lan_mode) + { return ORCA_NETWORK_ERR_CMD_NOT_SUPPORTED; } + virtual int command_axis_control(std::string dev_id, std::string axis, double unit, double input_val, int speed, + bool is_core_xy, bool supports_mqtt_axis_control, int sequence_id, bool lan_mode) + { return ORCA_NETWORK_ERR_CMD_NOT_SUPPORTED; } + + /** + * Default LAN account username for this agent's protocol, if it has a fixed one. + * Returns an empty string if the agent has no fixed default (e.g. caller must supply one). + */ + virtual std::string default_lan_username() const { return {}; } + /** * Establish a direct LAN connection to a printer. */ diff --git a/src/slic3r/Utils/NetworkAgent.cpp b/src/slic3r/Utils/NetworkAgent.cpp index 4687b77772..776a759a00 100644 --- a/src/slic3r/Utils/NetworkAgent.cpp +++ b/src/slic3r/Utils/NetworkAgent.cpp @@ -4,6 +4,7 @@ #include #include +#include "IPrinterAgent.hpp" #include "libslic3r/Utils.hpp" #include "NetworkAgent.hpp" #include "BBLNetworkPlugin.hpp" @@ -795,6 +796,49 @@ int NetworkAgent::command_start_camera(std::string dev_id) return -1; } +int NetworkAgent::command_xyz_abs(std::string dev_id, int sequence_id, bool lan_mode) +{ + if (m_printer_agent) + return m_printer_agent->command_xyz_abs(dev_id, sequence_id, lan_mode); + return -1; +} + +int NetworkAgent::command_auto_leveling(std::string dev_id, int sequence_id, bool lan_mode) +{ + if (m_printer_agent) + return m_printer_agent->command_auto_leveling(dev_id, sequence_id, lan_mode); + return -1; +} + +int NetworkAgent::command_go_home(std::string dev_id, bool is_printing, bool supports_mqtt_homing, int sequence_id, bool lan_mode) +{ + if (m_printer_agent) + return m_printer_agent->command_go_home(dev_id, is_printing, supports_mqtt_homing, sequence_id, lan_mode); + return -1; +} + +int NetworkAgent::command_set_bed(std::string dev_id, int temp, bool supports_mqtt_bed_ctrl, int sequence_id, bool lan_mode) +{ + if (m_printer_agent) + return m_printer_agent->command_set_bed(dev_id, temp, supports_mqtt_bed_ctrl, sequence_id, lan_mode); + return -1; +} + +int NetworkAgent::command_set_nozzle(std::string dev_id, int temp, int sequence_id, bool lan_mode) +{ + if (m_printer_agent) + return m_printer_agent->command_set_nozzle(dev_id, temp, sequence_id, lan_mode); + return -1; +} + +int NetworkAgent::command_axis_control(std::string dev_id, std::string axis, double unit, double input_val, int speed, + bool is_core_xy, bool supports_mqtt_axis_control, int sequence_id, bool lan_mode) +{ + if (m_printer_agent) + return m_printer_agent->command_axis_control(dev_id, axis, unit, input_val, speed, is_core_xy, supports_mqtt_axis_control, sequence_id, lan_mode); + return -1; +} + int NetworkAgent::connect_printer(std::string dev_id, std::string dev_ip, std::string username, std::string password, bool use_ssl) { if (m_printer_agent) @@ -816,6 +860,13 @@ int NetworkAgent::send_message_to_printer(std::string dev_id, std::string json_s return -1; } +std::string NetworkAgent::default_lan_username() const +{ + if (m_printer_agent) + return m_printer_agent->default_lan_username(); + return {}; +} + int NetworkAgent::check_cert() { if (m_printer_agent) diff --git a/src/slic3r/Utils/NetworkAgent.hpp b/src/slic3r/Utils/NetworkAgent.hpp index 48ae7268f1..e9d05143a1 100644 --- a/src/slic3r/Utils/NetworkAgent.hpp +++ b/src/slic3r/Utils/NetworkAgent.hpp @@ -2,9 +2,10 @@ #define __NETWORK_Agent_HPP__ #include "bambu_networking.hpp" + #include "libslic3r/ProjectTask.hpp" #include "ICloudServiceAgent.hpp" -#include "IPrinterAgent.hpp" + #include #include #include @@ -12,6 +13,9 @@ namespace Slic3r { +class IPrinterAgent; +enum class FilamentSyncMode; + // Forward declaration class BBLNetworkPlugin; @@ -146,9 +150,17 @@ public: int command_ams_calibrate(std::string dev_id, int ams_id, int sequence_id, bool lan_mode); int command_ams_select_tray(std::string dev_id, std::string tray_id, int sequence_id, bool lan_mode); int command_start_camera(std::string dev_id); + int command_xyz_abs(std::string dev_id, int sequence_id, bool lan_mode); + int command_auto_leveling(std::string dev_id, int sequence_id, bool lan_mode); + int command_go_home(std::string dev_id, bool is_printing, bool supports_mqtt_homing, int sequence_id, bool lan_mode); + int command_set_bed(std::string dev_id, int temp, bool supports_mqtt_bed_ctrl, int sequence_id, bool lan_mode); + int command_set_nozzle(std::string dev_id, int temp, int sequence_id, bool lan_mode); + int command_axis_control(std::string dev_id, std::string axis, double unit, double input_val, int speed, + bool is_core_xy, bool supports_mqtt_axis_control, int sequence_id, bool lan_mode); int connect_printer(std::string dev_id, std::string dev_ip, std::string username, std::string password, bool use_ssl); int disconnect_printer(); int send_message_to_printer(std::string dev_id, std::string json_str, int qos, int flag); + std::string default_lan_username() const; int check_cert(); void install_device_cert(std::string dev_id, bool lan_only); bool start_discovery(bool start, bool sending); diff --git a/src/slic3r/Utils/PrinterNetworkTypes.hpp b/src/slic3r/Utils/PrinterNetworkTypes.hpp new file mode 100644 index 0000000000..d87be6cdcb --- /dev/null +++ b/src/slic3r/Utils/PrinterNetworkTypes.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include + +namespace Slic3r { + +enum LiveviewLocal { + LVL_None, + LVL_Disable, + LVL_Local, + LVL_Rtsps, + LVL_Rtsp +}; + +enum LiveviewRemote { + LVR_None, + LVR_Tutk, + LVR_Agora, + LVR_TutkAgora +}; + +enum FileLocal { + FL_None, + FL_Local +}; + +enum FileRemote { + FR_None, + FR_Tutk, + FR_Agora, + FR_TutkAgora +}; + +} // namespace Slic3r diff --git a/src/slic3r/plugin/PluginFsUtils.cpp b/src/slic3r/plugin/PluginFsUtils.cpp index 8f93f7aaef..4d3758508e 100644 --- a/src/slic3r/plugin/PluginFsUtils.cpp +++ b/src/slic3r/plugin/PluginFsUtils.cpp @@ -631,7 +631,7 @@ void parse_metadata_rfc822(const std::string& content, bool is_ignored_plugin_directory(const boost::filesystem::path& path) { const std::string name = path.filename().string(); - return name.empty() || name[0] == '.' || name.rfind("__", 0) == 0 || name == PLUGIN_SUBSCRIBED_DIR; + return name.empty() || name[0] == '.' || name.rfind("__", 0) == 0 || name == PLUGIN_SUBSCRIBED_DIR || name == PLUGIN_DATA_DIR; } bool is_safe_relative_path(const boost::filesystem::path& path) diff --git a/src/slic3r/plugin/PluginFsUtils.hpp b/src/slic3r/plugin/PluginFsUtils.hpp index 7922946b1c..5f57dbf807 100644 --- a/src/slic3r/plugin/PluginFsUtils.hpp +++ b/src/slic3r/plugin/PluginFsUtils.hpp @@ -12,6 +12,7 @@ #include #define PLUGIN_SUBSCRIBED_DIR "_subscribed" +#define PLUGIN_DATA_DIR "plugin_data" namespace Slic3r { diff --git a/src/slic3r/plugin/PluginManager.cpp b/src/slic3r/plugin/PluginManager.cpp index 3587c0a824..2bae29611f 100644 --- a/src/slic3r/plugin/PluginManager.cpp +++ b/src/slic3r/plugin/PluginManager.cpp @@ -522,6 +522,38 @@ bool PluginManager::try_get_plugin_descriptor_for_capability(const std::string& return false; } +std::string PluginManager::get_storage_dir(const std::string& plugin_key) const +{ + namespace fs = boost::filesystem; + + PluginDescriptor descriptor; + if (!try_get_plugin_descriptor(plugin_key, descriptor)) + throw std::runtime_error("The current plugin is not registered"); + + const fs::path base_storage_dir = fs::path(get_orca_plugins_dir()) / PLUGIN_DATA_DIR; + + if (!descriptor.is_cloud_plugin()) { + const fs::path local_storage_dir = base_storage_dir / plugin_key; + fs::create_directories(local_storage_dir); + return local_storage_dir.string(); + } + + auto agent = m_cloud_service.get_cloud_agent(); + if (!agent) + throw std::runtime_error("Cloud plugin storage is unavailable before networking is initialized"); + + const std::string user_id = agent->get_user_id(); + if (user_id.empty()) + throw std::runtime_error("Cloud plugin storage is unavailable without a logged-in user"); + + if (!is_valid_plugin_id(plugin_key)) + throw std::runtime_error("The current cloud plugin key is not a valid folder name"); + + const fs::path cloud_storage_dir = base_storage_dir / PLUGIN_SUBSCRIBED_DIR / user_id / plugin_key; + fs::create_directories(cloud_storage_dir); + return cloud_storage_dir.string(); +} + // ── Capability instances ──────────────────────────────────────────────────────────────────── std::vector> PluginManager::get_plugin_capabilities(const std::string& plugin_key, diff --git a/src/slic3r/plugin/PluginManager.hpp b/src/slic3r/plugin/PluginManager.hpp index ddb0bf9dce..b5044d6dba 100644 --- a/src/slic3r/plugin/PluginManager.hpp +++ b/src/slic3r/plugin/PluginManager.hpp @@ -143,6 +143,10 @@ public: bool try_get_plugin_descriptor_for_capability(const std::string& capability_name, PluginCapabilityType type, PluginDescriptor& out) const; + // Per-plugin storage directory under orca_plugins/plugin_data, created if missing. Throws + // std::runtime_error if the plugin is unregistered, the key is invalid, or (cloud plugins) + // no user is logged in yet. + std::string get_storage_dir(const std::string& plugin_key) const; std::vector> get_plugin_capabilities( const std::string& plugin_key = "", // "" => all plugins diff --git a/src/slic3r/plugin/host/PluginHost.cpp b/src/slic3r/plugin/host/PluginHost.cpp index 524f07f12c..2830d6f276 100644 --- a/src/slic3r/plugin/host/PluginHost.cpp +++ b/src/slic3r/plugin/host/PluginHost.cpp @@ -1,9 +1,31 @@ #include "PluginHost.hpp" #include "PluginHostBindings.hpp" #include "PluginHostUi.hpp" +#include +#include + +#include namespace Slic3r { +namespace host_bindings { +void register_plugin(pybind11::module_& host) +{ + auto plugin_host = host.def_submodule("plugin", "Plugin host API"); + + plugin_host.def( + "storage", + []() -> std::string { + const std::string plugin_key = PluginAuditManager::instance().current_plugin(); + if (plugin_key.empty()) + throw std::runtime_error("plugin.storage() must be called from a plugin callback"); + + return PluginManager::instance().get_storage_dir(plugin_key); + }, + "Return the installed folder of the current plugin."); +} +} // namespace host_bindings + void PluginHost::RegisterBindings(pybind11::module_& module) { auto host = module.def_submodule("host", "Host application API"); @@ -15,6 +37,7 @@ void PluginHost::RegisterBindings(pybind11::module_& module) host_bindings::register_presets(host); host_bindings::register_model(host); host_bindings::register_app(host); + host_bindings::register_plugin(host); // UI: native dialogs and interactive HTML windows for plugins. PluginHostUi::RegisterBindings(host); diff --git a/src/slic3r/plugin/host/PluginHostBindings.hpp b/src/slic3r/plugin/host/PluginHostBindings.hpp index 0f206d5992..94601ad99c 100644 --- a/src/slic3r/plugin/host/PluginHostBindings.hpp +++ b/src/slic3r/plugin/host/PluginHostBindings.hpp @@ -12,5 +12,5 @@ void register_presets(pybind11::module_& host); // PluginHostPresets.cpp void register_model(pybind11::module_& host); // PluginHostModel.cpp void register_app(pybind11::module_& host); // PluginHostApp.cpp void register_slicing(pybind11::module_& host); // PluginHostSlicing.cpp - +void register_plugin(pybind11::module_& host); // PluginHost.cpp } // namespace Slic3r::host_bindings