OrcaSlicer latest
OrcaSlicer
Loading...
Searching...
No Matches
Slic3r::Flashforge Class Reference

#include </home/runner/work/OrcaSlicer/OrcaSlicer/src/slic3r/Utils/Flashforge.hpp>

Inheritance diagram for Slic3r::Flashforge:
Collaboration diagram for Slic3r::Flashforge:

Public Types

typedef Http::ProgressFn ProgressFn
typedef std::function< void(wxString)> ErrorFn
typedef std::function< void(wxString, wxString)> InfoFn

Public Member Functions

 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
bool can_test () const override
PrintHostPostUploadActions get_post_upload_actions () const override
std::string get_host () const override
bool fetch_material_slots (std::vector< FlashforgeMaterialSlot > &slots, bool *supports_material_station, wxString &msg) const
virtual bool supports_multiple_printers () const
virtual std::string get_sn () const
virtual bool get_groups (wxArrayString &) const
virtual bool get_printers (wxArrayString &) const
virtual bool get_storage (wxArrayString &, wxArrayString &) const
virtual bool is_cloud () const
virtual bool is_logged_in () const
virtual void log_out () const
virtual bool get_login_url (wxString &auth_url) const

Static Public Member Functions

static bool parse_material_slots (const std::string &body, std::vector< FlashforgeMaterialSlot > &slots, bool *supports_material_station)
static bool discover_printers (std::vector< FlashforgeDiscoveredPrinter > &printers, wxString &msg, int timeout_ms=10000, int idle_timeout_ms=1500, int max_retries=3)
static PrintHost * get_print_host (DynamicPrintConfig *config)
static std::string get_print_host_webui (DynamicPrintConfig *config)
static int get_err_code_from_body (const std::string &body)

Protected Member Functions

virtual wxString format_error (const std::string &body, const std::string &error, unsigned status) const

Static Protected Member Functions

static wxString timed_out_message ()

Private Member Functions

bool upload_local_api (PrintHostUpload upload_data, ProgressFn progress_fn, ErrorFn error_fn) const
bool test_local_api (wxString &msg) const
bool request_local_api_json (const std::string &path, const std::string &body, std::string &response_body, wxString &error_msg) const
std::string make_http_url (const std::string &path) const
std::string extract_host_name () const
bool connect (wxString &msg) const
bool start_print (wxString &msg, const std::string &filename) const

Private Attributes

std::string m_host
std::string m_serial_number
std::string m_check_code
std::string m_console_port
const int m_bufferSize
GCodeFlavor m_gcFlavor
Slic3r::Utils::SerialMessage controlCommand = {"~M601 S1\r\n",Slic3r::Utils::Command}
Slic3r::Utils::SerialMessage connectKlipperCommand = {"~M640\r\n",Slic3r::Utils::Command}
Slic3r::Utils::SerialMessage connectLegacyCommand = {"~M650\r\n",Slic3r::Utils::Command}
Slic3r::Utils::SerialMessage nozzlePosCommand = {"~M114\r\n", Slic3r::Utils::Command}
Slic3r::Utils::SerialMessage deviceInfoCommand = {"~M115\r\n", Slic3r::Utils::Command}
Slic3r::Utils::SerialMessage statusCommand = {"~M119\r\n",Slic3r::Utils::Command}
Slic3r::Utils::SerialMessage tempStatusCommand = {"~M105\r\n", Slic3r::Utils::Command}
Slic3r::Utils::SerialMessage printStatusCommand = {"~M27\r\n", Slic3r::Utils::Command}
Slic3r::Utils::SerialMessage saveFileCommand = {"~M29\r\n",Slic3r::Utils::Command}

Detailed Description

Member Typedef Documentation

◆ ErrorFn

typedef std::function<void(wxString )> Slic3r::PrintHost::ErrorFn
inherited

◆ InfoFn

typedef std::function<void(wxString , wxString )> Slic3r::PrintHost::InfoFn
inherited

◆ ProgressFn

Constructor & Destructor Documentation

◆ Flashforge()

Slic3r::Flashforge::Flashforge ( DynamicPrintConfig * config)
explicit
222 : m_host()
224 , m_check_code()
225 , m_console_port("8899")
227 , m_bufferSize(4096) // 4K buffer size
228{
229 m_host = safe_config_string(config, "print_host");
230 m_serial_number = safe_config_string(config, "flashforge_serial_number");
231 m_check_code = safe_config_string(config, "printhost_apikey");
232
233 if (config != nullptr) {
234 if (const auto* gcode_flavor = config->option<ConfigOptionEnum<GCodeFlavor>>("gcode_flavor"); gcode_flavor != nullptr)
235 m_gcFlavor = gcode_flavor->value;
236 }
237}
const int m_bufferSize
Definition Flashforge.hpp:58
std::string m_console_port
Definition Flashforge.hpp:57
std::string m_check_code
Definition Flashforge.hpp:56
GCodeFlavor m_gcFlavor
Definition Flashforge.hpp:59
std::string m_host
Definition Flashforge.hpp:54
std::string m_serial_number
Definition Flashforge.hpp:55
std::string safe_config_string(DynamicPrintConfig *config, const char *key)
Definition Flashforge.cpp:123
@ gcfMarlinLegacy
Definition PrintConfig.hpp:52
zaa_minimize_perimeter_height gcode_flavor((ConfigOptionBool, gcode_skip_config_block))((ConfigOptionFloat

References Slic3r::gcfMarlinLegacy, Slic3r::gcode_flavor(), m_bufferSize, m_check_code, m_console_port, m_gcFlavor, m_host, m_serial_number, and Slic3r::ConfigBase::option().

Here is the call graph for this function:

◆ ~Flashforge()

Slic3r::Flashforge::~Flashforge ( )
overridedefault

Member Function Documentation

◆ can_test()

bool Slic3r::Flashforge::can_test ( ) const
inlineoverridevirtual

Implements Slic3r::PrintHost.

45{ return true; }

◆ connect()

bool Slic3r::Flashforge::connect ( wxString & msg) const
private
380{
381
382 Utils::TCPConsole client(m_host, m_console_port);
383
384 client.enqueue_cmd(controlCommand);
385 client.enqueue_cmd(deviceInfoCommand);
386
387 if (m_gcFlavor == gcfKlipper)
388 client.enqueue_cmd(connectKlipperCommand);
389 else {
390 client.enqueue_cmd(connectLegacyCommand);
391
392 }
393
394 client.enqueue_cmd(statusCommand);
395
396
397 bool res = client.run_queue();
398
399 if (!res) {
400 msg = wxString::FromUTF8(client.error_message().c_str());
401 BOOST_LOG_TRIVIAL(info) << boost::format("[Flashforge Serial] Failed to initiate connection");
402 } else
403 BOOST_LOG_TRIVIAL(info) << boost::format("[Flashforge Serial] Successfully initiated Connection");
404
405 return res;
406}
Slic3r::Utils::SerialMessage connectKlipperCommand
Definition Flashforge.hpp:61
Slic3r::Utils::SerialMessage connectLegacyCommand
Definition Flashforge.hpp:62
Slic3r::Utils::SerialMessage deviceInfoCommand
Definition Flashforge.hpp:64
Slic3r::Utils::SerialMessage statusCommand
Definition Flashforge.hpp:65
Slic3r::Utils::SerialMessage controlCommand
Definition Flashforge.hpp:60
@ gcfKlipper
Definition PrintConfig.hpp:53

References connectKlipperCommand, connectLegacyCommand, controlCommand, deviceInfoCommand, Slic3r::gcfKlipper, m_console_port, m_gcFlavor, m_host, and statusCommand.

Referenced by upload().

Here is the caller graph for this function:

◆ discover_printers()

bool Slic3r::Flashforge::discover_printers ( std::vector< FlashforgeDiscoveredPrinter > & printers,
wxString & msg,
int timeout_ms = 10000,
int idle_timeout_ms = 1500,
int max_retries = 3 )
static
242{
243 printers.clear();
244
245 try {
246 const auto broadcast_addresses = get_discovery_broadcast_addresses();
247 std::map<std::string, FlashforgeDiscoveredPrinter> by_ip;
248
249 for (int attempt = 0; attempt < std::max(1, max_retries); ++attempt) {
250 boost::asio::io_context io_context;
251 boost::asio::ip::udp::socket socket(io_context);
252 boost::system::error_code ec;
253
254 socket.open(boost::asio::ip::udp::v4(), ec);
255 if (ec) {
256 msg = wxString::FromUTF8(ec.message().c_str());
257 return false;
258 }
259
260 socket.set_option(boost::asio::socket_base::broadcast(true), ec);
261 if (ec) {
262 msg = wxString::FromUTF8(ec.message().c_str());
263 return false;
264 }
265
266 socket.set_option(boost::asio::socket_base::reuse_address(true), ec);
267 if (ec) {
268 msg = wxString::FromUTF8(ec.message().c_str());
269 return false;
270 }
271
272 socket.bind({boost::asio::ip::udp::v4(), FLASHFORGE_DISCOVERY_LISTEN_PORT}, ec);
273 if (ec) {
274 msg = wxString::FromUTF8(ec.message().c_str());
275 return false;
276 }
277
278 for (const auto& addr : broadcast_addresses) {
279 socket.send_to(boost::asio::buffer(FLASHFORGE_DISCOVERY_MESSAGE),
280 {boost::asio::ip::make_address_v4(addr, ec), FLASHFORGE_DISCOVERY_PORT}, 0, ec);
281 ec.clear();
282 }
283
284 socket.non_blocking(true, ec);
285 if (ec) {
286 msg = wxString::FromUTF8(ec.message().c_str());
287 return false;
288 }
289
290 const auto start = std::chrono::steady_clock::now();
291 auto last_reply = start;
292
293 while (true) {
294 const auto now = std::chrono::steady_clock::now();
295 if (std::chrono::duration_cast<std::chrono::milliseconds>(now - start).count() >= timeout_ms)
296 break;
297 if (!by_ip.empty() && std::chrono::duration_cast<std::chrono::milliseconds>(now - last_reply).count() >= idle_timeout_ms)
298 break;
299
300 std::vector<unsigned char> buffer(512);
301 boost::asio::ip::udp::endpoint remote_endpoint;
302 const auto received = socket.receive_from(boost::asio::buffer(buffer), remote_endpoint, 0, ec);
303 if (!ec) {
304 buffer.resize(received);
305 FlashforgeDiscoveredPrinter printer;
306 if (parse_discovery_response(buffer, remote_endpoint.address().to_string(), printer)) {
307 by_ip[printer.ip_address] = std::move(printer);
308 last_reply = std::chrono::steady_clock::now();
309 }
310 } else if (ec == boost::asio::error::would_block || ec == boost::asio::error::try_again) {
311 ec.clear();
312 std::this_thread::sleep_for(std::chrono::milliseconds(50));
313 } else {
314 msg = wxString::FromUTF8(ec.message().c_str());
315 return false;
316 }
317 }
318
319 if (!by_ip.empty())
320 break;
321 }
322
323 for (auto& [_, printer] : by_ip)
324 printers.emplace_back(std::move(printer));
325
326 std::sort(printers.begin(), printers.end(), [](const FlashforgeDiscoveredPrinter& lhs, const FlashforgeDiscoveredPrinter& rhs) {
327 if (lhs.name != rhs.name)
328 return lhs.name < rhs.name;
329 return lhs.ip_address < rhs.ip_address;
330 });
331
332 if (printers.empty()) {
333 msg = _(L("No Flashforge printers were discovered on the local network."));
334 return false;
335 }
336
337 return true;
338 } catch (const std::exception& ex) {
339 msg = wxString::FromUTF8(ex.what());
340 return false;
341 }
342}
#define _(s)
Definition 3mf.cpp:306
static unsigned int count
Definition AuxiliaryDataViewModel.cpp:246
#define L(s)
Definition ExtrusionEntity.cpp:25
bool parse_discovery_response(const std::vector< unsigned char > &response, const std::string &ip_address, FlashforgeDiscoveredPrinter &printer)
Definition Flashforge.cpp:81
constexpr unsigned short FLASHFORGE_DISCOVERY_PORT
Definition Flashforge.cpp:62
constexpr unsigned short FLASHFORGE_DISCOVERY_LISTEN_PORT
Definition Flashforge.cpp:63
std::vector< std::string > get_discovery_broadcast_addresses()
Definition Flashforge.cpp:92

References _, count, Slic3r::FlashforgeDiscoveredPrinter::ip_address, and L.

Referenced by Slic3r::GUI::PhysicalPrinterDialog::build_printhost_settings().

Here is the caller graph for this function:

◆ extract_host_name()

std::string Slic3r::Flashforge::extract_host_name ( ) const
private
680{
681 std::string host = m_host;
682 if (host.find("://") == std::string::npos) {
683 const auto slash_pos = host.find('/');
684 if (slash_pos != std::string::npos)
685 host = host.substr(0, slash_pos);
686 return host;
687 }
688
689 std::string out = host;
690 CURLU* hurl = curl_url();
691 if (!hurl)
692 return host;
693
694 const auto rc = curl_url_set(hurl, CURLUPART_URL, host.c_str(), 0);
695 if (rc == CURLUE_OK) {
696 char* raw_host = nullptr;
697 if (curl_url_get(hurl, CURLUPART_HOST, &raw_host, 0) == CURLUE_OK && raw_host != nullptr) {
698 out = raw_host;
699 curl_free(raw_host);
700 }
701 }
702
703 curl_url_cleanup(hurl);
704 return out;
705}

References m_host.

Referenced by make_http_url().

Here is the caller graph for this function:

◆ fetch_material_slots()

bool Slic3r::Flashforge::fetch_material_slots ( std::vector< FlashforgeMaterialSlot > & slots,
bool * supports_material_station,
wxString & msg ) const
516{
517 slots.clear();
518
519 if (m_serial_number.empty() || m_check_code.empty()) {
520 msg = _(L("Flashforge local API requires both serial number and access code."));
521 return false;
522 }
523
524 std::string body;
525 if (!request_local_api_json("detail", json{{"serialNumber", m_serial_number}, {"checkCode", m_check_code}}.dump(), body, msg))
526 return false;
527
528 if (!parse_material_slots(body, slots, supports_material_station)) {
529 msg = _(L("Flashforge returned an invalid JSON response."));
530 return false;
531 }
532
533 return true;
534}
bool request_local_api_json(const std::string &path, const std::string &body, std::string &response_body, wxString &error_msg) const
Definition Flashforge.cpp:654
static bool parse_material_slots(const std::string &body, std::vector< FlashforgeMaterialSlot > &slots, bool *supports_material_station)
Definition Flashforge.cpp:536
nlohmann::json json
Definition AssembleList.cpp:42

References _, L, m_check_code, m_serial_number, parse_material_slots(), and request_local_api_json().

Here is the call graph for this function:

◆ format_error()

wxString Slic3r::PrintHost::format_error ( const std::string & body,
const std::string & error,
unsigned status ) const
protectedvirtualinherited
203{
204 if (status != 0) {
205 const std::string reason = moonraker_error_reason(body);
206 auto wxbody = wxString::FromUTF8(reason.empty() ? body : reason);
207 return wxString::Format("HTTP %u: %s", status, wxbody);
208 } else {
209 if (error.find("curl:Timeout was reached") != std::string::npos) {
210 return timed_out_message();
211 }else if(error.find("curl:Couldn't resolve host name")!= std::string::npos){
212 return _L("The Hostname/IP/URL could not be parsed, please check it and try again.");
213 } else if (error.find("Connection was reset") != std::string::npos){
214 return _L("File/data transfer interrupted. Please check the printer and network, then try it again.");
215 }
216 else {
217 return wxString::FromUTF8(error.data());
218 }
219 }
220}
#define _L(s)
Definition OBJ.cpp:34
static wxString timed_out_message()
Definition PrintHost.cpp:222
std::string moonraker_error_reason(const std::string &body)
Definition PrintHost.cpp:137

References _L, and timed_out_message().

Referenced by Slic3r::Duet::connect(), Slic3r::UltiMaker::connect(), Slic3r::SimplyPrint::do_chunk_upload(), Slic3r::SimplyPrint::do_temp_upload(), Slic3r::ElegooLink::elegoo_cc2_test(), Slic3r::ElegooLink::elegoo_test(), Slic3r::PrusaLink::post_inner(), Slic3r::PrusaLink::put_inner(), Slic3r::Flashforge::request_local_api_json(), Slic3r::Duet::start_print(), Slic3r::Moonraker::start_print(), Slic3r::UltiMaker::start_print(), Slic3r::AstroBox::test(), Slic3r::CrealityPrint::test(), Slic3r::ESP3D::test(), Slic3r::FlashAir::test(), Slic3r::Moonraker::test(), Slic3r::Obico::test(), Slic3r::OctoPrint::test(), Slic3r::PrusaLink::test(), Slic3r::Repetier::test(), Slic3r::UltiMaker::test(), Slic3r::PrusaLink::test_with_method_check(), Slic3r::AstroBox::upload(), Slic3r::C3DPrinterOS::upload(), Slic3r::CrealityPrint::upload(), Slic3r::Duet::upload(), Slic3r::ESP3D::upload(), Slic3r::FlashAir::upload(), Slic3r::MKS::upload(), Slic3r::Moonraker::upload(), Slic3r::Obico::upload(), Slic3r::Repetier::upload(), Slic3r::UltiMaker::upload(), Slic3r::OctoPrint::upload_inner_with_host(), Slic3r::Flashforge::upload_local_api(), Slic3r::ElegooLink::uploadPart(), and Slic3r::ElegooLink::uploadPartCC2().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_err_code_from_body()

int Slic3r::PrintHost::get_err_code_from_body ( const std::string & body)
staticinherited
189{
190 boost::property_tree::ptree root;
191 std::istringstream iss(body);
192 try {
193 boost::property_tree::read_json(iss, root);
194 } catch (const std::exception &ex) {
195 BOOST_LOG_TRIVIAL(error) << "PrintHost: response is not valid JSON: " << ex.what();
196 return -1;
197 }
198
199 return root.get<int>("err", 0);
200}

Referenced by Slic3r::Duet::connect(), Slic3r::UltiMaker::connect(), Slic3r::Duet::upload(), Slic3r::MKS::upload(), and Slic3r::UltiMaker::upload().

Here is the caller graph for this function:

◆ get_groups()

virtual bool Slic3r::PrintHost::get_groups ( wxArrayString & ) const
inlinevirtualinherited

Reimplemented in Slic3r::Repetier.

84{ return false; }

◆ get_host()

std::string Slic3r::Flashforge::get_host ( ) const
inlineoverridevirtual

Implements Slic3r::PrintHost.

47{ return m_host; }

References m_host.

◆ get_login_url()

virtual bool Slic3r::PrintHost::get_login_url ( wxString & auth_url) const
inlinevirtualinherited

Reimplemented in Slic3r::Obico.

99{ return false; }

Referenced by Slic3r::GUI::PrinterCloudAuthDialog::PrinterCloudAuthDialog().

Here is the caller graph for this function:

◆ get_name()

const char * Slic3r::Flashforge::get_name ( ) const
overridevirtual

Implements Slic3r::PrintHost.

239{ return "Flashforge"; }

◆ get_post_upload_actions()

PrintHostPostUploadActions Slic3r::Flashforge::get_post_upload_actions ( ) const
inlineoverridevirtual

Implements Slic3r::PrintHost.

@ StartPrint
Definition PrintHost.hpp:25

References Slic3r::StartPrint.

◆ get_print_host()

PrintHost * Slic3r::PrintHost::get_print_host ( DynamicPrintConfig * config)
staticinherited
59{
61
62 {
63 const auto opt = config->option<ConfigOptionEnum<PrinterTechnology>>("printer_technology");
64 if (opt != nullptr) {
65 tech = opt->value;
66 }
67 }
68
69 if (tech == ptFFF) {
70 const auto opt = config->option<ConfigOptionEnum<PrintHostType>>("host_type");
71 const auto host_type = opt != nullptr ? opt->value : htOctoPrint;
72
73 switch (host_type) {
74 case htOctoPrint: return new OctoPrint(config);
75 case htDuet: return new Duet(config);
76 case htUltiMaker: return new UltiMaker(config);
77 case htFlashAir: return new FlashAir(config);
78 case htAstroBox: return new AstroBox(config);
79 case htRepetier: return new Repetier(config);
80 case htPrusaLink: return new PrusaLink(config);
81 case htPrusaConnect: return new PrusaConnect(config);
82 case htMKS: return new MKS(config);
83 case htESP3D: return new ESP3D(config);
84 case htCrealityPrint: return new CrealityPrint(config);
85 case htObico: return new Obico(config);
86 case htFlashforge: return new Flashforge(config);
87 case htSimplyPrint: return new SimplyPrint(config);
88 case htElegooLink: return new ElegooLink(config);
89 case ht3DPrinterOS: return new C3DPrinterOS(config);
90 case htMoonraker: return new Moonraker(config);
91 default: return nullptr;
92 }
93 } else {
94 return new SL1Host(config);
95 }
96}
PrinterTechnology
Definition Config.hpp:229
@ ptFFF
Definition Config.hpp:231
@ htSimplyPrint
Definition PrintConfig.hpp:119
@ htMoonraker
Definition PrintConfig.hpp:119
@ htElegooLink
Definition PrintConfig.hpp:119
@ htCrealityPrint
Definition PrintConfig.hpp:119
@ ht3DPrinterOS
Definition PrintConfig.hpp:119
@ htPrusaLink
Definition PrintConfig.hpp:119
@ htRepetier
Definition PrintConfig.hpp:119
@ htMKS
Definition PrintConfig.hpp:119
@ htPrusaConnect
Definition PrintConfig.hpp:119
@ htDuet
Definition PrintConfig.hpp:119
@ htUltiMaker
Definition PrintConfig.hpp:119
@ htObico
Definition PrintConfig.hpp:119
@ htOctoPrint
Definition PrintConfig.hpp:119
@ htFlashforge
Definition PrintConfig.hpp:119
@ htFlashAir
Definition PrintConfig.hpp:119
@ htAstroBox
Definition PrintConfig.hpp:119
@ htESP3D
Definition PrintConfig.hpp:119
ConfigOptionEnum< PrinterTechnology >
Definition PrintConfig.hpp:2358

References Slic3r::ht3DPrinterOS, Slic3r::htAstroBox, Slic3r::htCrealityPrint, Slic3r::htDuet, Slic3r::htElegooLink, Slic3r::htESP3D, Slic3r::htFlashAir, Slic3r::htFlashforge, Slic3r::htMKS, Slic3r::htMoonraker, Slic3r::htObico, Slic3r::htOctoPrint, Slic3r::htPrusaConnect, Slic3r::htPrusaLink, Slic3r::htRepetier, Slic3r::htSimplyPrint, Slic3r::htUltiMaker, Slic3r::ConfigBase::option(), and Slic3r::ptFFF.

Referenced by Slic3r::GUI::PhysicalPrinterDialog::build_printhost_settings(), Slic3r::GUI::anonymous_namespace{PrinterWebViewHandler.cpp}::ElegooPrinterWebViewHandler::handle_get_sn_request(), Slic3r::GUI::anonymous_namespace{PrinterWebViewHandler.cpp}::ElegooPrinterWebViewHandler::handle_upload_request(), Slic3r::GUI::PhysicalPrinterDialog::update_printers(), and Slic3r::GUI::PhysicalPrinterDialog::update_printhost_buttons().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_print_host_webui()

std::string Slic3r::PrintHost::get_print_host_webui ( DynamicPrintConfig * config)
staticinherited
99{
100 if (config == nullptr)
101 return {};
102
103 std::string webui_url;
104 const auto* host_type_opt = config->option<ConfigOptionEnum<PrintHostType>>("host_type");
105 const auto host_type = host_type_opt != nullptr ? host_type_opt->value : htOctoPrint;
106
107 switch (host_type) {
108 case htElegooLink: {
109 webui_url = ElegooLink::get_print_host_webui(config);
110 break;
111 }
112 default: break;
113 }
114
115 if (webui_url.empty()) {
116 webui_url = config->opt_string("print_host_webui");
117 if (webui_url.empty())
118 webui_url = config->opt_string("print_host");
119 if (webui_url.empty())
120 return webui_url;
121 }
122
123 const bool has_http_scheme = boost::algorithm::istarts_with(webui_url, "http");
124 const bool has_file_scheme = boost::algorithm::istarts_with(webui_url, "file:");
125
126 if (!has_http_scheme && !has_file_scheme)
127 webui_url = "http://" + webui_url;
128
129 return webui_url;
130}

References Slic3r::ElegooLink::get_print_host_webui(), Slic3r::htElegooLink, Slic3r::htOctoPrint, Slic3r::DynamicConfig::opt_string(), Slic3r::ConfigBase::option(), and Slic3r::ConfigOptionSingle< T >::value.

Referenced by Slic3r::GUI::MainFrame::load_printer_url(), Slic3r::GUI::Plater::priv::on_tab_selection_changing(), and Slic3r::GUI::Sidebar::update_all_preset_comboboxes().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_printers()

virtual bool Slic3r::PrintHost::get_printers ( wxArrayString & ) const
inlinevirtualinherited

Reimplemented in Slic3r::Obico, and Slic3r::Repetier.

85{ return false; }

◆ get_sn()

virtual std::string Slic3r::PrintHost::get_sn ( ) const
inlinevirtualinherited

Get the serial number for connecting to the printer. For Elegoo CC2, the device details connection to the printer requires the serial number. Other print hosts do not need to implement this interface, and it returns an empty string by default.

Reimplemented in Slic3r::ElegooLink.

80{ return ""; }

◆ get_storage()

virtual bool Slic3r::PrintHost::get_storage ( wxArrayString & ,
wxArrayString &  ) const
inlinevirtualinherited

Reimplemented in Slic3r::Moonraker, Slic3r::PrusaConnect, and Slic3r::PrusaLink.

88{ return false; }

◆ get_test_failed_msg()

wxString Slic3r::Flashforge::get_test_failed_msg ( wxString & msg) const
overridevirtual

Implements Slic3r::PrintHost.

371{
372 const std::string prefix = (!m_serial_number.empty() && !m_check_code.empty()) ?
373 _utf8(L("Could not connect to Flashforge local API")) :
374 _utf8(L("Could not connect to Flashforge via serial"));
375 return GUI::from_u8((boost::format("%s: %s") % prefix % std::string(msg.ToUTF8())).str());
376}
wxString from_u8(const std::string &str)
Definition GUI.cpp:544
#define _utf8(s)
Definition I18N.hpp:10

References _utf8, Slic3r::GUI::from_u8(), L, m_check_code, and m_serial_number.

Here is the call graph for this function:

◆ get_test_ok_msg()

wxString Slic3r::Flashforge::get_test_ok_msg ( ) const
overridevirtual

Implements Slic3r::PrintHost.

364{
365 if (!m_serial_number.empty() && !m_check_code.empty())
366 return _(L("Connected to Flashforge local API successfully."));
367 return _(L("Serial connection to Flashforge is working correctly."));
368}

References _, L, m_check_code, and m_serial_number.

◆ has_auto_discovery()

bool Slic3r::Flashforge::has_auto_discovery ( ) const
inlineoverridevirtual

Implements Slic3r::PrintHost.

44{ return true; }

◆ is_cloud()

virtual bool Slic3r::PrintHost::is_cloud ( ) const
inlinevirtualinherited

Reimplemented in Slic3r::C3DPrinterOS, Slic3r::Obico, and Slic3r::SimplyPrint.

96{ return false; }

◆ is_logged_in()

virtual bool Slic3r::PrintHost::is_logged_in ( ) const
inlinevirtualinherited

Reimplemented in Slic3r::C3DPrinterOS, and Slic3r::SimplyPrint.

97{ return false; }

◆ log_out()

virtual void Slic3r::PrintHost::log_out ( ) const
inlinevirtualinherited

Reimplemented in Slic3r::C3DPrinterOS, and Slic3r::SimplyPrint.

98{}

◆ make_http_url()

std::string Slic3r::Flashforge::make_http_url ( const std::string & path) const
private
675{
676 return (boost::format("http://%1%:8898/%2%") % extract_host_name() % path).str();
677}
std::string extract_host_name() const
Definition Flashforge.cpp:679

References extract_host_name().

Referenced by request_local_api_json(), and upload_local_api().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ parse_material_slots()

bool Slic3r::Flashforge::parse_material_slots ( const std::string & body,
std::vector< FlashforgeMaterialSlot > & slots,
bool * supports_material_station )
static
537{
538 slots.clear();
539
540 const auto parsed = json::parse(body, nullptr, false, true);
541 if (parsed.is_discarded())
542 return false;
543
544 const auto& detail = parsed.contains("detail") ? parsed["detail"] : parsed;
545 const auto& station = detail.contains("matlStationInfo") ? detail["matlStationInfo"] :
546 detail.contains("MatlStationInfo") ? detail["MatlStationInfo"] : json();
547 const auto& slot_infos = station.contains("slotInfos") ? station["slotInfos"] :
548 station.contains("SlotInfos") ? station["SlotInfos"] : json::array();
549
550 bool reports_material_station = false;
551
552 int has_material_station_flag = 0;
553 if (detail.contains("hasMatlStation") && try_parse_json_int(detail["hasMatlStation"], has_material_station_flag))
554 reports_material_station = has_material_station_flag != 0;
555 else if (detail.contains("HasMatlStation") && try_parse_json_int(detail["HasMatlStation"], has_material_station_flag))
556 reports_material_station = has_material_station_flag != 0;
557
558 int slot_count = 0;
559 if (station.contains("slotCnt") && try_parse_json_int(station["slotCnt"], slot_count))
560 reports_material_station = reports_material_station || slot_count > 0;
561 else if (station.contains("SlotCnt") && try_parse_json_int(station["SlotCnt"], slot_count))
562 reports_material_station = reports_material_station || slot_count > 0;
563
564 if (slot_infos.is_array() && !slot_infos.empty())
565 reports_material_station = true;
566
567 if (supports_material_station != nullptr)
568 *supports_material_station = reports_material_station;
569
570 // Fields are read leniently: firmware may send numbers as strings or flags as numbers.
571 for (const auto& slot : slot_infos) {
572 if (!slot.is_object())
573 continue;
574 FlashforgeMaterialSlot info;
575 info.slot_id = static_cast<int>(slots.size()) + 1;
576 if (const auto it = slot.find("slotId"); it != slot.end())
577 try_parse_json_int(*it, info.slot_id);
578 int has_filament = 0;
579 if (const auto it = slot.find("hasFilament"); it != slot.end() && try_parse_json_int(*it, has_filament))
580 info.has_filament = has_filament != 0;
581 if (const auto it = slot.find("materialName"); it != slot.end() && it->is_string())
582 info.material_name = it->get<std::string>();
583 if (const auto it = slot.find("materialColor"); it != slot.end() && it->is_string())
584 info.material_color = it->get<std::string>();
585 slots.emplace_back(std::move(info));
586 }
587
588 return true;
589}
bool try_parse_json_int(const json &value, int &out)
Definition Flashforge.cpp:134

References Slic3r::FlashforgeMaterialSlot::has_filament, Slic3r::FlashforgeMaterialSlot::material_color, Slic3r::FlashforgeMaterialSlot::material_name, and Slic3r::FlashforgeMaterialSlot::slot_id.

Referenced by fetch_material_slots().

Here is the caller graph for this function:

◆ request_local_api_json()

bool Slic3r::Flashforge::request_local_api_json ( const std::string & path,
const std::string & body,
std::string & response_body,
wxString & error_msg ) const
private
655{
656 bool ok = true;
657 auto http = Http::post(make_http_url(path));
658 http.header("Content-Type", "application/json")
659 .set_post_body(body)
660 .on_complete([&](std::string body_text, unsigned) {
661 response_body = std::move(body_text);
662 if (!validate_local_api_response(response_body, error_msg))
663 ok = false;
664 })
665 .on_error([&](std::string body_text, std::string error, unsigned status) {
666 response_body = std::move(body_text);
667 error_msg = format_error(response_body, error, status);
668 ok = false;
669 })
670 .perform_sync();
671 return ok;
672}
std::string make_http_url(const std::string &path) const
Definition Flashforge.cpp:674
static Http post(std::string url)
Definition Http.cpp:891
virtual wxString format_error(const std::string &body, const std::string &error, unsigned status) const
Definition PrintHost.cpp:202
bool validate_local_api_response(const std::string &response_body, wxString &error_msg)
Definition Flashforge.cpp:166
@ http
Definition IPrinterAgent.hpp:64

References Slic3r::PrintHost::format_error(), Slic3r::http, make_http_url(), and Slic3r::Http::post().

Referenced by fetch_material_slots(), and test_local_api().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ start_print()

bool Slic3r::Flashforge::start_print ( wxString & msg,
const std::string & filename ) const
private
409{
410 Utils::TCPConsole client(m_host, m_console_port);
411 const std::string safe_filename = sanitize_flashforge_filename(filename);
412 Slic3r::Utils::SerialMessage startPrintCommand = {(boost::format("~M23 0:/user/%1%") % safe_filename).str(), Slic3r::Utils::Command};
413 client.enqueue_cmd(startPrintCommand);
414 bool res = client.run_queue();
415
416 if (!res) {
417 msg = wxString::FromUTF8(client.error_message().c_str());
418 BOOST_LOG_TRIVIAL(info) << boost::format("[Flashforge Serial] Failed to start print %1%") % safe_filename;
419 } else
420 BOOST_LOG_TRIVIAL(info) << boost::format("[Flashforge Serial] Started print %1%") % safe_filename;
421
422 return res;
423}
@ Command
Definition SerialMessageType.hpp:6
std::string sanitize_flashforge_filename(const std::string &filename, const std::string &fallback_extension={})
Definition Flashforge.cpp:200

References Slic3r::Utils::Command, m_console_port, and m_host.

Referenced by upload().

Here is the caller graph for this function:

◆ supports_multiple_printers()

virtual bool Slic3r::PrintHost::supports_multiple_printers ( ) const
inlinevirtualinherited

Reimplemented in Slic3r::Repetier.

73{ return false; }

◆ test()

bool Slic3r::Flashforge::test ( wxString & curl_msg) const
overridevirtual

Implements Slic3r::PrintHost.

345{
346 if (!m_serial_number.empty() && !m_check_code.empty())
347 return test_local_api(msg);
348
349 BOOST_LOG_TRIVIAL(debug) << boost::format("[Flashforge Serial] testing connection");
350 // Utils::TCPConsole console(m_host, m_console_port);
351 Utils::TCPConsole client(m_host, m_console_port);
352 client.enqueue_cmd(controlCommand);
353 bool res = client.run_queue();
354 if (!res) {
355 msg = wxString::FromUTF8(client.error_message().c_str());
356 BOOST_LOG_TRIVIAL(info) << boost::format("[Flashforge Serial] testing connection failed");
357 } else {
358 BOOST_LOG_TRIVIAL(info) << boost::format("[Flashforge Serial] testing connection success");
359 }
360 return res;
361}
bool test_local_api(wxString &msg) const
Definition Flashforge.cpp:509

References controlCommand, m_check_code, m_console_port, m_host, m_serial_number, and test_local_api().

Here is the call graph for this function:

◆ test_local_api()

bool Slic3r::Flashforge::test_local_api ( wxString & msg) const
private
510{
511 std::string body;
512 return request_local_api_json("detail", json{{"serialNumber", m_serial_number}, {"checkCode", m_check_code}}.dump(), body, msg);
513}

References m_check_code, m_serial_number, and request_local_api_json().

Referenced by test().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ timed_out_message()

wxString Slic3r::PrintHost::timed_out_message ( )
staticprotectedinherited
223{
224 return _L("Connection timed out. Please check if the printer and computer network are functioning properly, and confirm that they are on the same network.");
225}

References _L.

Referenced by format_error(), and Slic3r::CrealityPrint::start_print().

Here is the caller graph for this function:

◆ upload()

bool Slic3r::Flashforge::upload ( PrintHostUpload upload_data,
ProgressFn prorgess_fn,
ErrorFn error_fn,
InfoFn info_fn ) const
overridevirtual

Implements Slic3r::PrintHost.

426{
427 if (!m_serial_number.empty() && !m_check_code.empty())
428 return upload_local_api(std::move(upload_data), std::move(progress_fn), std::move(error_fn));
429
430 bool res = true;
431 wxString errormsg;
432
433 Utils::TCPConsole client(m_host, m_console_port);
434
435 try {
436
437 res = connect(errormsg);
438 const std::string fallback_extension = upload_data.source_path.extension().string().empty() ? ".gcode" : upload_data.source_path.extension().string();
439 const std::string upload_filename = sanitize_flashforge_filename(upload_data.upload_path.string(), fallback_extension);
440
441 std::ifstream newfile;
442 newfile.open(upload_data.source_path.c_str(), std::ios::binary); // open a file to perform read operation using file object
443 std::string gcodeFile;
444 if (newfile.is_open()) { // checking whether the file is open
445 BOOST_LOG_TRIVIAL(info) << boost::format("[Flashforge Serial] Reading file...");
446 newfile.seekg(0, std::ios::end);
447 std::ifstream::pos_type pos = newfile.tellg();
448
449 std::vector<char> result(pos);
450
451 newfile.seekg(0, std::ios::beg);
452 newfile.read(&result[0], pos);
453
454 gcodeFile = std::string(result.begin(), result.end()); // TODO: Find more efficient way of breaking ifstream
455
456 BOOST_LOG_TRIVIAL(info) << boost::format("[Flashforge Serial] Reading file...done size is %1%") % gcodeFile.size();
457
458 newfile.close(); // close the file object.
459 }
460 Slic3r::Utils::SerialMessage fileuploadCommand =
461 {(boost::format("~M28 %1% 0:/user/%2%") % gcodeFile.size() % upload_filename).str(),
463 client.enqueue_cmd(fileuploadCommand);
464
465 //client.set_tcp_queue_delay(std::chrono::nanoseconds(10000));
466
467 for (int bytePos = 0; bytePos < gcodeFile.size(); bytePos += m_bufferSize) { // TODO: Find more efficient way of breaking ifstream
468
469 int bytePosEnd = (gcodeFile.size() - bytePos > m_bufferSize - 1) ? m_bufferSize : gcodeFile.size();
470 Slic3r::Utils::SerialMessage dataCommand = {gcodeFile.substr(bytePos, bytePosEnd), Slic3r::Utils::Data}; // Break into smaller byte chunks
471
472 client.enqueue_cmd(dataCommand);
473
474 }
475
476 res = client.run_queue();
477
478 if (res)
479 BOOST_LOG_TRIVIAL(info) << boost::format("[Flashforge Serial] Sent %1% ") % gcodeFile.size();
480
481
482 if (!res) {
483 BOOST_LOG_TRIVIAL(info) << boost::format("[Flashforge Serial] error %1%") % client.error_message().c_str();
484 errormsg = wxString::FromUTF8(client.error_message().c_str());
485 error_fn(std::move(errormsg));
486 } else {
487
488 client.set_tcp_queue_delay(std::chrono::milliseconds(3000));
489
490 BOOST_LOG_TRIVIAL(info) << boost::format("[Flashforge Serial] Sending file save command ");
491
492 client.enqueue_cmd(saveFileCommand);
493
494 res = client.run_queue();
495
496 if (upload_data.post_action == PrintHostPostUploadAction::StartPrint)
497 res = start_print(errormsg, upload_filename);
498 }
499
500 } catch (const std::exception& e) {
501 BOOST_LOG_TRIVIAL(info) << boost::format("[Flashforge Serial] error %1%") % e.what();
502 errormsg = wxString::FromUTF8(e.what());
503 error_fn(std::move(errormsg));
504 }
505
506 return res;
507}
Slic3r::Utils::SerialMessage saveFileCommand
Definition Flashforge.hpp:68
bool connect(wxString &msg) const
Definition Flashforge.cpp:379
bool upload_local_api(PrintHostUpload upload_data, ProgressFn progress_fn, ErrorFn error_fn) const
Definition Flashforge.cpp:591
bool start_print(wxString &msg, const std::string &filename) const
Definition Flashforge.cpp:408
@ Data
Definition SerialMessageType.hpp:6
Vec3d pos(const Pt &p)
Definition ReprojectPointsOnMesh.hpp:16

References Slic3r::Utils::Command, connect(), Slic3r::Utils::Data, m_bufferSize, m_check_code, m_console_port, m_host, m_serial_number, Slic3r::PrintHostUpload::post_action, saveFileCommand, Slic3r::PrintHostUpload::source_path, start_print(), Slic3r::StartPrint, upload_local_api(), and Slic3r::PrintHostUpload::upload_path.

Here is the call graph for this function:

◆ upload_local_api()

bool Slic3r::Flashforge::upload_local_api ( PrintHostUpload upload_data,
ProgressFn progress_fn,
ErrorFn error_fn ) const
private
592{
593 bool res = true;
594 std::string material_map_b64;
595 std::string material_map_json = "[]";
596 auto leveling_before_print = upload_data.extended_info["levelingBeforePrint"] == "1";
597 auto time_lapse_video = upload_data.extended_info["timeLapseVideo"] == "1";
598 auto use_material_station = upload_data.extended_info["useMatlStation"] == "1";
599
600 if (auto it = upload_data.extended_info.find("materialMappings"); it != upload_data.extended_info.end())
601 material_map_json = it->second;
602
603 material_map_b64.resize(boost::beast::detail::base64::encoded_size(material_map_json.size()));
604 material_map_b64.resize(boost::beast::detail::base64::encode(material_map_b64.data(), material_map_json.data(), material_map_json.size()));
605
606 auto url = make_http_url("uploadGcode");
607 const std::string fallback_extension = upload_data.source_path.extension().string().empty() ? (upload_data.use_3mf ? ".3mf" : ".gcode") : upload_data.source_path.extension().string();
608 auto filename = sanitize_flashforge_filename(upload_data.upload_path.string(), fallback_extension);
609 std::string file_size;
610 try {
611 file_size = std::to_string(fs::file_size(upload_data.source_path));
612 } catch (...) {
613 file_size = "0";
614 }
615
616 auto http = Http::post(url);
617 http.header("serialNumber", m_serial_number)
618 .header("checkCode", m_check_code)
619 .header("fileSize", file_size)
620 .header("printNow", upload_data.post_action == PrintHostPostUploadAction::StartPrint ? "true" : "false")
621 .header("levelingBeforePrint", leveling_before_print ? "true" : "false")
622 .header("flowCalibration", "false")
623 .header("firstLayerInspection", "false")
624 .header("timeLapseVideo", time_lapse_video ? "true" : "false")
625 .header("useMatlStation", use_material_station ? "true" : "false")
626 .header("gcodeToolCnt", upload_data.extended_info["gcodeToolCnt"])
627 .header("materialMappings", material_map_b64)
628 .form_add_file("gcodeFile", upload_data.source_path.string(), filename)
629 .on_complete([&](std::string body, unsigned status) {
630 wxString msg;
631 if (!validate_local_api_response(body, msg)) {
632 BOOST_LOG_TRIVIAL(error) << boost::format("[Flashforge HTTP] upload rejected by printer: HTTP %1% body: `%2%`") % status % body;
633 error_fn(msg);
634 res = false;
635 } else {
636 BOOST_LOG_TRIVIAL(info) << boost::format("[Flashforge HTTP] upload complete: HTTP %1% body: %2%") % status % body;
637 }
638 })
639 .on_error([&](std::string body, std::string error, unsigned status) {
640 BOOST_LOG_TRIVIAL(error) << boost::format("[Flashforge HTTP] upload failed: %1%, HTTP %2%, body: `%3%`") % error % status % body;
641 error_fn(format_error(body, error, status));
642 res = false;
643 })
644 .on_progress([&](Http::Progress progress, bool& cancel) {
645 progress_fn(std::move(progress), cancel);
646 if (cancel)
647 res = false;
648 })
649 .perform_sync();
650
651 return res;
652}

References Slic3r::PrintHostUpload::extended_info, Slic3r::PrintHost::format_error(), Slic3r::http, m_check_code, m_serial_number, make_http_url(), Slic3r::Http::post(), Slic3r::PrintHostUpload::post_action, Slic3r::PrintHostUpload::source_path, Slic3r::StartPrint, Slic3r::PrintHostUpload::upload_path, and Slic3r::PrintHostUpload::use_3mf.

Referenced by upload().

Here is the call graph for this function:
Here is the caller graph for this function:

Member Data Documentation

◆ connectKlipperCommand

Slic3r::Utils::SerialMessage Slic3r::Flashforge::connectKlipperCommand = {"~M640\r\n",Slic3r::Utils::Command}
private
61{"~M640\r\n",Slic3r::Utils::Command};

Referenced by connect().

◆ connectLegacyCommand

Slic3r::Utils::SerialMessage Slic3r::Flashforge::connectLegacyCommand = {"~M650\r\n",Slic3r::Utils::Command}
private
62{"~M650\r\n",Slic3r::Utils::Command};

Referenced by connect().

◆ controlCommand

Slic3r::Utils::SerialMessage Slic3r::Flashforge::controlCommand = {"~M601 S1\r\n",Slic3r::Utils::Command}
private
60{"~M601 S1\r\n",Slic3r::Utils::Command};

Referenced by connect(), and test().

◆ deviceInfoCommand

Slic3r::Utils::SerialMessage Slic3r::Flashforge::deviceInfoCommand = {"~M115\r\n", Slic3r::Utils::Command}
private
64{"~M115\r\n", Slic3r::Utils::Command};

Referenced by connect().

◆ m_bufferSize

const int Slic3r::Flashforge::m_bufferSize
private

Referenced by Flashforge(), and upload().

◆ m_check_code

std::string Slic3r::Flashforge::m_check_code
private

◆ m_console_port

std::string Slic3r::Flashforge::m_console_port
private

◆ m_gcFlavor

GCodeFlavor Slic3r::Flashforge::m_gcFlavor
private

Referenced by Flashforge(), and connect().

◆ m_host

std::string Slic3r::Flashforge::m_host
private

◆ m_serial_number

std::string Slic3r::Flashforge::m_serial_number
private

◆ nozzlePosCommand

Slic3r::Utils::SerialMessage Slic3r::Flashforge::nozzlePosCommand = {"~M114\r\n", Slic3r::Utils::Command}
private
63{"~M114\r\n", Slic3r::Utils::Command};

◆ printStatusCommand

Slic3r::Utils::SerialMessage Slic3r::Flashforge::printStatusCommand = {"~M27\r\n", Slic3r::Utils::Command}
private
67{"~M27\r\n", Slic3r::Utils::Command};

◆ saveFileCommand

Slic3r::Utils::SerialMessage Slic3r::Flashforge::saveFileCommand = {"~M29\r\n",Slic3r::Utils::Command}
private
68{"~M29\r\n",Slic3r::Utils::Command};

Referenced by upload().

◆ statusCommand

Slic3r::Utils::SerialMessage Slic3r::Flashforge::statusCommand = {"~M119\r\n",Slic3r::Utils::Command}
private
65{"~M119\r\n",Slic3r::Utils::Command};

Referenced by connect().

◆ tempStatusCommand

Slic3r::Utils::SerialMessage Slic3r::Flashforge::tempStatusCommand = {"~M105\r\n", Slic3r::Utils::Command}
private
66{"~M105\r\n", Slic3r::Utils::Command};

The documentation for this class was generated from the following files:
  • /home/runner/work/OrcaSlicer/OrcaSlicer/src/slic3r/Utils/Flashforge.hpp
  • /home/runner/work/OrcaSlicer/OrcaSlicer/src/slic3r/Utils/Flashforge.cpp