From 4917f3b811ddf3f1bf31ac14180af5e7e1940ef7 Mon Sep 17 00:00:00 2001 From: Sergey Kovalev Date: Sun, 27 Dec 2020 21:51:06 +0700 Subject: [PATCH 1/8] Initial implementation, mostly proof of concept --- src/libslic3r/PrintConfig.cpp | 2 + src/libslic3r/PrintConfig.hpp | 2 +- src/slic3r/CMakeLists.txt | 2 + src/slic3r/Utils/MKS.cpp | 171 +++++++++++++++++++++++++++++++++ src/slic3r/Utils/MKS.hpp | 44 +++++++++ src/slic3r/Utils/PrintHost.cpp | 2 + 6 files changed, 222 insertions(+), 1 deletion(-) create mode 100644 src/slic3r/Utils/MKS.cpp create mode 100644 src/slic3r/Utils/MKS.hpp diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index c63780449..85cae5c1b 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -1854,12 +1854,14 @@ void PrintConfigDef::init_fff_params() def->enum_values.push_back("flashair"); def->enum_values.push_back("astrobox"); def->enum_values.push_back("repetier"); + def->enum_values.push_back("mks"); def->enum_labels.push_back("PrusaLink"); def->enum_labels.push_back("OctoPrint"); def->enum_labels.push_back("Duet"); def->enum_labels.push_back("FlashAir"); def->enum_labels.push_back("AstroBox"); def->enum_labels.push_back("Repetier"); + def->enum_labels.push_back("MKS"); def->mode = comAdvanced; def->cli = ConfigOptionDef::nocli; def->set_default_value(new ConfigOptionEnum(htOctoPrint)); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 68dbd68d3..657f34ad1 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -44,7 +44,7 @@ enum class MachineLimitsUsage { }; enum PrintHostType { - htPrusaLink, htOctoPrint, htDuet, htFlashAir, htAstroBox, htRepetier + htPrusaLink, htOctoPrint, htDuet, htFlashAir, htAstroBox, htRepetier, htMKS }; enum AuthorizationType { diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index f0c2338e9..75887d17c 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -237,6 +237,8 @@ set(SLIC3R_GUI_SOURCES Utils/UndoRedo.hpp Utils/HexFile.cpp Utils/HexFile.hpp + Utils/MKS.cpp + Utils/MKS.hpp ) if (APPLE) diff --git a/src/slic3r/Utils/MKS.cpp b/src/slic3r/Utils/MKS.cpp new file mode 100644 index 000000000..4f7c9a90b --- /dev/null +++ b/src/slic3r/Utils/MKS.cpp @@ -0,0 +1,171 @@ +#include "MKS.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "libslic3r/PrintConfig.hpp" +#include "slic3r/GUI/GUI.hpp" +#include "slic3r/GUI/I18N.hpp" +#include "slic3r/GUI/MsgDialog.hpp" +#include "Http.hpp" + +namespace fs = boost::filesystem; +namespace pt = boost::property_tree; + +namespace Slic3r { + +MKS::MKS(DynamicPrintConfig *config) : + host(config->opt_string("print_host")), console_port(8080) +{} + +const char* MKS::get_name() const { return "MKS"; } + +bool MKS::test(wxString &msg) const +{ + return run_simple_gcode("M105", msg); +} + +wxString MKS::get_test_ok_msg () const +{ + return _(L("Connection to MKS works correctly.")); +} + +wxString MKS::get_test_failed_msg (wxString &msg) const +{ + return GUI::from_u8((boost::format("%s: %s") + % _utf8(L("Could not connect to MKS")) + % std::string(msg.ToUTF8())).str()); +} + +bool MKS::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn) const +{ + bool res = true; + + auto upload_cmd = get_upload_url(upload_data.upload_path.string()); + BOOST_LOG_TRIVIAL(info) << boost::format("MKS: Uploading file %1%, filepath: %2%, print: %3%, command: %4%") + % upload_data.source_path + % upload_data.upload_path + % upload_data.start_print + % upload_cmd; + + auto http = Http::post(std::move(upload_cmd)); + http.set_post_body(upload_data.source_path); + + http.on_complete([&](std::string body, unsigned status) { + BOOST_LOG_TRIVIAL(debug) << boost::format("MKS: File uploaded: HTTP %1%: %2%") % status % body; + + int err_code = get_err_code_from_body(body); + if (err_code != 0) { + BOOST_LOG_TRIVIAL(error) << boost::format("MKS: Request completed but error code was received: %1%") % err_code; + error_fn(format_error(body, L("Unknown error occured"), 0)); + res = false; + } else if (upload_data.start_print) { + wxString errormsg; + res = start_print(errormsg, upload_data.upload_path.string()); + if (! res) { + error_fn(std::move(errormsg)); + } + } + }) + .on_error([&](std::string body, std::string error, unsigned status) { + BOOST_LOG_TRIVIAL(error) << boost::format("MKS: Error uploading file: %1%, HTTP %2%, body: `%3%`") % error % status % body; + error_fn(format_error(body, error, status)); + res = false; + }) + .on_progress([&](Http::Progress progress, bool &cancel) { + prorgess_fn(std::move(progress), cancel); + if (cancel) { + // Upload was canceled + BOOST_LOG_TRIVIAL(info) << "MKS: Upload canceled"; + res = false; + } + }) + .perform_sync(); + + if (res) { + std::this_thread::sleep_for(std::chrono::milliseconds(1500)); + + wxString msg; + res &= run_simple_gcode(std::string("M23 ") + upload_data.upload_path.string(), msg); + if (res) { + res &= run_simple_gcode(std::string("M24"), msg); + } + } + + return res; +} + +std::string MKS::get_upload_url(const std::string &filename) const +{ + return (boost::format("http://%1%/upload?X-Filename=%2%") + % host + % Http::url_encode(filename)).str(); +} + +bool MKS::start_print(wxString &msg, const std::string &filename) const +{ + BOOST_LOG_TRIVIAL(warning) << boost::format("MKS: start_print is not implemented yet, called stub"); + return true; +} + +int MKS::get_err_code_from_body(const std::string& body) const +{ + pt::ptree root; + std::istringstream iss(body); // wrap returned json to istringstream + pt::read_json(iss, root); + + return root.get("err", 0); +} + +bool MKS::run_simple_gcode(const std::string &cmd, wxString &msg) const +{ + using boost::asio::ip::tcp; + + try + { + boost::asio::io_context io_context; + tcp::socket s(io_context); + + tcp::resolver resolver(io_context); + boost::asio::connect(s, resolver.resolve(host, std::to_string(console_port))); + boost::asio::write(s, boost::asio::buffer(cmd + "\r\n")); + + msg = "request:" + cmd + "\r\n"; + + boost::asio::streambuf input_buffer; + size_t reply_length = boost::asio::read_until(s, input_buffer, '\n'); + + std::string response((std::istreambuf_iterator(&input_buffer)), std::istreambuf_iterator()); + if (response.length() == 0) { + msg += "Empty response"; + return false; + } + + msg += "response:" + response; + return true; + } + catch (std::exception& e) + { + msg = std::string("exception:") + e.what(); + return false; + } +} + +} diff --git a/src/slic3r/Utils/MKS.hpp b/src/slic3r/Utils/MKS.hpp new file mode 100644 index 000000000..4fed921d5 --- /dev/null +++ b/src/slic3r/Utils/MKS.hpp @@ -0,0 +1,44 @@ +#ifndef slic3r_MKS_hpp_ +#define slic3r_MKS_hpp_ + +#include +#include + +#include "PrintHost.hpp" + +namespace Slic3r { + +class DynamicPrintConfig; +class Http; + +class MKS : public PrintHost +{ +public: + explicit MKS(DynamicPrintConfig *config); + ~MKS() override = default; + + const char* get_name() const override; + + bool test(wxString &curl_msg) const override; + wxString get_test_ok_msg() const override; + wxString get_test_failed_msg(wxString &msg) const override; + bool upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn) const override; + bool has_auto_discovery() const override { return false; } + bool can_test() const override { return true; } + bool can_start_print() const override { return true; } + std::string get_host() const override { return host; } + +private: + std::string host; + int console_port; + + std::string get_upload_url(const std::string &filename) const; + std::string timestamp_str() const; + bool start_print(wxString &msg, const std::string &filename) const; + int get_err_code_from_body(const std::string &body) const; + bool run_simple_gcode(const std::string& cmd, wxString& msg) const; +}; + +} + +#endif diff --git a/src/slic3r/Utils/PrintHost.cpp b/src/slic3r/Utils/PrintHost.cpp index 53200a4c9..86f6101b6 100644 --- a/src/slic3r/Utils/PrintHost.cpp +++ b/src/slic3r/Utils/PrintHost.cpp @@ -18,6 +18,7 @@ #include "FlashAir.hpp" #include "AstroBox.hpp" #include "Repetier.hpp" +#include "MKS.hpp" #include "../GUI/PrintHostDialogs.hpp" namespace fs = boost::filesystem; @@ -51,6 +52,7 @@ PrintHost* PrintHost::get_print_host(DynamicPrintConfig *config) case htAstroBox: return new AstroBox(config); case htRepetier: return new Repetier(config); case htPrusaLink: return new PrusaLink(config); + case htMKS: return new MKS(config); default: return nullptr; } } else { From 11eafebd8ffd0d1453d90cab0b93681023202fb2 Mon Sep 17 00:00:00 2001 From: Sergey Kovalev Date: Sun, 27 Dec 2020 23:16:19 +0700 Subject: [PATCH 2/8] Fix printing start condition, a little bit more comments --- src/slic3r/Utils/MKS.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/slic3r/Utils/MKS.cpp b/src/slic3r/Utils/MKS.cpp index 4f7c9a90b..aa7eee48e 100644 --- a/src/slic3r/Utils/MKS.cpp +++ b/src/slic3r/Utils/MKS.cpp @@ -99,7 +99,9 @@ bool MKS::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn er }) .perform_sync(); - if (res) { + if (res && upload_data.start_print) { + // For some reason printer firmware does not want to respond on gcode commands immediately after file upload. + // So we just introduce artificial delay to workaround it. std::this_thread::sleep_for(std::chrono::milliseconds(1500)); wxString msg; From 869b8c8c66e0fee0464c98b7008e0f6a2dbc41d8 Mon Sep 17 00:00:00 2001 From: Sergey Kovalev Date: Tue, 29 Dec 2020 00:44:39 +0700 Subject: [PATCH 3/8] Add better implementation of tcp console --- src/slic3r/CMakeLists.txt | 2 + src/slic3r/Utils/MKS.cpp | 74 +++++-------- src/slic3r/Utils/MKS.hpp | 6 +- src/slic3r/Utils/TCPConsole.cpp | 191 ++++++++++++++++++++++++++++++++ src/slic3r/Utils/TCPConsole.hpp | 81 ++++++++++++++ 5 files changed, 303 insertions(+), 51 deletions(-) create mode 100644 src/slic3r/Utils/TCPConsole.cpp create mode 100644 src/slic3r/Utils/TCPConsole.hpp diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 75887d17c..94b8bae6f 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -237,6 +237,8 @@ set(SLIC3R_GUI_SOURCES Utils/UndoRedo.hpp Utils/HexFile.cpp Utils/HexFile.hpp + Utils/TCPConsole.cpp + Utils/TCPConsole.hpp Utils/MKS.cpp Utils/MKS.hpp ) diff --git a/src/slic3r/Utils/MKS.cpp b/src/slic3r/Utils/MKS.cpp index aa7eee48e..c25ae9d0d 100644 --- a/src/slic3r/Utils/MKS.cpp +++ b/src/slic3r/Utils/MKS.cpp @@ -32,14 +32,21 @@ namespace pt = boost::property_tree; namespace Slic3r { MKS::MKS(DynamicPrintConfig *config) : - host(config->opt_string("print_host")), console_port(8080) + host(config->opt_string("print_host")), console(config->opt_string("print_host"), "8080") {} const char* MKS::get_name() const { return "MKS"; } bool MKS::test(wxString &msg) const { - return run_simple_gcode("M105", msg); + console.enqueue_cmd("M105"); + bool ret = console.run_queue(); + + if (!ret) { + msg = console.error_message(); + } + + return ret; } wxString MKS::get_test_ok_msg () const @@ -100,15 +107,7 @@ bool MKS::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn er .perform_sync(); if (res && upload_data.start_print) { - // For some reason printer firmware does not want to respond on gcode commands immediately after file upload. - // So we just introduce artificial delay to workaround it. - std::this_thread::sleep_for(std::chrono::milliseconds(1500)); - - wxString msg; - res &= run_simple_gcode(std::string("M23 ") + upload_data.upload_path.string(), msg); - if (res) { - res &= run_simple_gcode(std::string("M24"), msg); - } + start_print(upload_data.upload_path); } return res; @@ -123,8 +122,21 @@ std::string MKS::get_upload_url(const std::string &filename) const bool MKS::start_print(wxString &msg, const std::string &filename) const { - BOOST_LOG_TRIVIAL(warning) << boost::format("MKS: start_print is not implemented yet, called stub"); - return true; + // For some reason printer firmware does not want to respond on gcode commands immediately after file upload. + // So we just introduce artificial delay to workaround it. + // TODO: Inspect reasons + std::this_thread::sleep_for(std::chrono::milliseconds(1500)); + + console.enqueue_cmd("M23 " + upload_data.upload_path.string()); + console.enqueue_cmd("M24"); + + bool ret = console.run_queue(); + + if (!ret) { + msg = console.error_message(); + } + + return ret; } int MKS::get_err_code_from_body(const std::string& body) const @@ -136,38 +148,4 @@ int MKS::get_err_code_from_body(const std::string& body) const return root.get("err", 0); } -bool MKS::run_simple_gcode(const std::string &cmd, wxString &msg) const -{ - using boost::asio::ip::tcp; - - try - { - boost::asio::io_context io_context; - tcp::socket s(io_context); - - tcp::resolver resolver(io_context); - boost::asio::connect(s, resolver.resolve(host, std::to_string(console_port))); - boost::asio::write(s, boost::asio::buffer(cmd + "\r\n")); - - msg = "request:" + cmd + "\r\n"; - - boost::asio::streambuf input_buffer; - size_t reply_length = boost::asio::read_until(s, input_buffer, '\n'); - - std::string response((std::istreambuf_iterator(&input_buffer)), std::istreambuf_iterator()); - if (response.length() == 0) { - msg += "Empty response"; - return false; - } - - msg += "response:" + response; - return true; - } - catch (std::exception& e) - { - msg = std::string("exception:") + e.what(); - return false; - } -} - -} +} // Slic3r diff --git a/src/slic3r/Utils/MKS.hpp b/src/slic3r/Utils/MKS.hpp index 4fed921d5..0414e3335 100644 --- a/src/slic3r/Utils/MKS.hpp +++ b/src/slic3r/Utils/MKS.hpp @@ -5,6 +5,7 @@ #include #include "PrintHost.hpp" +#include "TCPConsole.hpp" namespace Slic3r { @@ -27,16 +28,15 @@ public: bool can_test() const override { return true; } bool can_start_print() const override { return true; } std::string get_host() const override { return host; } - + private: std::string host; - int console_port; + Utils::TCPConsole console; std::string get_upload_url(const std::string &filename) const; std::string timestamp_str() const; bool start_print(wxString &msg, const std::string &filename) const; int get_err_code_from_body(const std::string &body) const; - bool run_simple_gcode(const std::string& cmd, wxString& msg) const; }; } diff --git a/src/slic3r/Utils/TCPConsole.cpp b/src/slic3r/Utils/TCPConsole.cpp new file mode 100644 index 000000000..4e1ca1f7c --- /dev/null +++ b/src/slic3r/Utils/TCPConsole.cpp @@ -0,0 +1,191 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +using boost::asio::steady_timer; +using boost::asio::ip::tcp; + +namespace Slic3r { +namespace Utils { + +void TCPConsole::transmit_next_command() +{ + if (cmd_queue_.empty()) { + io_context_.stop(); + return; + } + + std::string cmd = cmd_queue_.front(); + cmd_queue_.pop_front(); + + BOOST_LOG_TRIVIAL(debug) << boost::format("TCPConsole: transmitting '%3%' to %1%:%2%") + % host_name_ + % port_name_ + % cmd; + + auto data = boost::asio::buffer(cmd + newline_); + + boost::asio::async_write( + socket_, + data, + boost::bind(&TCPConsole::handle_write, this, _1, _2) + ); +} + +void TCPConsole::wait_next_line() +{ + boost::asio::async_read_until( + socket_, + recv_buffer_, + newline_, + boost::bind(&TCPConsole::handle_read, this, _1, _2) + ); +} + +// TODO: Use std::optional here +std::string TCPConsole::extract_next_line() +{ + char linebuf[1024]; + + std::istream is(&recv_buffer_); + is.getline(linebuf, sizeof(linebuf)); + if (is.good()) { + return linebuf; + } + + return ""; +} + +void TCPConsole::handle_read( + const boost::system::error_code& ec, + std::size_t bytes_transferred) +{ + error_code_ = ec; + + if (ec) { + BOOST_LOG_TRIVIAL(error) << boost::format("TCPConsole: Can't read from %1%:%2%: %3%") + % host_name_ + % port_name_ + % ec.message(); + + io_context_.stop(); + } else { + std::string line = extract_next_line(); + boost::trim(line); + + BOOST_LOG_TRIVIAL(debug) << boost::format("TCPConsole: received '%3%' from %1%:%2%") + % host_name_ + % port_name_ + % line; + + boost::to_lower(line); + + if (line == done_string_) { + transmit_next_command(); + } else { + wait_next_line(); + } + } +} + +void TCPConsole::handle_write( + const boost::system::error_code& ec, + std::size_t) +{ + error_code_ = ec; + if (ec) { + BOOST_LOG_TRIVIAL(error) << boost::format("TCPConsole: Can't write to %1%:%2%: %3%") + % host_name_ + % port_name_ + % ec.message(); + + io_context_.stop(); + } else { + wait_next_line(); + } +} + +void TCPConsole::handle_connect(const boost::system::error_code& ec) +{ + error_code_ = ec; + + if (ec) { + BOOST_LOG_TRIVIAL(error) << boost::format("TCPConsole: Can't connect to %1%:%2%: %3%") + % host_name_ + % port_name_ + % ec.message(); + + io_context_.stop(); + } else { + BOOST_LOG_TRIVIAL(info) << boost::format("TCPConsole: connected to %1%:%2%") + % host_name_ + % port_name_; + + + transmit_next_command(); + } +} + +bool TCPConsole::run_queue() +{ + try { + // TODO: Add more resets and initializations after previous run + + auto endpoints = resolver_.resolve(host_name_, port_name_); + + socket_.async_connect(endpoints->endpoint(), + boost::bind(&TCPConsole::handle_connect, this, _1) + ); + + // TODO: Add error and timeout processing + io_context_.restart(); + while (!io_context_.stopped()) { + BOOST_LOG_TRIVIAL(debug) << ".\n"; + if (error_code_) { + io_context_.stop(); + } + io_context_.run_for(boost::asio::chrono::milliseconds(100)); + } + + // Socket is not closed automatically by boost + socket_.close(); + + if (error_code_) { + // We expect that message is logged in handler + return false; + } + + // It's expected to have empty queue after successful exchange + if (!cmd_queue_.empty()) { + BOOST_LOG_TRIVIAL(error) << "TCPConsole: command queue is not empty after end of exchange"; + return false; + } + } + catch (std::exception& e) + { + BOOST_LOG_TRIVIAL(error) << boost::format("TCPConsole: Exception while talking with %1%:%2%: %3%") + % host_name_ + % port_name_ + % e.what(); + + return false; + } + + return true; +} + + +} +} diff --git a/src/slic3r/Utils/TCPConsole.hpp b/src/slic3r/Utils/TCPConsole.hpp new file mode 100644 index 000000000..6ff65ad8a --- /dev/null +++ b/src/slic3r/Utils/TCPConsole.hpp @@ -0,0 +1,81 @@ +#ifndef slic3r_Utils_TCPConsole_hpp_ +#define slic3r_Utils_TCPConsole_hpp_ + +#include +#include +#include +#include +#include + +namespace Slic3r { +namespace Utils { + +const char * default_newline = "\n"; +const char * default_done_string = "ok"; + +using boost::asio::ip::tcp; + +class TCPConsole +{ +public: + TCPConsole(): resolver_(io_context_), socket_(io_context_), newline_(default_newline), done_string_(default_done_string) {} + + TCPConsole(const std::string &host_name, const std::string &port_name): + resolver_(io_context_), socket_(io_context_), newline_(default_newline), done_string_(default_done_string) + { + set_remote(host_name, port_name); + } + ~TCPConsole(){} + + void set_line_delimiter(const std::string &newline) { + newline_ = newline; + } + void set_command_done_string(const std::string &done_string) { + done_string_ = done_string; + } + + void set_remote(const std::string &host_name, const std::string &port_name) + { + host_name_ = host_name; + port_name_ = port_name; + } + + bool enqueue_cmd(const std::string &cmd) { + // TODO: Add multithread protection to queue + cmd_queue_.push_back(cmd); + return true; + } + + bool run_queue(); + std::string error_message() { + return error_code_.message(); + } + +private: + void handle_connect(const boost::system::error_code& ec); + void handle_read(const boost::system::error_code& ec, std::size_t bytes_transferred); + void handle_write(const boost::system::error_code& ec, std::size_t bytes_transferred); + + void transmit_next_command(); + void wait_next_line(); + std::string extract_next_line(); + + std::string host_name_; + std::string port_name_; + std::string newline_; + std::string done_string_; + + std::list cmd_queue_; + + boost::asio::io_context io_context_; + tcp::resolver resolver_; + tcp::socket socket_; + boost::asio::streambuf recv_buffer_; + + boost::system::error_code error_code_; +}; + +} // Utils +} // Slic3r + +#endif From f1ae74f9d3969a8c0235c5b7943a4e2a7660a468 Mon Sep 17 00:00:00 2001 From: Sergey Kovalev Date: Tue, 29 Dec 2020 01:01:39 +0700 Subject: [PATCH 4/8] Small adaptation and formatting --- src/slic3r/Utils/MKS.cpp | 170 ++++++++-------- src/slic3r/Utils/MKS.hpp | 48 ++--- src/slic3r/Utils/TCPConsole.cpp | 330 ++++++++++++++++---------------- src/slic3r/Utils/TCPConsole.hpp | 106 +++++----- 4 files changed, 331 insertions(+), 323 deletions(-) diff --git a/src/slic3r/Utils/MKS.cpp b/src/slic3r/Utils/MKS.cpp index c25ae9d0d..1a60c5a3e 100644 --- a/src/slic3r/Utils/MKS.cpp +++ b/src/slic3r/Utils/MKS.cpp @@ -31,51 +31,51 @@ namespace pt = boost::property_tree; namespace Slic3r { -MKS::MKS(DynamicPrintConfig *config) : - host(config->opt_string("print_host")), console(config->opt_string("print_host"), "8080") -{} + MKS::MKS(DynamicPrintConfig* config) : + host(config->opt_string("print_host")), console(config->opt_string("print_host"), "8080") + {} -const char* MKS::get_name() const { return "MKS"; } + const char* MKS::get_name() const { return "MKS"; } -bool MKS::test(wxString &msg) const -{ - console.enqueue_cmd("M105"); - bool ret = console.run_queue(); + bool MKS::test(wxString& msg) const + { + console.enqueue_cmd("M105"); + bool ret = console.run_queue(); - if (!ret) { - msg = console.error_message(); - } + if (!ret) { + msg = console.error_message(); + } - return ret; -} + return ret; + } -wxString MKS::get_test_ok_msg () const -{ - return _(L("Connection to MKS works correctly.")); -} + wxString MKS::get_test_ok_msg() const + { + return _(L("Connection to MKS works correctly.")); + } -wxString MKS::get_test_failed_msg (wxString &msg) const -{ - return GUI::from_u8((boost::format("%s: %s") - % _utf8(L("Could not connect to MKS")) - % std::string(msg.ToUTF8())).str()); -} + wxString MKS::get_test_failed_msg(wxString& msg) const + { + return GUI::from_u8((boost::format("%s: %s") + % _utf8(L("Could not connect to MKS")) + % std::string(msg.ToUTF8())).str()); + } -bool MKS::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn) const -{ - bool res = true; + bool MKS::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn) const + { + bool res = true; - auto upload_cmd = get_upload_url(upload_data.upload_path.string()); - BOOST_LOG_TRIVIAL(info) << boost::format("MKS: Uploading file %1%, filepath: %2%, print: %3%, command: %4%") - % upload_data.source_path - % upload_data.upload_path - % upload_data.start_print - % upload_cmd; + auto upload_cmd = get_upload_url(upload_data.upload_path.string()); + BOOST_LOG_TRIVIAL(info) << boost::format("MKS: Uploading file %1%, filepath: %2%, print: %3%, command: %4%") + % upload_data.source_path + % upload_data.upload_path + % upload_data.start_print + % upload_cmd; - auto http = Http::post(std::move(upload_cmd)); - http.set_post_body(upload_data.source_path); + auto http = Http::post(std::move(upload_cmd)); + http.set_post_body(upload_data.source_path); - http.on_complete([&](std::string body, unsigned status) { + http.on_complete([&](std::string body, unsigned status) { BOOST_LOG_TRIVIAL(debug) << boost::format("MKS: File uploaded: HTTP %1%: %2%") % status % body; int err_code = get_err_code_from_body(body); @@ -83,69 +83,73 @@ bool MKS::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn er BOOST_LOG_TRIVIAL(error) << boost::format("MKS: Request completed but error code was received: %1%") % err_code; error_fn(format_error(body, L("Unknown error occured"), 0)); res = false; - } else if (upload_data.start_print) { + } + else if (upload_data.start_print) { wxString errormsg; res = start_print(errormsg, upload_data.upload_path.string()); - if (! res) { + if (!res) { error_fn(std::move(errormsg)); } } - }) - .on_error([&](std::string body, std::string error, unsigned status) { - BOOST_LOG_TRIVIAL(error) << boost::format("MKS: Error uploading file: %1%, HTTP %2%, body: `%3%`") % error % status % body; - error_fn(format_error(body, error, status)); - res = false; - }) - .on_progress([&](Http::Progress progress, bool &cancel) { - prorgess_fn(std::move(progress), cancel); - if (cancel) { - // Upload was canceled - BOOST_LOG_TRIVIAL(info) << "MKS: Upload canceled"; + }) + .on_error([&](std::string body, std::string error, unsigned status) { + BOOST_LOG_TRIVIAL(error) << boost::format("MKS: Error uploading file: %1%, HTTP %2%, body: `%3%`") % error % status % body; + error_fn(format_error(body, error, status)); res = false; - } - }) - .perform_sync(); + }) + .on_progress([&](Http::Progress progress, bool& cancel) { + prorgess_fn(std::move(progress), cancel); + if (cancel) { + // Upload was canceled + BOOST_LOG_TRIVIAL(info) << "MKS: Upload canceled"; + res = false; + } + }) + .perform_sync(); - if (res && upload_data.start_print) { - start_print(upload_data.upload_path); + if (res && upload_data.start_print) { + wxString msg; + if (!start_print(msg, upload_data.upload_path.string())) { + error_fn(wxString("Can't start printing: ") + msg); + } + } + + return res; } - return res; -} + std::string MKS::get_upload_url(const std::string& filename) const + { + return (boost::format("http://%1%/upload?X-Filename=%2%") + % host + % Http::url_encode(filename)).str(); + } -std::string MKS::get_upload_url(const std::string &filename) const -{ - return (boost::format("http://%1%/upload?X-Filename=%2%") - % host - % Http::url_encode(filename)).str(); -} + bool MKS::start_print(wxString& msg, const std::string& filename) const + { + // For some reason printer firmware does not want to respond on gcode commands immediately after file upload. + // So we just introduce artificial delay to workaround it. + // TODO: Inspect reasons + std::this_thread::sleep_for(std::chrono::milliseconds(1500)); -bool MKS::start_print(wxString &msg, const std::string &filename) const -{ - // For some reason printer firmware does not want to respond on gcode commands immediately after file upload. - // So we just introduce artificial delay to workaround it. - // TODO: Inspect reasons - std::this_thread::sleep_for(std::chrono::milliseconds(1500)); + console.enqueue_cmd(std::string("M23 ") + filename); + console.enqueue_cmd("M24"); - console.enqueue_cmd("M23 " + upload_data.upload_path.string()); - console.enqueue_cmd("M24"); + bool ret = console.run_queue(); - bool ret = console.run_queue(); + if (!ret) { + msg = console.error_message(); + } - if (!ret) { - msg = console.error_message(); - } + return ret; + } - return ret; -} + int MKS::get_err_code_from_body(const std::string& body) const + { + pt::ptree root; + std::istringstream iss(body); // wrap returned json to istringstream + pt::read_json(iss, root); -int MKS::get_err_code_from_body(const std::string& body) const -{ - pt::ptree root; - std::istringstream iss(body); // wrap returned json to istringstream - pt::read_json(iss, root); - - return root.get("err", 0); -} + return root.get("err", 0); + } } // Slic3r diff --git a/src/slic3r/Utils/MKS.hpp b/src/slic3r/Utils/MKS.hpp index 0414e3335..67c655293 100644 --- a/src/slic3r/Utils/MKS.hpp +++ b/src/slic3r/Utils/MKS.hpp @@ -9,35 +9,35 @@ namespace Slic3r { -class DynamicPrintConfig; -class Http; + class DynamicPrintConfig; + class Http; -class MKS : public PrintHost -{ -public: - explicit MKS(DynamicPrintConfig *config); - ~MKS() override = default; + class MKS : public PrintHost + { + public: + explicit MKS(DynamicPrintConfig* config); + ~MKS() override = default; - const char* get_name() const override; + const char* get_name() const override; - bool test(wxString &curl_msg) const override; - wxString get_test_ok_msg() const override; - wxString get_test_failed_msg(wxString &msg) const override; - bool upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn) const override; - bool has_auto_discovery() const override { return false; } - bool can_test() const override { return true; } - bool can_start_print() const override { return true; } - std::string get_host() const override { return host; } + bool test(wxString& curl_msg) const override; + wxString get_test_ok_msg() const override; + wxString get_test_failed_msg(wxString& msg) const override; + bool upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn) const override; + bool has_auto_discovery() const override { return false; } + bool can_test() const override { return true; } + bool can_start_print() const override { return true; } + std::string get_host() const override { return host; } -private: - std::string host; - Utils::TCPConsole console; + private: + std::string host; + Utils::TCPConsole console; - std::string get_upload_url(const std::string &filename) const; - std::string timestamp_str() const; - bool start_print(wxString &msg, const std::string &filename) const; - int get_err_code_from_body(const std::string &body) const; -}; + std::string get_upload_url(const std::string& filename) const; + std::string timestamp_str() const; + bool start_print(wxString& msg, const std::string& filename) const; + int get_err_code_from_body(const std::string& body) const; + }; } diff --git a/src/slic3r/Utils/TCPConsole.cpp b/src/slic3r/Utils/TCPConsole.cpp index 4e1ca1f7c..bea991945 100644 --- a/src/slic3r/Utils/TCPConsole.cpp +++ b/src/slic3r/Utils/TCPConsole.cpp @@ -18,174 +18,178 @@ using boost::asio::steady_timer; using boost::asio::ip::tcp; namespace Slic3r { -namespace Utils { + namespace Utils { -void TCPConsole::transmit_next_command() -{ - if (cmd_queue_.empty()) { - io_context_.stop(); - return; - } + void TCPConsole::transmit_next_command() + { + if (cmd_queue_.empty()) { + io_context_.stop(); + return; + } - std::string cmd = cmd_queue_.front(); - cmd_queue_.pop_front(); + std::string cmd = cmd_queue_.front(); + cmd_queue_.pop_front(); - BOOST_LOG_TRIVIAL(debug) << boost::format("TCPConsole: transmitting '%3%' to %1%:%2%") - % host_name_ - % port_name_ - % cmd; + BOOST_LOG_TRIVIAL(debug) << boost::format("TCPConsole: transmitting '%3%' to %1%:%2%") + % host_name_ + % port_name_ + % cmd; - auto data = boost::asio::buffer(cmd + newline_); + auto data = boost::asio::buffer(cmd + newline_); - boost::asio::async_write( - socket_, - data, - boost::bind(&TCPConsole::handle_write, this, _1, _2) - ); -} - -void TCPConsole::wait_next_line() -{ - boost::asio::async_read_until( - socket_, - recv_buffer_, - newline_, - boost::bind(&TCPConsole::handle_read, this, _1, _2) - ); -} - -// TODO: Use std::optional here -std::string TCPConsole::extract_next_line() -{ - char linebuf[1024]; - - std::istream is(&recv_buffer_); - is.getline(linebuf, sizeof(linebuf)); - if (is.good()) { - return linebuf; - } - - return ""; -} - -void TCPConsole::handle_read( - const boost::system::error_code& ec, - std::size_t bytes_transferred) -{ - error_code_ = ec; - - if (ec) { - BOOST_LOG_TRIVIAL(error) << boost::format("TCPConsole: Can't read from %1%:%2%: %3%") - % host_name_ - % port_name_ - % ec.message(); - - io_context_.stop(); - } else { - std::string line = extract_next_line(); - boost::trim(line); - - BOOST_LOG_TRIVIAL(debug) << boost::format("TCPConsole: received '%3%' from %1%:%2%") - % host_name_ - % port_name_ - % line; - - boost::to_lower(line); - - if (line == done_string_) { - transmit_next_command(); - } else { - wait_next_line(); - } - } -} - -void TCPConsole::handle_write( - const boost::system::error_code& ec, - std::size_t) -{ - error_code_ = ec; - if (ec) { - BOOST_LOG_TRIVIAL(error) << boost::format("TCPConsole: Can't write to %1%:%2%: %3%") - % host_name_ - % port_name_ - % ec.message(); - - io_context_.stop(); - } else { - wait_next_line(); - } -} - -void TCPConsole::handle_connect(const boost::system::error_code& ec) -{ - error_code_ = ec; - - if (ec) { - BOOST_LOG_TRIVIAL(error) << boost::format("TCPConsole: Can't connect to %1%:%2%: %3%") - % host_name_ - % port_name_ - % ec.message(); - - io_context_.stop(); - } else { - BOOST_LOG_TRIVIAL(info) << boost::format("TCPConsole: connected to %1%:%2%") - % host_name_ - % port_name_; - - - transmit_next_command(); - } -} - -bool TCPConsole::run_queue() -{ - try { - // TODO: Add more resets and initializations after previous run - - auto endpoints = resolver_.resolve(host_name_, port_name_); - - socket_.async_connect(endpoints->endpoint(), - boost::bind(&TCPConsole::handle_connect, this, _1) - ); - - // TODO: Add error and timeout processing - io_context_.restart(); - while (!io_context_.stopped()) { - BOOST_LOG_TRIVIAL(debug) << ".\n"; - if (error_code_) { - io_context_.stop(); + boost::asio::async_write( + socket_, + data, + boost::bind(&TCPConsole::handle_write, this, _1, _2) + ); } - io_context_.run_for(boost::asio::chrono::milliseconds(100)); + + void TCPConsole::wait_next_line() + { + boost::asio::async_read_until( + socket_, + recv_buffer_, + newline_, + boost::bind(&TCPConsole::handle_read, this, _1, _2) + ); + } + + // TODO: Use std::optional here + std::string TCPConsole::extract_next_line() + { + char linebuf[1024]; + + std::istream is(&recv_buffer_); + is.getline(linebuf, sizeof(linebuf)); + if (is.good()) { + return linebuf; + } + + return ""; + } + + void TCPConsole::handle_read( + const boost::system::error_code& ec, + std::size_t bytes_transferred) + { + error_code_ = ec; + + if (ec) { + BOOST_LOG_TRIVIAL(error) << boost::format("TCPConsole: Can't read from %1%:%2%: %3%") + % host_name_ + % port_name_ + % ec.message(); + + io_context_.stop(); + } + else { + std::string line = extract_next_line(); + boost::trim(line); + + BOOST_LOG_TRIVIAL(debug) << boost::format("TCPConsole: received '%3%' from %1%:%2%") + % host_name_ + % port_name_ + % line; + + boost::to_lower(line); + + if (line == done_string_) { + transmit_next_command(); + } + else { + wait_next_line(); + } + } + } + + void TCPConsole::handle_write( + const boost::system::error_code& ec, + std::size_t) + { + error_code_ = ec; + if (ec) { + BOOST_LOG_TRIVIAL(error) << boost::format("TCPConsole: Can't write to %1%:%2%: %3%") + % host_name_ + % port_name_ + % ec.message(); + + io_context_.stop(); + } + else { + wait_next_line(); + } + } + + void TCPConsole::handle_connect(const boost::system::error_code& ec) + { + error_code_ = ec; + + if (ec) { + BOOST_LOG_TRIVIAL(error) << boost::format("TCPConsole: Can't connect to %1%:%2%: %3%") + % host_name_ + % port_name_ + % ec.message(); + + io_context_.stop(); + } + else { + BOOST_LOG_TRIVIAL(info) << boost::format("TCPConsole: connected to %1%:%2%") + % host_name_ + % port_name_; + + + transmit_next_command(); + } + } + + bool TCPConsole::run_queue() + { + try { + // TODO: Add more resets and initializations after previous run + + auto endpoints = resolver_.resolve(host_name_, port_name_); + + socket_.async_connect(endpoints->endpoint(), + boost::bind(&TCPConsole::handle_connect, this, _1) + ); + + // TODO: Add error and timeout processing + io_context_.restart(); + while (!io_context_.stopped()) { + BOOST_LOG_TRIVIAL(debug) << ".\n"; + if (error_code_) { + io_context_.stop(); + } + io_context_.run_for(boost::asio::chrono::milliseconds(100)); + } + + // Socket is not closed automatically by boost + socket_.close(); + + if (error_code_) { + // We expect that message is logged in handler + return false; + } + + // It's expected to have empty queue after successful exchange + if (!cmd_queue_.empty()) { + BOOST_LOG_TRIVIAL(error) << "TCPConsole: command queue is not empty after end of exchange"; + return false; + } + } + catch (std::exception& e) + { + BOOST_LOG_TRIVIAL(error) << boost::format("TCPConsole: Exception while talking with %1%:%2%: %3%") + % host_name_ + % port_name_ + % e.what(); + + return false; + } + + return true; + } + + } - - // Socket is not closed automatically by boost - socket_.close(); - - if (error_code_) { - // We expect that message is logged in handler - return false; - } - - // It's expected to have empty queue after successful exchange - if (!cmd_queue_.empty()) { - BOOST_LOG_TRIVIAL(error) << "TCPConsole: command queue is not empty after end of exchange"; - return false; - } - } - catch (std::exception& e) - { - BOOST_LOG_TRIVIAL(error) << boost::format("TCPConsole: Exception while talking with %1%:%2%: %3%") - % host_name_ - % port_name_ - % e.what(); - - return false; - } - - return true; -} - - -} } diff --git a/src/slic3r/Utils/TCPConsole.hpp b/src/slic3r/Utils/TCPConsole.hpp index 6ff65ad8a..aa3b7da6f 100644 --- a/src/slic3r/Utils/TCPConsole.hpp +++ b/src/slic3r/Utils/TCPConsole.hpp @@ -8,74 +8,74 @@ #include namespace Slic3r { -namespace Utils { + namespace Utils { -const char * default_newline = "\n"; -const char * default_done_string = "ok"; + const char* default_newline = "\n"; + const char* default_done_string = "ok"; -using boost::asio::ip::tcp; + using boost::asio::ip::tcp; -class TCPConsole -{ -public: - TCPConsole(): resolver_(io_context_), socket_(io_context_), newline_(default_newline), done_string_(default_done_string) {} + class TCPConsole + { + public: + TCPConsole() : resolver_(io_context_), socket_(io_context_), newline_(default_newline), done_string_(default_done_string) {} - TCPConsole(const std::string &host_name, const std::string &port_name): - resolver_(io_context_), socket_(io_context_), newline_(default_newline), done_string_(default_done_string) - { - set_remote(host_name, port_name); - } - ~TCPConsole(){} + TCPConsole(const std::string& host_name, const std::string& port_name) : + resolver_(io_context_), socket_(io_context_), newline_(default_newline), done_string_(default_done_string) + { + set_remote(host_name, port_name); + } + ~TCPConsole() {} - void set_line_delimiter(const std::string &newline) { - newline_ = newline; - } - void set_command_done_string(const std::string &done_string) { - done_string_ = done_string; - } + void set_line_delimiter(const std::string& newline) { + newline_ = newline; + } + void set_command_done_string(const std::string& done_string) { + done_string_ = done_string; + } - void set_remote(const std::string &host_name, const std::string &port_name) - { - host_name_ = host_name; - port_name_ = port_name; - } + void set_remote(const std::string& host_name, const std::string& port_name) + { + host_name_ = host_name; + port_name_ = port_name; + } - bool enqueue_cmd(const std::string &cmd) { - // TODO: Add multithread protection to queue - cmd_queue_.push_back(cmd); - return true; - } + bool enqueue_cmd(const std::string& cmd) { + // TODO: Add multithread protection to queue + cmd_queue_.push_back(cmd); + return true; + } - bool run_queue(); - std::string error_message() { - return error_code_.message(); - } + bool run_queue(); + std::string error_message() { + return error_code_.message(); + } -private: - void handle_connect(const boost::system::error_code& ec); - void handle_read(const boost::system::error_code& ec, std::size_t bytes_transferred); - void handle_write(const boost::system::error_code& ec, std::size_t bytes_transferred); + private: + void handle_connect(const boost::system::error_code& ec); + void handle_read(const boost::system::error_code& ec, std::size_t bytes_transferred); + void handle_write(const boost::system::error_code& ec, std::size_t bytes_transferred); - void transmit_next_command(); - void wait_next_line(); - std::string extract_next_line(); + void transmit_next_command(); + void wait_next_line(); + std::string extract_next_line(); - std::string host_name_; - std::string port_name_; - std::string newline_; - std::string done_string_; + std::string host_name_; + std::string port_name_; + std::string newline_; + std::string done_string_; - std::list cmd_queue_; + std::list cmd_queue_; - boost::asio::io_context io_context_; - tcp::resolver resolver_; - tcp::socket socket_; - boost::asio::streambuf recv_buffer_; + boost::asio::io_context io_context_; + tcp::resolver resolver_; + tcp::socket socket_; + boost::asio::streambuf recv_buffer_; - boost::system::error_code error_code_; -}; + boost::system::error_code error_code_; + }; -} // Utils + } // Utils } // Slic3r #endif From bb928f6ef7cdc3321834f51765c16166f92ee41b Mon Sep 17 00:00:00 2001 From: Sergey Kovalev Date: Tue, 29 Dec 2020 01:12:04 +0700 Subject: [PATCH 5/8] Multiple fixes for building --- src/slic3r/Utils/MKS.cpp | 6 +++++- src/slic3r/Utils/MKS.hpp | 3 +-- src/slic3r/Utils/TCPConsole.cpp | 14 +++++++++++++- src/slic3r/Utils/TCPConsole.hpp | 12 ++---------- 4 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/slic3r/Utils/MKS.cpp b/src/slic3r/Utils/MKS.cpp index 1a60c5a3e..97cdbfffa 100644 --- a/src/slic3r/Utils/MKS.cpp +++ b/src/slic3r/Utils/MKS.cpp @@ -32,13 +32,15 @@ namespace pt = boost::property_tree; namespace Slic3r { MKS::MKS(DynamicPrintConfig* config) : - host(config->opt_string("print_host")), console(config->opt_string("print_host"), "8080") + host(config->opt_string("print_host")), console_port("8080") {} const char* MKS::get_name() const { return "MKS"; } bool MKS::test(wxString& msg) const { + Utils::TCPConsole console(host, console_port); + console.enqueue_cmd("M105"); bool ret = console.run_queue(); @@ -131,6 +133,8 @@ namespace Slic3r { // TODO: Inspect reasons std::this_thread::sleep_for(std::chrono::milliseconds(1500)); + Utils::TCPConsole console(host, console_port); + console.enqueue_cmd(std::string("M23 ") + filename); console.enqueue_cmd("M24"); diff --git a/src/slic3r/Utils/MKS.hpp b/src/slic3r/Utils/MKS.hpp index 67c655293..6e0aad58b 100644 --- a/src/slic3r/Utils/MKS.hpp +++ b/src/slic3r/Utils/MKS.hpp @@ -8,7 +8,6 @@ #include "TCPConsole.hpp" namespace Slic3r { - class DynamicPrintConfig; class Http; @@ -31,7 +30,7 @@ namespace Slic3r { private: std::string host; - Utils::TCPConsole console; + std::string console_port; std::string get_upload_url(const std::string& filename) const; std::string timestamp_str() const; diff --git a/src/slic3r/Utils/TCPConsole.cpp b/src/slic3r/Utils/TCPConsole.cpp index bea991945..17a37ef7c 100644 --- a/src/slic3r/Utils/TCPConsole.cpp +++ b/src/slic3r/Utils/TCPConsole.cpp @@ -12,7 +12,7 @@ #include #include -#include +#include "TCPConsole.hpp" using boost::asio::steady_timer; using boost::asio::ip::tcp; @@ -20,6 +20,18 @@ using boost::asio::ip::tcp; namespace Slic3r { namespace Utils { + const char* default_newline = "\n"; + const char* default_done_string = "ok"; + + TCPConsole::TCPConsole() : resolver_(io_context_), socket_(io_context_), newline_(default_newline), done_string_(default_done_string) {} + + TCPConsole::TCPConsole(const std::string& host_name, const std::string& port_name) : + resolver_(io_context_), socket_(io_context_), newline_(default_newline), done_string_(default_done_string) + { + set_remote(host_name, port_name); + } + + void TCPConsole::transmit_next_command() { if (cmd_queue_.empty()) { diff --git a/src/slic3r/Utils/TCPConsole.hpp b/src/slic3r/Utils/TCPConsole.hpp index aa3b7da6f..82d850299 100644 --- a/src/slic3r/Utils/TCPConsole.hpp +++ b/src/slic3r/Utils/TCPConsole.hpp @@ -10,21 +10,13 @@ namespace Slic3r { namespace Utils { - const char* default_newline = "\n"; - const char* default_done_string = "ok"; - using boost::asio::ip::tcp; class TCPConsole { public: - TCPConsole() : resolver_(io_context_), socket_(io_context_), newline_(default_newline), done_string_(default_done_string) {} - - TCPConsole(const std::string& host_name, const std::string& port_name) : - resolver_(io_context_), socket_(io_context_), newline_(default_newline), done_string_(default_done_string) - { - set_remote(host_name, port_name); - } + TCPConsole(); + TCPConsole(const std::string& host_name, const std::string& port_name); ~TCPConsole() {} void set_line_delimiter(const std::string& newline) { From fbe90b55346dac8af06bc1194597a0724d2580f1 Mon Sep 17 00:00:00 2001 From: Sergey Kovalev Date: Tue, 29 Dec 2020 04:50:52 +0700 Subject: [PATCH 6/8] Add timeout/errors management, multiple fixes --- src/slic3r/Utils/MKS.cpp | 31 ++++++++------------ src/slic3r/Utils/MKS.hpp | 1 - src/slic3r/Utils/TCPConsole.cpp | 52 +++++++++++++++++++++++---------- src/slic3r/Utils/TCPConsole.hpp | 19 ++++++++++++ 4 files changed, 68 insertions(+), 35 deletions(-) diff --git a/src/slic3r/Utils/MKS.cpp b/src/slic3r/Utils/MKS.cpp index 97cdbfffa..636a0b3b2 100644 --- a/src/slic3r/Utils/MKS.cpp +++ b/src/slic3r/Utils/MKS.cpp @@ -45,7 +45,7 @@ namespace Slic3r { bool ret = console.run_queue(); if (!ret) { - msg = console.error_message(); + msg = wxString::FromUTF8(console.error_message().c_str()); } return ret; @@ -98,25 +98,18 @@ namespace Slic3r { BOOST_LOG_TRIVIAL(error) << boost::format("MKS: Error uploading file: %1%, HTTP %2%, body: `%3%`") % error % status % body; error_fn(format_error(body, error, status)); res = false; - }) - .on_progress([&](Http::Progress progress, bool& cancel) { - prorgess_fn(std::move(progress), cancel); - if (cancel) { - // Upload was canceled - BOOST_LOG_TRIVIAL(info) << "MKS: Upload canceled"; - res = false; - } - }) - .perform_sync(); + }) + .on_progress([&](Http::Progress progress, bool& cancel) { + prorgess_fn(std::move(progress), cancel); + if (cancel) { + // Upload was canceled + BOOST_LOG_TRIVIAL(info) << "MKS: Upload canceled"; + res = false; + } + }).perform_sync(); - if (res && upload_data.start_print) { - wxString msg; - if (!start_print(msg, upload_data.upload_path.string())) { - error_fn(wxString("Can't start printing: ") + msg); - } - } - return res; + return res; } std::string MKS::get_upload_url(const std::string& filename) const @@ -141,7 +134,7 @@ namespace Slic3r { bool ret = console.run_queue(); if (!ret) { - msg = console.error_message(); + msg = wxString::FromUTF8(console.error_message().c_str()); } return ret; diff --git a/src/slic3r/Utils/MKS.hpp b/src/slic3r/Utils/MKS.hpp index 6e0aad58b..feddd17d8 100644 --- a/src/slic3r/Utils/MKS.hpp +++ b/src/slic3r/Utils/MKS.hpp @@ -33,7 +33,6 @@ namespace Slic3r { std::string console_port; std::string get_upload_url(const std::string& filename) const; - std::string timestamp_str() const; bool start_print(wxString& msg, const std::string& filename) const; int get_err_code_from_body(const std::string& body) const; }; diff --git a/src/slic3r/Utils/TCPConsole.cpp b/src/slic3r/Utils/TCPConsole.cpp index 17a37ef7c..edbfd8cde 100644 --- a/src/slic3r/Utils/TCPConsole.cpp +++ b/src/slic3r/Utils/TCPConsole.cpp @@ -20,17 +20,17 @@ using boost::asio::ip::tcp; namespace Slic3r { namespace Utils { - const char* default_newline = "\n"; - const char* default_done_string = "ok"; - - TCPConsole::TCPConsole() : resolver_(io_context_), socket_(io_context_), newline_(default_newline), done_string_(default_done_string) {} - - TCPConsole::TCPConsole(const std::string& host_name, const std::string& port_name) : - resolver_(io_context_), socket_(io_context_), newline_(default_newline), done_string_(default_done_string) + TCPConsole::TCPConsole() : resolver_(io_context_), socket_(io_context_) { - set_remote(host_name, port_name); + set_defaults(); } + TCPConsole::TCPConsole(const std::string& host_name, const std::string& port_name) : + resolver_(io_context_), socket_(io_context_) + { + set_defaults(); + set_remote(host_name, port_name); + } void TCPConsole::transmit_next_command() { @@ -47,17 +47,20 @@ namespace Slic3r { % port_name_ % cmd; - auto data = boost::asio::buffer(cmd + newline_); + send_buffer_ = cmd + newline_; + + set_deadline_in(write_timeout_); boost::asio::async_write( socket_, - data, + boost::asio::buffer(send_buffer_), boost::bind(&TCPConsole::handle_write, this, _1, _2) ); } void TCPConsole::wait_next_line() { + set_deadline_in(read_timeout_); boost::asio::async_read_until( socket_, recv_buffer_, @@ -145,6 +148,7 @@ namespace Slic3r { io_context_.stop(); } else { + is_connected_ = true; BOOST_LOG_TRIVIAL(info) << boost::format("TCPConsole: connected to %1%:%2%") % host_name_ % port_name_; @@ -154,10 +158,23 @@ namespace Slic3r { } } + void TCPConsole::set_deadline_in(boost::chrono::steady_clock::duration d) + { + deadline_ = boost::chrono::steady_clock::now() + d; + } + bool TCPConsole::is_deadline_over() + { + return deadline_ < boost::chrono::steady_clock::now(); + } + bool TCPConsole::run_queue() { + auto now = boost::chrono::steady_clock::now(); try { - // TODO: Add more resets and initializations after previous run + // TODO: Add more resets and initializations after previous run (reset() method?..) + set_deadline_in(connect_timeout_); + is_connected_ = false; + io_context_.restart(); auto endpoints = resolver_.resolve(host_name_, port_name_); @@ -165,16 +182,21 @@ namespace Slic3r { boost::bind(&TCPConsole::handle_connect, this, _1) ); - // TODO: Add error and timeout processing - io_context_.restart(); - while (!io_context_.stopped()) { - BOOST_LOG_TRIVIAL(debug) << ".\n"; + // Loop until we get any reasonable result. Negative result is also result. + // TODO: Rewrite to more graceful way using deadlime_timer + bool timeout = false; + while (!(timeout = is_deadline_over()) && !io_context_.stopped()) { if (error_code_) { io_context_.stop(); } io_context_.run_for(boost::asio::chrono::milliseconds(100)); } + // Override error message if timeout is set + if (timeout) { + error_code_ = make_error_code(boost::asio::error::timed_out); + } + // Socket is not closed automatically by boost socket_.close(); diff --git a/src/slic3r/Utils/TCPConsole.hpp b/src/slic3r/Utils/TCPConsole.hpp index 82d850299..507325db6 100644 --- a/src/slic3r/Utils/TCPConsole.hpp +++ b/src/slic3r/Utils/TCPConsole.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -19,6 +20,15 @@ namespace Slic3r { TCPConsole(const std::string& host_name, const std::string& port_name); ~TCPConsole() {} + void set_defaults() + { + newline_ = "\n"; + done_string_ = "ok"; + connect_timeout_ = boost::chrono::milliseconds(5000); + write_timeout_ = boost::chrono::milliseconds(10000); + read_timeout_ = boost::chrono::milliseconds(10000); + } + void set_line_delimiter(const std::string& newline) { newline_ = newline; } @@ -52,10 +62,16 @@ namespace Slic3r { void wait_next_line(); std::string extract_next_line(); + void set_deadline_in(boost::chrono::steady_clock::duration); + bool is_deadline_over(); + std::string host_name_; std::string port_name_; std::string newline_; std::string done_string_; + boost::chrono::steady_clock::duration connect_timeout_; + boost::chrono::steady_clock::duration write_timeout_; + boost::chrono::steady_clock::duration read_timeout_; std::list cmd_queue_; @@ -63,8 +79,11 @@ namespace Slic3r { tcp::resolver resolver_; tcp::socket socket_; boost::asio::streambuf recv_buffer_; + std::string send_buffer_; + bool is_connected_; boost::system::error_code error_code_; + boost::chrono::steady_clock::time_point deadline_; }; } // Utils From a0f0f329c858b2ef7ddce1abcf88e5fe31521c2c Mon Sep 17 00:00:00 2001 From: Sergey Kovalev Date: Wed, 24 Nov 2021 00:18:55 +0700 Subject: [PATCH 7/8] Fix chrono --- src/slic3r/Utils/TCPConsole.cpp | 8 ++++---- src/slic3r/Utils/TCPConsole.hpp | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/slic3r/Utils/TCPConsole.cpp b/src/slic3r/Utils/TCPConsole.cpp index edbfd8cde..bb834bb5f 100644 --- a/src/slic3r/Utils/TCPConsole.cpp +++ b/src/slic3r/Utils/TCPConsole.cpp @@ -158,18 +158,18 @@ namespace Slic3r { } } - void TCPConsole::set_deadline_in(boost::chrono::steady_clock::duration d) + void TCPConsole::set_deadline_in(std::chrono::steady_clock::duration d) { - deadline_ = boost::chrono::steady_clock::now() + d; + deadline_ = std::chrono::steady_clock::now() + d; } bool TCPConsole::is_deadline_over() { - return deadline_ < boost::chrono::steady_clock::now(); + return deadline_ < std::chrono::steady_clock::now(); } bool TCPConsole::run_queue() { - auto now = boost::chrono::steady_clock::now(); + auto now = std::chrono::steady_clock::now(); try { // TODO: Add more resets and initializations after previous run (reset() method?..) set_deadline_in(connect_timeout_); diff --git a/src/slic3r/Utils/TCPConsole.hpp b/src/slic3r/Utils/TCPConsole.hpp index 507325db6..20472750b 100644 --- a/src/slic3r/Utils/TCPConsole.hpp +++ b/src/slic3r/Utils/TCPConsole.hpp @@ -24,9 +24,9 @@ namespace Slic3r { { newline_ = "\n"; done_string_ = "ok"; - connect_timeout_ = boost::chrono::milliseconds(5000); - write_timeout_ = boost::chrono::milliseconds(10000); - read_timeout_ = boost::chrono::milliseconds(10000); + connect_timeout_ = std::chrono::milliseconds(5000); + write_timeout_ = std::chrono::milliseconds(10000); + read_timeout_ = std::chrono::milliseconds(10000); } void set_line_delimiter(const std::string& newline) { @@ -62,16 +62,16 @@ namespace Slic3r { void wait_next_line(); std::string extract_next_line(); - void set_deadline_in(boost::chrono::steady_clock::duration); + void set_deadline_in(std::chrono::steady_clock::duration); bool is_deadline_over(); std::string host_name_; std::string port_name_; std::string newline_; std::string done_string_; - boost::chrono::steady_clock::duration connect_timeout_; - boost::chrono::steady_clock::duration write_timeout_; - boost::chrono::steady_clock::duration read_timeout_; + std::chrono::steady_clock::duration connect_timeout_; + std::chrono::steady_clock::duration write_timeout_; + std::chrono::steady_clock::duration read_timeout_; std::list cmd_queue_; @@ -83,7 +83,7 @@ namespace Slic3r { bool is_connected_; boost::system::error_code error_code_; - boost::chrono::steady_clock::time_point deadline_; + std::chrono::steady_clock::time_point deadline_; }; } // Utils From 5fe529ffbc8ff6034f16f7520423c58c56517bb3 Mon Sep 17 00:00:00 2001 From: Sergey Kovalev Date: Wed, 24 Nov 2021 00:49:53 +0700 Subject: [PATCH 8/8] Add missing mapping --- src/libslic3r/PrintConfig.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 85cae5c1b..e37edec84 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -72,7 +72,8 @@ static t_config_enum_values s_keys_map_PrintHostType { { "duet", htDuet }, { "flashair", htFlashAir }, { "astrobox", htAstroBox }, - { "repetier", htRepetier } + { "repetier", htRepetier }, + { "mks", htMKS } }; CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(PrintHostType)