mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-08-29 21:07:11 +00:00
Move Moonraker commands off the UI thread
Pause/resume/stop, g-code sends, temps, and light ran synchronous HTTP on the UI thread, freezing the app up to 10s per click on slow or unreachable printers. Run them on a single agent-owned FIFO worker so g-code ordering is preserved, while command translation stays synchronous so unsupported- command dialogs still work. Add a pending-disabled state to the pause, resume, and abort buttons for Moonraker-family printers: the icon only flips once the WebSocket reports the real state, which also rules out double-click races.
This commit is contained in:
@@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
#include "MsgDialog.hpp"
|
#include "MsgDialog.hpp"
|
||||||
#include "slic3r/Utils/Http.hpp"
|
#include "slic3r/Utils/Http.hpp"
|
||||||
|
#include "slic3r/Utils/MoonrakerPrinterAgent.hpp"
|
||||||
#include "libslic3r/Thread.hpp"
|
#include "libslic3r/Thread.hpp"
|
||||||
#include "DeviceErrorDialog.hpp"
|
#include "DeviceErrorDialog.hpp"
|
||||||
|
|
||||||
@@ -2714,7 +2715,8 @@ void StatusPanel::on_subtask_partskip(wxCommandEvent &event)
|
|||||||
void StatusPanel::on_subtask_pause_resume(wxCommandEvent &event)
|
void StatusPanel::on_subtask_pause_resume(wxCommandEvent &event)
|
||||||
{
|
{
|
||||||
if (obj) {
|
if (obj) {
|
||||||
if (obj->can_resume()) {
|
const bool was_resume = obj->can_resume();
|
||||||
|
if (was_resume) {
|
||||||
BOOST_LOG_TRIVIAL(info) << "monitor: resume current print task dev_id =" << obj->get_dev_id();
|
BOOST_LOG_TRIVIAL(info) << "monitor: resume current print task dev_id =" << obj->get_dev_id();
|
||||||
obj->command_task_resume();
|
obj->command_task_resume();
|
||||||
}
|
}
|
||||||
@@ -2722,6 +2724,13 @@ void StatusPanel::on_subtask_pause_resume(wxCommandEvent &event)
|
|||||||
BOOST_LOG_TRIVIAL(info) << "monitor: pause current print task dev_id =" << obj->get_dev_id();
|
BOOST_LOG_TRIVIAL(info) << "monitor: pause current print task dev_id =" << obj->get_dev_id();
|
||||||
obj->command_task_pause();
|
obj->command_task_pause();
|
||||||
}
|
}
|
||||||
|
if (is_moonraker_agent()) {
|
||||||
|
m_pause_resume_pending = true;
|
||||||
|
m_pause_resume_was_resume = was_resume;
|
||||||
|
m_pause_resume_deadline = std::chrono::steady_clock::now() + std::chrono::seconds(6);
|
||||||
|
m_pause_resume_machine_id = obj->get_dev_id();
|
||||||
|
m_project_task_panel->enable_pause_resume_button(false, was_resume ? "resume_disable" : "pause_disable");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2733,6 +2742,12 @@ void StatusPanel::on_subtask_abort(wxCommandEvent &event)
|
|||||||
if (obj) {
|
if (obj) {
|
||||||
BOOST_LOG_TRIVIAL(info) << "monitor: stop current print task dev_id =" << obj->get_dev_id();
|
BOOST_LOG_TRIVIAL(info) << "monitor: stop current print task dev_id =" << obj->get_dev_id();
|
||||||
obj->command_task_abort();
|
obj->command_task_abort();
|
||||||
|
if (is_moonraker_agent()) {
|
||||||
|
m_abort_pending = true;
|
||||||
|
m_abort_deadline = std::chrono::steady_clock::now() + std::chrono::seconds(6);
|
||||||
|
m_abort_machine_id = obj->get_dev_id();
|
||||||
|
m_project_task_panel->enable_abort_button(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -3706,6 +3721,25 @@ void StatusPanel::update_model_info()
|
|||||||
void StatusPanel::update_subtask(MachineObject *obj)
|
void StatusPanel::update_subtask(MachineObject *obj)
|
||||||
{
|
{
|
||||||
if (!obj) return;
|
if (!obj) return;
|
||||||
|
const auto now = std::chrono::steady_clock::now();
|
||||||
|
if (m_pause_resume_pending) {
|
||||||
|
if (!is_moonraker_agent() || m_pause_resume_machine_id != obj->get_dev_id() ||
|
||||||
|
obj->can_resume() != m_pause_resume_was_resume) {
|
||||||
|
m_pause_resume_pending = false;
|
||||||
|
} else if (now >= m_pause_resume_deadline) {
|
||||||
|
BOOST_LOG_TRIVIAL(warning) << "StatusPanel: Moonraker pause/resume command did not change printer state";
|
||||||
|
m_pause_resume_pending = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (m_abort_pending) {
|
||||||
|
if (!is_moonraker_agent() || m_abort_machine_id != obj->get_dev_id() || obj->print_status == "FAILED" ||
|
||||||
|
obj->print_status == "FINISH" || obj->print_status == "IDLE") {
|
||||||
|
m_abort_pending = false;
|
||||||
|
} else if (now >= m_abort_deadline) {
|
||||||
|
BOOST_LOG_TRIVIAL(warning) << "StatusPanel: Moonraker abort command did not change printer state";
|
||||||
|
m_abort_pending = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (m_current_print_mode != PRINGINT) {
|
if (m_current_print_mode != PRINGINT) {
|
||||||
if (calib_bitmap == nullptr) {
|
if (calib_bitmap == nullptr) {
|
||||||
m_calib_mode = get_obj_calibration_mode(obj, m_calib_method, cali_stage);
|
m_calib_mode = get_obj_calibration_mode(obj, m_calib_method, cali_stage);
|
||||||
@@ -3813,10 +3847,12 @@ void StatusPanel::update_subtask(MachineObject *obj)
|
|||||||
}
|
}
|
||||||
update_basic_print_data(false);
|
update_basic_print_data(false);
|
||||||
} else {
|
} else {
|
||||||
if (obj->can_resume()) {
|
if (!m_pause_resume_pending) {
|
||||||
m_project_task_panel->enable_pause_resume_button(true, "resume");
|
if (obj->can_resume()) {
|
||||||
} else {
|
m_project_task_panel->enable_pause_resume_button(true, "resume");
|
||||||
m_project_task_panel->enable_pause_resume_button(true, "pause");
|
} else {
|
||||||
|
m_project_task_panel->enable_pause_resume_button(true, "pause");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
m_project_task_panel->enable_partskip_button(obj, true);
|
m_project_task_panel->enable_partskip_button(obj, true);
|
||||||
// update printing stage
|
// update printing stage
|
||||||
@@ -3873,7 +3909,9 @@ void StatusPanel::update_subtask(MachineObject *obj)
|
|||||||
m_project_task_panel->market_scoring_hide();
|
m_project_task_panel->market_scoring_hide();
|
||||||
}
|
}
|
||||||
} else { // model printing is not finished, hide scoring page
|
} else { // model printing is not finished, hide scoring page
|
||||||
m_project_task_panel->enable_abort_button(true);
|
if (!m_abort_pending) {
|
||||||
|
m_project_task_panel->enable_abort_button(true);
|
||||||
|
}
|
||||||
m_project_task_panel->market_scoring_hide();
|
m_project_task_panel->market_scoring_hide();
|
||||||
m_project_task_panel->get_request_failed_panel()->Hide();
|
m_project_task_panel->get_request_failed_panel()->Hide();
|
||||||
}
|
}
|
||||||
@@ -4016,6 +4054,8 @@ void StatusPanel::update_sdcard_subtask(MachineObject *obj)
|
|||||||
|
|
||||||
void StatusPanel::reset_printing_values()
|
void StatusPanel::reset_printing_values()
|
||||||
{
|
{
|
||||||
|
m_pause_resume_pending = false;
|
||||||
|
m_abort_pending = false;
|
||||||
m_project_task_panel->enable_partskip_button(nullptr, false);
|
m_project_task_panel->enable_partskip_button(nullptr, false);
|
||||||
m_project_task_panel->enable_pause_resume_button(false, "pause_disable");
|
m_project_task_panel->enable_pause_resume_button(false, "pause_disable");
|
||||||
m_project_task_panel->enable_abort_button(false);
|
m_project_task_panel->enable_abort_button(false);
|
||||||
@@ -4041,6 +4081,12 @@ void StatusPanel::reset_printing_values()
|
|||||||
this->Layout();
|
this->Layout();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool StatusPanel::is_moonraker_agent() const
|
||||||
|
{
|
||||||
|
auto* agent = wxGetApp().getAgent();
|
||||||
|
return agent && std::dynamic_pointer_cast<Slic3r::MoonrakerPrinterAgent>(agent->get_printer_agent()) != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void StatusPanel::on_axis_ctrl_xy(wxCommandEvent &event)
|
void StatusPanel::on_axis_ctrl_xy(wxCommandEvent &event)
|
||||||
{
|
{
|
||||||
if (!obj) return;
|
if (!obj) return;
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
#include <wx/sizer.h>
|
#include <wx/sizer.h>
|
||||||
#include <wx/gbsizer.h>
|
#include <wx/gbsizer.h>
|
||||||
#include <wx/webrequest.h>
|
#include <wx/webrequest.h>
|
||||||
|
#include <chrono>
|
||||||
#include "wxMediaCtrl2.h"
|
#include "wxMediaCtrl2.h"
|
||||||
#include "MediaPlayCtrl.h"
|
#include "MediaPlayCtrl.h"
|
||||||
#include "AMSSetting.hpp"
|
#include "AMSSetting.hpp"
|
||||||
@@ -688,6 +689,13 @@ protected:
|
|||||||
CalibrationMethod m_calib_method;
|
CalibrationMethod m_calib_method;
|
||||||
int cali_stage;
|
int cali_stage;
|
||||||
PrintingTaskType m_current_print_mode = PrintingTaskType::NOT_CLEAR;
|
PrintingTaskType m_current_print_mode = PrintingTaskType::NOT_CLEAR;
|
||||||
|
bool m_pause_resume_pending = false;
|
||||||
|
bool m_pause_resume_was_resume = false;
|
||||||
|
std::chrono::steady_clock::time_point m_pause_resume_deadline;
|
||||||
|
std::string m_pause_resume_machine_id;
|
||||||
|
bool m_abort_pending = false;
|
||||||
|
std::chrono::steady_clock::time_point m_abort_deadline;
|
||||||
|
std::string m_abort_machine_id;
|
||||||
|
|
||||||
void init_scaled_buttons();
|
void init_scaled_buttons();
|
||||||
void create_tasklist_info();
|
void create_tasklist_info();
|
||||||
@@ -790,6 +798,7 @@ protected:
|
|||||||
void update_calib_bitmap();
|
void update_calib_bitmap();
|
||||||
|
|
||||||
void reset_printing_values();
|
void reset_printing_values();
|
||||||
|
bool is_moonraker_agent() const;
|
||||||
void on_webrequest_state(wxWebRequestEvent &evt);
|
void on_webrequest_state(wxWebRequestEvent &evt);
|
||||||
bool is_task_changed(MachineObject* obj);
|
bool is_task_changed(MachineObject* obj);
|
||||||
|
|
||||||
|
|||||||
@@ -126,6 +126,53 @@ MoonrakerPrinterAgent::~MoonrakerPrinterAgent()
|
|||||||
connect_thread.join();
|
connect_thread.join();
|
||||||
}
|
}
|
||||||
stop_status_stream();
|
stop_status_stream();
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(cmd_mutex);
|
||||||
|
cmd_stop = true;
|
||||||
|
cmd_queue.clear();
|
||||||
|
}
|
||||||
|
cmd_cv.notify_one();
|
||||||
|
if (cmd_thread.joinable()) {
|
||||||
|
cmd_thread.join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MoonrakerPrinterAgent::enqueue_command(std::function<void()> fn)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(cmd_mutex);
|
||||||
|
if (!cmd_thread.joinable()) {
|
||||||
|
cmd_thread = std::thread(&MoonrakerPrinterAgent::run_command_worker, this);
|
||||||
|
}
|
||||||
|
cmd_queue.emplace_back(std::move(fn));
|
||||||
|
}
|
||||||
|
cmd_cv.notify_one();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MoonrakerPrinterAgent::run_command_worker()
|
||||||
|
{
|
||||||
|
for (;;) {
|
||||||
|
std::function<void()> command;
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(cmd_mutex);
|
||||||
|
cmd_cv.wait(lock, [this] { return cmd_stop || !cmd_queue.empty(); });
|
||||||
|
if (cmd_stop && cmd_queue.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
command = std::move(cmd_queue.front());
|
||||||
|
cmd_queue.pop_front();
|
||||||
|
}
|
||||||
|
// why: an exception escaping a worker thread is std::terminate; the old synchronous
|
||||||
|
// path at least ran under wx's unhandled-exception hook. nlohmann dump() can throw
|
||||||
|
// on invalid UTF-8 smuggled in via custom g-code.
|
||||||
|
try {
|
||||||
|
command();
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
BOOST_LOG_TRIVIAL(error) << "MoonrakerPrinterAgent: queued command failed: " << e.what();
|
||||||
|
} catch (...) {
|
||||||
|
BOOST_LOG_TRIVIAL(error) << "MoonrakerPrinterAgent: queued command failed: unknown exception";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AgentInfo MoonrakerPrinterAgent::get_agent_info_static()
|
AgentInfo MoonrakerPrinterAgent::get_agent_info_static()
|
||||||
@@ -181,6 +228,10 @@ int MoonrakerPrinterAgent::connect_printer(std::string dev_id, std::string dev_i
|
|||||||
|
|
||||||
// Stop existing status stream and clear state
|
// Stop existing status stream and clear state
|
||||||
stop_status_stream();
|
stop_status_stream();
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(cmd_mutex);
|
||||||
|
cmd_queue.clear();
|
||||||
|
}
|
||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> lock(payload_mutex);
|
std::lock_guard<std::recursive_mutex> lock(payload_mutex);
|
||||||
status_cache = nlohmann::json::object();
|
status_cache = nlohmann::json::object();
|
||||||
@@ -210,6 +261,10 @@ int MoonrakerPrinterAgent::disconnect_printer()
|
|||||||
}
|
}
|
||||||
|
|
||||||
stop_status_stream();
|
stop_status_stream();
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(cmd_mutex);
|
||||||
|
cmd_queue.clear();
|
||||||
|
}
|
||||||
return BAMBU_NETWORK_SUCCESS;
|
return BAMBU_NETWORK_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1016,6 +1071,10 @@ bool MoonrakerPrinterAgent::fetch_hh_filament_info(std::vector<AmsTrayData>& tra
|
|||||||
|
|
||||||
int MoonrakerPrinterAgent::handle_request(const std::string& dev_id, const std::string& json_str)
|
int MoonrakerPrinterAgent::handle_request(const std::string& dev_id, const std::string& json_str)
|
||||||
{
|
{
|
||||||
|
auto connection_snapshot = [this]() {
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(connect_mutex);
|
||||||
|
return std::make_pair(device_info.base_url, device_info.api_key);
|
||||||
|
};
|
||||||
auto json = nlohmann::json::parse(json_str, nullptr, false);
|
auto json = nlohmann::json::parse(json_str, nullptr, false);
|
||||||
if (json.is_discarded()) {
|
if (json.is_discarded()) {
|
||||||
BOOST_LOG_TRIVIAL(error) << "MoonrakerPrinterAgent: Invalid JSON request";
|
BOOST_LOG_TRIVIAL(error) << "MoonrakerPrinterAgent: Invalid JSON request";
|
||||||
@@ -1092,13 +1151,14 @@ int MoonrakerPrinterAgent::handle_request(const std::string& dev_id, const std::
|
|||||||
BOOST_LOG_TRIVIAL(warning) << "MoonrakerPrinterAgent: ledctrl - no light object found, dropping";
|
BOOST_LOG_TRIVIAL(warning) << "MoonrakerPrinterAgent: ledctrl - no light object found, dropping";
|
||||||
return ORCA_NETWORK_ERR_CAP_NOT_AVAILABLE;
|
return ORCA_NETWORK_ERR_CAP_NOT_AVAILABLE;
|
||||||
}
|
}
|
||||||
if (!send_gcode(dev_id, gcode)) {
|
auto [base_url, api_key] = connection_snapshot();
|
||||||
return BAMBU_NETWORK_ERR_CONNECTION_TO_PRINTER_FAILED;
|
enqueue_command([this, dev_id, gcode = std::move(gcode), base_url = std::move(base_url),
|
||||||
}
|
api_key = std::move(api_key), requested_light_on]() {
|
||||||
{
|
if (send_gcode(dev_id, gcode, base_url, api_key)) {
|
||||||
std::lock_guard<std::recursive_mutex> lock(payload_mutex);
|
std::lock_guard<std::recursive_mutex> lock(payload_mutex);
|
||||||
assumed_light_on = requested_light_on;
|
assumed_light_on = requested_light_on;
|
||||||
}
|
}
|
||||||
|
});
|
||||||
return BAMBU_NETWORK_SUCCESS;
|
return BAMBU_NETWORK_SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1143,25 +1203,38 @@ int MoonrakerPrinterAgent::handle_request(const std::string& dev_id, const std::
|
|||||||
}
|
}
|
||||||
response["print"]["param"] = gcode;
|
response["print"]["param"] = gcode;
|
||||||
|
|
||||||
if (send_gcode(dev_id, gcode)) {
|
auto [base_url, api_key] = connection_snapshot();
|
||||||
response["print"]["result"] = "success";
|
enqueue_command([this, dev_id, response = std::move(response), base_url = std::move(base_url),
|
||||||
|
api_key = std::move(api_key)]() mutable {
|
||||||
|
response["print"]["result"] = send_gcode(dev_id, response["print"]["param"].get<std::string>(), base_url, api_key)
|
||||||
|
? "success"
|
||||||
|
: "failed";
|
||||||
dispatch_message(dev_id, response.dump());
|
dispatch_message(dev_id, response.dump());
|
||||||
return BAMBU_NETWORK_SUCCESS;
|
});
|
||||||
}
|
return BAMBU_NETWORK_SUCCESS;
|
||||||
response["print"]["result"] = "failed";
|
|
||||||
dispatch_message(dev_id, response.dump());
|
|
||||||
return BAMBU_NETWORK_ERR_CONNECTION_TO_PRINTER_FAILED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Print control commands
|
// Print control commands
|
||||||
if (cmd == "pause") {
|
if (cmd == "pause") {
|
||||||
return pause_print(dev_id);
|
auto [base_url, api_key] = connection_snapshot();
|
||||||
|
enqueue_command([this, base_url = std::move(base_url), api_key = std::move(api_key)] {
|
||||||
|
post_print_action("pause", base_url, api_key);
|
||||||
|
});
|
||||||
|
return BAMBU_NETWORK_SUCCESS;
|
||||||
}
|
}
|
||||||
if (cmd == "resume") {
|
if (cmd == "resume") {
|
||||||
return resume_print(dev_id);
|
auto [base_url, api_key] = connection_snapshot();
|
||||||
|
enqueue_command([this, base_url = std::move(base_url), api_key = std::move(api_key)] {
|
||||||
|
post_print_action("resume", base_url, api_key);
|
||||||
|
});
|
||||||
|
return BAMBU_NETWORK_SUCCESS;
|
||||||
}
|
}
|
||||||
if (cmd == "stop") {
|
if (cmd == "stop") {
|
||||||
return cancel_print(dev_id);
|
auto [base_url, api_key] = connection_snapshot();
|
||||||
|
enqueue_command([this, base_url = std::move(base_url), api_key = std::move(api_key)] {
|
||||||
|
post_print_action("cancel", base_url, api_key);
|
||||||
|
});
|
||||||
|
return BAMBU_NETWORK_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bed temperature - UI sends "temp" field
|
// Bed temperature - UI sends "temp" field
|
||||||
@@ -1169,7 +1242,11 @@ int MoonrakerPrinterAgent::handle_request(const std::string& dev_id, const std::
|
|||||||
if (json["print"].contains("temp") && json["print"]["temp"].is_number()) {
|
if (json["print"].contains("temp") && json["print"]["temp"].is_number()) {
|
||||||
int temp = json["print"]["temp"].get<int>();
|
int temp = json["print"]["temp"].get<int>();
|
||||||
std::string gcode = "SET_HEATER_TEMPERATURE HEATER=heater_bed TARGET=" + std::to_string(temp);
|
std::string gcode = "SET_HEATER_TEMPERATURE HEATER=heater_bed TARGET=" + std::to_string(temp);
|
||||||
send_gcode(dev_id, gcode);
|
auto [base_url, api_key] = connection_snapshot();
|
||||||
|
enqueue_command([this, dev_id, gcode = std::move(gcode), base_url = std::move(base_url),
|
||||||
|
api_key = std::move(api_key)] {
|
||||||
|
send_gcode(dev_id, gcode, base_url, api_key);
|
||||||
|
});
|
||||||
return BAMBU_NETWORK_SUCCESS;
|
return BAMBU_NETWORK_SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1184,7 +1261,11 @@ int MoonrakerPrinterAgent::handle_request(const std::string& dev_id, const std::
|
|||||||
}
|
}
|
||||||
std::string heater = (extruder_idx == 0) ? "extruder" : "extruder" + std::to_string(extruder_idx);
|
std::string heater = (extruder_idx == 0) ? "extruder" : "extruder" + std::to_string(extruder_idx);
|
||||||
std::string gcode = "SET_HEATER_TEMPERATURE HEATER=" + heater + " TARGET=" + std::to_string(temp);
|
std::string gcode = "SET_HEATER_TEMPERATURE HEATER=" + heater + " TARGET=" + std::to_string(temp);
|
||||||
send_gcode(dev_id, gcode);
|
auto [base_url, api_key] = connection_snapshot();
|
||||||
|
enqueue_command([this, dev_id, gcode = std::move(gcode), base_url = std::move(base_url),
|
||||||
|
api_key = std::move(api_key)] {
|
||||||
|
send_gcode(dev_id, gcode, base_url, api_key);
|
||||||
|
});
|
||||||
return BAMBU_NETWORK_SUCCESS;
|
return BAMBU_NETWORK_SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1192,7 +1273,11 @@ int MoonrakerPrinterAgent::handle_request(const std::string& dev_id, const std::
|
|||||||
// why: no current OrcaSlicer sender emits the "home" discriminator;
|
// why: no current OrcaSlicer sender emits the "home" discriminator;
|
||||||
// GUI homing uses gcode_line with G28 instead.
|
// GUI homing uses gcode_line with G28 instead.
|
||||||
if (cmd == "home") {
|
if (cmd == "home") {
|
||||||
return send_gcode(dev_id, "G28") ? BAMBU_NETWORK_SUCCESS : BAMBU_NETWORK_ERR_SEND_MSG_FAILED;
|
auto [base_url, api_key] = connection_snapshot();
|
||||||
|
enqueue_command([this, dev_id, base_url = std::move(base_url), api_key = std::move(api_key)] {
|
||||||
|
send_gcode(dev_id, "G28", base_url, api_key);
|
||||||
|
});
|
||||||
|
return BAMBU_NETWORK_SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1456,6 +1541,21 @@ bool MoonrakerPrinterAgent::fetch_webcam_info(const std::string& base_url, const
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool MoonrakerPrinterAgent::post_print_action(const std::string& action) const
|
bool MoonrakerPrinterAgent::post_print_action(const std::string& action) const
|
||||||
|
{
|
||||||
|
// why: snapshot then release - holding connect_mutex across the blocking HTTP call
|
||||||
|
// would stall any UI-thread handle_request waiting to take its own snapshot.
|
||||||
|
std::string base_url, api_key;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(connect_mutex);
|
||||||
|
base_url = device_info.base_url;
|
||||||
|
api_key = device_info.api_key;
|
||||||
|
}
|
||||||
|
return post_print_action(action, base_url, api_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MoonrakerPrinterAgent::post_print_action(const std::string& action,
|
||||||
|
const std::string& base_url,
|
||||||
|
const std::string& api_key) const
|
||||||
{
|
{
|
||||||
// why: /printer/print/{pause,resume,cancel} map to Klipper's pause_resume
|
// why: /printer/print/{pause,resume,cancel} map to Klipper's pause_resume
|
||||||
// webhook (a direct interrupt). A raw PAUSE/RESUME/CANCEL_PRINT queued through
|
// webhook (a direct interrupt). A raw PAUSE/RESUME/CANCEL_PRINT queued through
|
||||||
@@ -1463,13 +1563,13 @@ bool MoonrakerPrinterAgent::post_print_action(const std::string& action) const
|
|||||||
// printer is busy (long move, heating, inside a macro).
|
// printer is busy (long move, heating, inside a macro).
|
||||||
// note: empty JSON body avoids a body-less POST (curl would treat it as a
|
// note: empty JSON body avoids a body-less POST (curl would treat it as a
|
||||||
// streamed upload) - same reason start_print_file sends a body.
|
// streamed upload) - same reason start_print_file sends a body.
|
||||||
const std::string full_url = join_url(device_info.base_url, "/printer/print/" + action);
|
const std::string full_url = join_url(base_url, "/printer/print/" + action);
|
||||||
bool success = false;
|
bool success = false;
|
||||||
std::string http_error;
|
std::string http_error;
|
||||||
|
|
||||||
auto http = Http::post(full_url);
|
auto http = Http::post(full_url);
|
||||||
if (!device_info.api_key.empty()) {
|
if (!api_key.empty()) {
|
||||||
http.header("X-Api-Key", device_info.api_key);
|
http.header("X-Api-Key", api_key);
|
||||||
}
|
}
|
||||||
http.header("Content-Type", "application/json")
|
http.header("Content-Type", "application/json")
|
||||||
.set_post_body(std::string("{}"))
|
.set_post_body(std::string("{}"))
|
||||||
@@ -1501,6 +1601,19 @@ bool MoonrakerPrinterAgent::post_print_action(const std::string& action) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool MoonrakerPrinterAgent::send_gcode(const std::string& dev_id, const std::string& gcode) const
|
bool MoonrakerPrinterAgent::send_gcode(const std::string& dev_id, const std::string& gcode) const
|
||||||
|
{
|
||||||
|
// why: snapshot then release - see post_print_action.
|
||||||
|
std::string base_url, api_key;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(connect_mutex);
|
||||||
|
base_url = device_info.base_url;
|
||||||
|
api_key = device_info.api_key;
|
||||||
|
}
|
||||||
|
return send_gcode(dev_id, gcode, base_url, api_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MoonrakerPrinterAgent::send_gcode(const std::string& dev_id, const std::string& gcode,
|
||||||
|
const std::string& base_url, const std::string& api_key) const
|
||||||
{
|
{
|
||||||
nlohmann::json payload;
|
nlohmann::json payload;
|
||||||
payload["script"] = gcode;
|
payload["script"] = gcode;
|
||||||
@@ -1510,10 +1623,10 @@ bool MoonrakerPrinterAgent::send_gcode(const std::string& dev_id, const std::str
|
|||||||
bool success = false;
|
bool success = false;
|
||||||
std::string http_error;
|
std::string http_error;
|
||||||
|
|
||||||
auto full_url = join_url(device_info.base_url, "/printer/gcode/script");
|
auto full_url = join_url(base_url, "/printer/gcode/script");
|
||||||
auto http = Http::post(full_url);
|
auto http = Http::post(full_url);
|
||||||
if (!device_info.api_key.empty()) {
|
if (!api_key.empty()) {
|
||||||
http.header("X-Api-Key", device_info.api_key);
|
http.header("X-Api-Key", api_key);
|
||||||
}
|
}
|
||||||
http.header("Content-Type", "application/json")
|
http.header("Content-Type", "application/json")
|
||||||
.set_post_body(payload_str)
|
.set_post_body(payload_str)
|
||||||
|
|||||||
@@ -9,6 +9,9 @@
|
|||||||
#include <set>
|
#include <set>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <deque>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
@@ -125,7 +128,11 @@ protected:
|
|||||||
|
|
||||||
// Send a G-code script via Moonraker (/printer/gcode/script)
|
// Send a G-code script via Moonraker (/printer/gcode/script)
|
||||||
bool send_gcode(const std::string& dev_id, const std::string& gcode) const;
|
bool send_gcode(const std::string& dev_id, const std::string& gcode) const;
|
||||||
|
bool send_gcode(const std::string& dev_id, const std::string& gcode,
|
||||||
|
const std::string& base_url, const std::string& api_key) const;
|
||||||
bool post_print_action(const std::string& action) const;
|
bool post_print_action(const std::string& action) const;
|
||||||
|
bool post_print_action(const std::string& action,
|
||||||
|
const std::string& base_url, const std::string& api_key) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int handle_request(const std::string& dev_id, const std::string& json_str);
|
int handle_request(const std::string& dev_id, const std::string& json_str);
|
||||||
@@ -221,7 +228,15 @@ private:
|
|||||||
// Connection thread management
|
// Connection thread management
|
||||||
std::atomic<uint64_t> connect_generation{0};
|
std::atomic<uint64_t> connect_generation{0};
|
||||||
std::thread connect_thread;
|
std::thread connect_thread;
|
||||||
std::recursive_mutex connect_mutex;
|
mutable std::recursive_mutex connect_mutex;
|
||||||
|
|
||||||
|
void enqueue_command(std::function<void()> fn);
|
||||||
|
void run_command_worker();
|
||||||
|
std::thread cmd_thread;
|
||||||
|
std::deque<std::function<void()>> cmd_queue;
|
||||||
|
std::mutex cmd_mutex;
|
||||||
|
std::condition_variable cmd_cv;
|
||||||
|
bool cmd_stop = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
|||||||
Reference in New Issue
Block a user