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 {