diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 0c7a3a5bff..21c5ffe48f 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -103,7 +103,8 @@ static t_config_enum_values s_keys_map_PrintHostType { { "astrobox", htAstroBox }, { "repetier", htRepetier }, { "mks", htMKS }, - { "obico", htObico } + { "obico", htObico }, + { "flashforge", htFlashforge} }; CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(PrintHostType) @@ -3066,6 +3067,7 @@ def = this->add("filament_loading_speed", coFloats); def->enum_values.push_back("repetier"); def->enum_values.push_back("mks"); def->enum_values.push_back("obico"); + def->enum_values.push_back("flashforge"); def->enum_labels.push_back("PrusaLink"); def->enum_labels.push_back("PrusaConnect"); def->enum_labels.push_back("Octo/Klipper"); @@ -3075,6 +3077,7 @@ def = this->add("filament_loading_speed", coFloats); def->enum_labels.push_back("Repetier"); def->enum_labels.push_back("MKS"); def->enum_labels.push_back("Obico"); + def->enum_labels.push_back("Flashforge"); 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 94a32e2892..f99e4c952b 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -59,7 +59,7 @@ enum class FuzzySkinType { }; enum PrintHostType { - htPrusaLink, htPrusaConnect, htOctoPrint, htDuet, htFlashAir, htAstroBox, htRepetier, htMKS, htObico + htPrusaLink, htPrusaConnect, htOctoPrint, htDuet, htFlashAir, htAstroBox, htRepetier, htMKS, htObico, htFlashforge }; enum AuthorizationType { diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 0b1526f1ee..3250e969ae 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -508,6 +508,8 @@ set(SLIC3R_GUI_SOURCES Utils/PrintHost.hpp Utils/Serial.cpp Utils/Serial.hpp + Utils/SerialMessageType.hpp + Utils/SerialMessage.hpp Utils/MKS.cpp Utils/MKS.hpp Utils/WxFontUtils.cpp @@ -528,6 +530,8 @@ set(SLIC3R_GUI_SOURCES GUI/PrinterCloudAuthDialog.hpp Utils/Obico.cpp Utils/Obico.hpp + Utils/Flashforge.cpp + Utils/Flashforge.hpp ) if (WIN32) @@ -633,4 +637,4 @@ if (UNIX AND NOT APPLE) endif () # Add a definition so that we can tell we are compiling slic3r. -target_compile_definitions(libslic3r_gui PRIVATE SLIC3R_CURRENTLY_COMPILING_GUI_MODULE) \ No newline at end of file +target_compile_definitions(libslic3r_gui PRIVATE SLIC3R_CURRENTLY_COMPILING_GUI_MODULE) diff --git a/src/slic3r/GUI/PhysicalPrinterDialog.cpp b/src/slic3r/GUI/PhysicalPrinterDialog.cpp index 7b75464496..d746f96f01 100644 --- a/src/slic3r/GUI/PhysicalPrinterDialog.cpp +++ b/src/slic3r/GUI/PhysicalPrinterDialog.cpp @@ -513,6 +513,11 @@ void PhysicalPrinterDialog::update(bool printer_change) } } } + + if (opt->value == htFlashforge) { + m_optgroup->hide_field("printhost_apikey"); + m_optgroup->hide_field("printhost_authorization_type"); + } } else { m_optgroup->set_value("host_type", int(PrintHostType::htOctoPrint), false); diff --git a/src/slic3r/Utils/Flashforge.cpp b/src/slic3r/Utils/Flashforge.cpp new file mode 100644 index 0000000000..068b1432d7 --- /dev/null +++ b/src/slic3r/Utils/Flashforge.cpp @@ -0,0 +1,135 @@ +#include "Flashforge.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" +#include "TCPConsole.hpp" +#include "SerialMessage.hpp" +#include "SerialMessageType.hpp" + +namespace fs = boost::filesystem; +namespace pt = boost::property_tree; + +namespace Slic3r { + +Flashforge::Flashforge(DynamicPrintConfig* config) : m_host(config->opt_string("print_host")), m_console_port("8899") +{ +} + +const char* Flashforge::get_name() const { return "Flashforge"; } + +bool Flashforge::test(wxString& msg) const +{ + BOOST_LOG_TRIVIAL(debug) << boost::format("[Flashforge] testing connection"); + // Utils::TCPConsole console(m_host, m_console_port); + Utils::TCPConsole client(m_host, m_console_port); + client.enqueue_cmd(controlCommand); + bool res = client.run_queue(); + if (!res) { + msg = wxString::FromUTF8(client.error_message().c_str()); + BOOST_LOG_TRIVIAL(info) << boost::format("[Flashforge] testing connection failed"); + } else { + BOOST_LOG_TRIVIAL(info) << boost::format("[Flashforge] testing connection success"); + } + return res; +} + +wxString Flashforge::get_test_ok_msg() const { return _(L("Connection to Flashforge works correctly.")); } + +wxString Flashforge::get_test_failed_msg(wxString& msg) const +{ + return GUI::from_u8((boost::format("%s: %s") % _utf8(L("Could not connect to Flashforge")) % std::string(msg.ToUTF8())).str()); +} + +bool Flashforge::upload(PrintHostUpload upload_data, ProgressFn progress_fn, ErrorFn error_fn, InfoFn info_fn) const +{ + bool res = true; + + Utils::TCPConsole client(m_host, m_console_port); + client.enqueue_cmd(controlCommand); + + client.enqueue_cmd(connect5MCommand); + + client.enqueue_cmd(statusCommand); + wxString errormsg; + try { + std::ifstream newfile; + newfile.open(upload_data.source_path.c_str(), std::ios::binary); // open a file to perform read operation using file object + if (newfile.is_open()) { // checking whether the file is open + BOOST_LOG_TRIVIAL(info) << boost::format("[Flashforge] Reading file..."); + newfile.seekg(0, std::ios::end); + std::ifstream::pos_type pos = newfile.tellg(); + + std::vector result(pos); + + newfile.seekg(0, std::ios::beg); + newfile.read(&result[0], pos); + BOOST_LOG_TRIVIAL(info) << boost::format("[Flashforge] Reading file...done size is %1%") % result.size(); + + Slic3r::Utils::SerialMessage fileuploadCommand = + {(boost::format("~M28 %1% 0:/user/%2%") % result.size() % upload_data.upload_path.generic_string()).str(), + Slic3r::Utils::Command}; + client.enqueue_cmd(fileuploadCommand); + Slic3r::Utils::SerialMessage dataCommand = {std::string(result.begin(), result.end()), Slic3r::Utils::Data}; + client.enqueue_cmd(dataCommand); + newfile.close(); // close the file object. + BOOST_LOG_TRIVIAL(info) << boost::format("[Flashforge] Sent %1% ") % result.size(); + } + BOOST_LOG_TRIVIAL(info) << boost::format("[Flashforge] Sending file save command "); + client.enqueue_cmd(saveFileCommand); + if (upload_data.post_action == PrintHostPostUploadAction::StartPrint) { + BOOST_LOG_TRIVIAL(info) << boost::format("[Flashforge] Starting print %1%") % upload_data.upload_path.string(); + Slic3r::Utils::SerialMessage startPrintCommand = {(boost::format("~M23 0:/user/%1%") % upload_data.upload_path.string()).str(), + Slic3r::Utils::Command}; + client.enqueue_cmd(startPrintCommand); + } + + res = client.run_queue(); + + if (!res) { + BOOST_LOG_TRIVIAL(info) << boost::format("[Flashforge] error %1%") % client.error_message().c_str(); + errormsg = wxString::FromUTF8(client.error_message().c_str()); + } + if (!res) { + error_fn(std::move(errormsg)); + } + } catch (const std::exception& e) { + BOOST_LOG_TRIVIAL(info) << boost::format("[Flashforge] error %1%") % e.what(); + errormsg = wxString::FromUTF8(e.what()); + error_fn(std::move(errormsg)); + } + + return res; +} + +int Flashforge::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); +} + +} // namespace Slic3r diff --git a/src/slic3r/Utils/Flashforge.hpp b/src/slic3r/Utils/Flashforge.hpp new file mode 100644 index 0000000000..18776ea1e7 --- /dev/null +++ b/src/slic3r/Utils/Flashforge.hpp @@ -0,0 +1,45 @@ +#ifndef slic3r_FlashForge_hpp_ +#define slic3r_FlashForge_hpp_ + +#include +#include +#include "PrintHost.hpp" +#include "SerialMessage.hpp" +#include "SerialMessageType.hpp" +#include "../../libslic3r/PrintConfig.hpp" + +namespace Slic3r { +class DynamicPrintConfig; +class Http; + +class Flashforge : public PrintHost +{ +public: + explicit Flashforge(DynamicPrintConfig *config); + ~Flashforge() 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, InfoFn info_fn) const override; + bool has_auto_discovery() const override { return false; } + bool can_test() const override { return true; } + PrintHostPostUploadActions get_post_upload_actions() const override { return PrintHostPostUploadAction::StartPrint; } + std::string get_host() const override { return m_host; } + +private: + std::string m_host; + std::string m_console_port; + Slic3r::Utils::SerialMessage controlCommand = {"~M601 S1\r\n",Slic3r::Utils::Command}; + Slic3r::Utils::SerialMessage connect5MCommand = {"~M640\r\n",Slic3r::Utils::Command}; + Slic3r::Utils::SerialMessage connectGuiderCommand = {"~M650\r\n",Slic3r::Utils::Command}; + Slic3r::Utils::SerialMessage statusCommand = {"~M119\r\n",Slic3r::Utils::Command}; + Slic3r::Utils::SerialMessage saveFileCommand = {"~M29\r\n",Slic3r::Utils::Command}; + int get_err_code_from_body(const std::string &body) const; +}; + +} // namespace Slic3r + +#endif diff --git a/src/slic3r/Utils/MKS.cpp b/src/slic3r/Utils/MKS.cpp index 109283fc66..7826788703 100644 --- a/src/slic3r/Utils/MKS.cpp +++ b/src/slic3r/Utils/MKS.cpp @@ -25,6 +25,8 @@ #include "slic3r/GUI/I18N.hpp" #include "slic3r/GUI/MsgDialog.hpp" #include "Http.hpp" +#include "SerialMessage.hpp" +#include "SerialMessageType.hpp" namespace fs = boost::filesystem; namespace pt = boost::property_tree; @@ -40,8 +42,8 @@ const char* MKS::get_name() const { return "MKS"; } bool MKS::test(wxString& msg) const { Utils::TCPConsole console(m_host, m_console_port); - - console.enqueue_cmd("M105"); + Slic3r::Utils::SerialMessage s("M105", Slic3r::Utils::Command); + console.enqueue_cmd(s); bool ret = console.run_queue(); if (!ret) @@ -126,9 +128,10 @@ bool MKS::start_print(wxString& msg, const std::string& filename) const std::this_thread::sleep_for(std::chrono::milliseconds(1500)); Utils::TCPConsole console(m_host, m_console_port); - - console.enqueue_cmd(std::string("M23 ") + filename); - console.enqueue_cmd("M24"); + Slic3r::Utils::SerialMessage s(std::string("M23 ") + filename, Slic3r::Utils::Command); + console.enqueue_cmd(s); + s.message = "M24"; + console.enqueue_cmd(s); bool ret = console.run_queue(); diff --git a/src/slic3r/Utils/PrintHost.cpp b/src/slic3r/Utils/PrintHost.cpp index 7b66f40800..f20c99ad50 100644 --- a/src/slic3r/Utils/PrintHost.cpp +++ b/src/slic3r/Utils/PrintHost.cpp @@ -21,6 +21,7 @@ #include "MKS.hpp" #include "../GUI/PrintHostDialogs.hpp" #include "Obico.hpp" +#include "Flashforge.hpp" namespace fs = boost::filesystem; using boost::optional; @@ -56,6 +57,7 @@ PrintHost* PrintHost::get_print_host(DynamicPrintConfig *config) case htPrusaConnect: return new PrusaConnect(config); case htMKS: return new MKS(config); case htObico: return new Obico(config); + case htFlashforge: return new Flashforge(config); default: return nullptr; } } else { diff --git a/src/slic3r/Utils/SerialMessage.hpp b/src/slic3r/Utils/SerialMessage.hpp new file mode 100644 index 0000000000..3cac8b85f9 --- /dev/null +++ b/src/slic3r/Utils/SerialMessage.hpp @@ -0,0 +1,22 @@ +#ifndef SERIALMESSAGE_H +#define SERIALMESSAGE_H + +#include +#include "SerialMessageType.hpp" + +namespace Slic3r { namespace Utils { + + struct SerialMessage + { + std::string message; + enum SerialMessageType messageType; + SerialMessage(std::string m, SerialMessageType mT) + { + message = m; + messageType = mT; + } + }; + + +}} +#endif \ No newline at end of file diff --git a/src/slic3r/Utils/SerialMessageType.hpp b/src/slic3r/Utils/SerialMessageType.hpp new file mode 100644 index 0000000000..ba4a1aa8ef --- /dev/null +++ b/src/slic3r/Utils/SerialMessageType.hpp @@ -0,0 +1,9 @@ +#ifndef SERIALMESSAGE_TYPE_H +#define SERIALMESSAGE_TYPE_H + +namespace Slic3r { namespace Utils { + +enum SerialMessageType { Command, Data }; + +}} // namespace Slic3r::Utils +#endif \ No newline at end of file diff --git a/src/slic3r/Utils/TCPConsole.cpp b/src/slic3r/Utils/TCPConsole.cpp index 277e3c0d5c..d76d29fe5c 100644 --- a/src/slic3r/Utils/TCPConsole.cpp +++ b/src/slic3r/Utils/TCPConsole.cpp @@ -13,6 +13,8 @@ #include #include "TCPConsole.hpp" +#include "SerialMessage.hpp" +#include "SerialMessageType.hpp" using boost::asio::steady_timer; using boost::asio::ip::tcp; @@ -27,21 +29,25 @@ void TCPConsole::transmit_next_command() return; } - std::string cmd = m_cmd_queue.front(); + SerialMessage cmd = m_cmd_queue.front(); m_cmd_queue.pop_front(); BOOST_LOG_TRIVIAL(debug) << boost::format("TCPConsole: transmitting '%3%' to %1%:%2%") % m_host_name % m_port_name - % cmd; + % cmd.message; - m_send_buffer = cmd + m_newline; + m_send_buffer = cmd.message; + + if (cmd.messageType == Command) { + m_send_buffer += m_newline; + } set_deadline_in(m_write_timeout); boost::asio::async_write( m_socket, boost::asio::buffer(m_send_buffer), - boost::bind(&TCPConsole::handle_write, this, boost::placeholders::_1, boost::placeholders::_2) + boost::bind(&TCPConsole::handle_write, this, boost::placeholders::_1, boost::placeholders::_2, cmd.messageType) ); } @@ -99,7 +105,7 @@ void TCPConsole::handle_read( void TCPConsole::handle_write( const boost::system::error_code& ec, - std::size_t) + std::size_t, SerialMessageType messageType) { m_error_code = ec; if (ec) { @@ -111,7 +117,12 @@ void TCPConsole::handle_write( m_io_context.stop(); } else { + if(messageType == Command){ wait_next_line(); + } + else{ + transmit_next_command(); + } } } diff --git a/src/slic3r/Utils/TCPConsole.hpp b/src/slic3r/Utils/TCPConsole.hpp index d353634e87..7592e9c7ec 100644 --- a/src/slic3r/Utils/TCPConsole.hpp +++ b/src/slic3r/Utils/TCPConsole.hpp @@ -7,6 +7,7 @@ #include #include #include +#include "SerialMessage.hpp" namespace Slic3r { namespace Utils { @@ -45,7 +46,7 @@ public: m_port_name = port_name; } - bool enqueue_cmd(const std::string& cmd) { + bool enqueue_cmd(const SerialMessage& cmd) { // TODO: Add multithread protection to queue m_cmd_queue.push_back(cmd); return true; @@ -57,7 +58,7 @@ public: 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 handle_write(const boost::system::error_code& ec, std::size_t bytes_transferred, SerialMessageType messageType); void transmit_next_command(); void wait_next_line(); @@ -74,7 +75,7 @@ private: std::chrono::steady_clock::duration m_write_timeout; std::chrono::steady_clock::duration m_read_timeout; - std::deque m_cmd_queue; + std::deque m_cmd_queue; boost::asio::io_context m_io_context; tcp::resolver m_resolver;