Added possibility for upload to Duet
Further changes: - Added new configuration option Host Type - Added abstract base class for future printer hosts - Moved location of upload dialog (also made it a little bit more configureable) - added possibility to send file via postfield instead a new frame
This commit is contained in:
parent
3433e8e374
commit
dd1fd66a47
@ -167,6 +167,8 @@ sub thread_cleanup {
|
||||
*Slic3r::GUI::PresetHints::DESTROY = sub {};
|
||||
*Slic3r::GUI::TabIface::DESTROY = sub {};
|
||||
*Slic3r::OctoPrint::DESTROY = sub {};
|
||||
*Slic3r::Duet::DESTROY = sub {};
|
||||
*Slic3r::PrintHostFactory::DESTROY = sub {};
|
||||
*Slic3r::PresetUpdater::DESTROY = sub {};
|
||||
return undef; # this prevents a "Scalars leaked" warning
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ sub new {
|
||||
my $self = $class->SUPER::new($parent, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
|
||||
$self->{config} = Slic3r::Config::new_from_defaults_keys([qw(
|
||||
bed_shape complete_objects extruder_clearance_radius skirts skirt_distance brim_width variable_layer_height
|
||||
serial_port serial_speed octoprint_host octoprint_apikey octoprint_cafile
|
||||
serial_port serial_speed host_type print_host printhost_apikey printhost_cafile
|
||||
nozzle_diameter single_extruder_multi_material wipe_tower wipe_tower_x wipe_tower_y wipe_tower_width
|
||||
wipe_tower_rotation_angle extruder_colour filament_colour max_print_height printer_model
|
||||
)]);
|
||||
@ -1569,7 +1569,7 @@ sub on_export_completed {
|
||||
$message = L("File added to print queue");
|
||||
$do_print = 1;
|
||||
} elsif ($self->{send_gcode_file}) {
|
||||
$message = L("Sending G-code file to the OctoPrint server...");
|
||||
$message = L("Sending G-code file to the Printer Host ...");
|
||||
$send_gcode = 1;
|
||||
} else {
|
||||
$message = L("G-code file exported to ") . $self->{export_gcode_output_file};
|
||||
@ -1585,9 +1585,10 @@ sub on_export_completed {
|
||||
|
||||
# Send $self->{send_gcode_file} to OctoPrint.
|
||||
if ($send_gcode) {
|
||||
my $op = Slic3r::OctoPrint->new($self->{config});
|
||||
if ($op->send_gcode($self->{send_gcode_file})) {
|
||||
$self->statusbar->SetStatusText(L("OctoPrint upload finished."));
|
||||
my $host = Slic3r::PrintHostFactory::get_print_host($self->{config});
|
||||
|
||||
if ($host->send_gcode($self->{send_gcode_file})) {
|
||||
$self->statusbar->SetStatusText(L("Upload to host finished."));
|
||||
} else {
|
||||
$self->statusbar->SetStatusText("");
|
||||
}
|
||||
@ -1914,8 +1915,8 @@ sub on_config_change {
|
||||
} elsif ($opt_key eq 'serial_port') {
|
||||
$self->{btn_print}->Show($config->get('serial_port'));
|
||||
$self->Layout;
|
||||
} elsif ($opt_key eq 'octoprint_host') {
|
||||
$self->{btn_send_gcode}->Show($config->get('octoprint_host'));
|
||||
} elsif ($opt_key eq 'print_host') {
|
||||
$self->{btn_send_gcode}->Show($config->get('print_host'));
|
||||
$self->Layout;
|
||||
} elsif ($opt_key eq 'variable_layer_height') {
|
||||
if ($config->get('variable_layer_height') != 1) {
|
||||
|
@ -1007,8 +1007,8 @@ max_layer_height = 0.25
|
||||
min_layer_height = 0.07
|
||||
max_print_height = 200
|
||||
nozzle_diameter = 0.4
|
||||
octoprint_apikey =
|
||||
octoprint_host =
|
||||
printhost_apikey =
|
||||
print_host =
|
||||
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK2\n
|
||||
printer_settings_id =
|
||||
retract_before_travel = 1
|
||||
|
@ -251,8 +251,14 @@ add_library(libslic3r_gui STATIC
|
||||
${LIBDIR}/slic3r/Utils/Http.hpp
|
||||
${LIBDIR}/slic3r/Utils/FixModelByWin10.cpp
|
||||
${LIBDIR}/slic3r/Utils/FixModelByWin10.hpp
|
||||
${LIBDIR}/slic3r/Utils/PrintHostSendDialog.cpp
|
||||
${LIBDIR}/slic3r/Utils/PrintHostSendDialog.hpp
|
||||
${LIBDIR}/slic3r/Utils/OctoPrint.cpp
|
||||
${LIBDIR}/slic3r/Utils/OctoPrint.hpp
|
||||
${LIBDIR}/slic3r/Utils/Duet.cpp
|
||||
${LIBDIR}/slic3r/Utils/Duet.hpp
|
||||
${LIBDIR}/slic3r/Utils/PrintHostFactory.cpp
|
||||
${LIBDIR}/slic3r/Utils/PrintHostFactory.hpp
|
||||
${LIBDIR}/slic3r/Utils/Bonjour.cpp
|
||||
${LIBDIR}/slic3r/Utils/Bonjour.hpp
|
||||
${LIBDIR}/slic3r/Utils/PresetUpdater.cpp
|
||||
@ -411,7 +417,8 @@ set(XS_XSP_FILES
|
||||
${XSP_DIR}/Surface.xsp
|
||||
${XSP_DIR}/SurfaceCollection.xsp
|
||||
${XSP_DIR}/TriangleMesh.xsp
|
||||
${XSP_DIR}/Utils_OctoPrint.xsp
|
||||
${XSP_DIR}/Utils_PrintHostFactory.xsp
|
||||
${XSP_DIR}/Utils_PrintHost.xsp
|
||||
${XSP_DIR}/Utils_PresetUpdater.xsp
|
||||
${XSP_DIR}/AppController.xsp
|
||||
${XSP_DIR}/XS.xsp
|
||||
|
@ -1137,24 +1137,36 @@ PrintConfigDef::PrintConfigDef()
|
||||
def->cli = "nozzle-diameter=f@";
|
||||
def->default_value = new ConfigOptionFloats { 0.5 };
|
||||
|
||||
def = this->add("octoprint_apikey", coString);
|
||||
def->label = L("API Key");
|
||||
def->tooltip = L("Slic3r can upload G-code files to OctoPrint. This field should contain "
|
||||
"the API Key required for authentication.");
|
||||
def = this->add("host_type", coEnum);
|
||||
def->label = L("Host Type");
|
||||
def->tooltip = L("Slic3r can upload G-code files to a printer host. This field must contain "
|
||||
"the kind of the host.");
|
||||
def->cli = "host-type=s";
|
||||
def->enum_keys_map = &ConfigOptionEnum<PrintHostType>::get_enum_values();
|
||||
def->enum_values.push_back("octoprint");
|
||||
def->enum_values.push_back("duet");
|
||||
def->enum_labels.push_back("OctoPrint");
|
||||
def->enum_labels.push_back("Duet");
|
||||
def->default_value = new ConfigOptionEnum<PrintHostType>(htOctoPrint);
|
||||
|
||||
def = this->add("printhost_apikey", coString);
|
||||
def->label = L("API Key / Password");
|
||||
def->tooltip = L("Slic3r can upload G-code files to a printer host. This field should contain "
|
||||
"the API Key or the password required for authentication.");
|
||||
def->cli = "octoprint-apikey=s";
|
||||
def->default_value = new ConfigOptionString("");
|
||||
|
||||
def = this->add("octoprint_cafile", coString);
|
||||
def = this->add("printhost_cafile", coString);
|
||||
def->label = "HTTPS CA file";
|
||||
def->tooltip = "Custom CA certificate file can be specified for HTTPS OctoPrint connections, in crt/pem format. "
|
||||
"If left blank, the default OS CA certificate repository is used.";
|
||||
def->cli = "octoprint-cafile=s";
|
||||
def->default_value = new ConfigOptionString("");
|
||||
|
||||
def = this->add("octoprint_host", coString);
|
||||
def = this->add("print_host", coString);
|
||||
def->label = L("Hostname, IP or URL");
|
||||
def->tooltip = L("Slic3r can upload G-code files to OctoPrint. This field should contain "
|
||||
"the hostname, IP address or URL of the OctoPrint instance.");
|
||||
def->tooltip = L("Slic3r can upload G-code files to a printer host. This field should contain "
|
||||
"the hostname, IP address or URL of the printer host instance.");
|
||||
def->cli = "octoprint-host=s";
|
||||
def->default_value = new ConfigOptionString("");
|
||||
|
||||
@ -2107,10 +2119,6 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va
|
||||
std::ostringstream oss;
|
||||
oss << "0x0," << p.value.x << "x0," << p.value.x << "x" << p.value.y << ",0x" << p.value.y;
|
||||
value = oss.str();
|
||||
// Maybe one day we will rename octoprint_host to print_host as it has been done in the upstream Slic3r.
|
||||
// Commenting this out fixes github issue #869 for now.
|
||||
// } else if (opt_key == "octoprint_host" && !value.empty()) {
|
||||
// opt_key = "print_host";
|
||||
} else if ((opt_key == "perimeter_acceleration" && value == "25")
|
||||
|| (opt_key == "infill_acceleration" && value == "50")) {
|
||||
/* For historical reasons, the world's full of configs having these very low values;
|
||||
|
@ -27,6 +27,10 @@ enum GCodeFlavor {
|
||||
gcfSmoothie, gcfNoExtrusion,
|
||||
};
|
||||
|
||||
enum PrintHostType {
|
||||
htOctoPrint, htDuet,
|
||||
};
|
||||
|
||||
enum InfillPattern {
|
||||
ipRectilinear, ipGrid, ipTriangles, ipStars, ipCubic, ipLine, ipConcentric, ipHoneycomb, ip3DHoneycomb,
|
||||
ipGyroid, ipHilbertCurve, ipArchimedeanChords, ipOctagramSpiral,
|
||||
@ -61,6 +65,15 @@ template<> inline t_config_enum_values& ConfigOptionEnum<GCodeFlavor>::get_enum_
|
||||
return keys_map;
|
||||
}
|
||||
|
||||
template<> inline t_config_enum_values& ConfigOptionEnum<PrintHostType>::get_enum_values() {
|
||||
static t_config_enum_values keys_map;
|
||||
if (keys_map.empty()) {
|
||||
keys_map["octoprint"] = htOctoPrint;
|
||||
keys_map["duet"] = htDuet;
|
||||
}
|
||||
return keys_map;
|
||||
}
|
||||
|
||||
template<> inline t_config_enum_values& ConfigOptionEnum<InfillPattern>::get_enum_values() {
|
||||
static t_config_enum_values keys_map;
|
||||
if (keys_map.empty()) {
|
||||
@ -789,18 +802,20 @@ class HostConfig : public StaticPrintConfig
|
||||
{
|
||||
STATIC_PRINT_CONFIG_CACHE(HostConfig)
|
||||
public:
|
||||
ConfigOptionString octoprint_host;
|
||||
ConfigOptionString octoprint_apikey;
|
||||
ConfigOptionString octoprint_cafile;
|
||||
ConfigOptionEnum<PrintHostType> host_type;
|
||||
ConfigOptionString print_host;
|
||||
ConfigOptionString printhost_apikey;
|
||||
ConfigOptionString printhost_cafile;
|
||||
ConfigOptionString serial_port;
|
||||
ConfigOptionInt serial_speed;
|
||||
|
||||
protected:
|
||||
void initialize(StaticCacheBase &cache, const char *base_ptr)
|
||||
{
|
||||
OPT_PTR(octoprint_host);
|
||||
OPT_PTR(octoprint_apikey);
|
||||
OPT_PTR(octoprint_cafile);
|
||||
OPT_PTR(host_type);
|
||||
OPT_PTR(print_host);
|
||||
OPT_PTR(printhost_apikey);
|
||||
OPT_PTR(printhost_cafile);
|
||||
OPT_PTR(serial_port);
|
||||
OPT_PTR(serial_speed);
|
||||
}
|
||||
|
@ -64,9 +64,10 @@ REGISTER_CLASS(PresetCollection, "GUI::PresetCollection");
|
||||
REGISTER_CLASS(PresetBundle, "GUI::PresetBundle");
|
||||
REGISTER_CLASS(TabIface, "GUI::Tab");
|
||||
REGISTER_CLASS(PresetUpdater, "PresetUpdater");
|
||||
REGISTER_CLASS(OctoPrint, "OctoPrint");
|
||||
REGISTER_CLASS(AppController, "AppController");
|
||||
REGISTER_CLASS(PrintController, "PrintController");
|
||||
REGISTER_CLASS(PrintHost, "PrintHost");
|
||||
REGISTER_CLASS(PrintHostFactory, "PrintHostFactory");
|
||||
|
||||
SV* ConfigBase__as_hash(ConfigBase* THIS)
|
||||
{
|
||||
|
@ -586,6 +586,8 @@ boost::any& Choice::get_value()
|
||||
m_value = static_cast<SupportMaterialPattern>(ret_enum);
|
||||
else if (m_opt_id.compare("seam_position") == 0)
|
||||
m_value = static_cast<SeamPosition>(ret_enum);
|
||||
else if (m_opt_id.compare("host_type") == 0)
|
||||
m_value = static_cast<PrintHostType>(ret_enum);
|
||||
}
|
||||
|
||||
return m_value;
|
||||
|
@ -604,6 +604,8 @@ void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt
|
||||
config.set_key_value(opt_key, new ConfigOptionEnum<SupportMaterialPattern>(boost::any_cast<SupportMaterialPattern>(value)));
|
||||
else if (opt_key.compare("seam_position") == 0)
|
||||
config.set_key_value(opt_key, new ConfigOptionEnum<SeamPosition>(boost::any_cast<SeamPosition>(value)));
|
||||
else if (opt_key.compare("host_type") == 0)
|
||||
config.set_key_value(opt_key, new ConfigOptionEnum<PrintHostType>(boost::any_cast<PrintHostType>(value)));
|
||||
}
|
||||
break;
|
||||
case coPoints:{
|
||||
|
@ -459,8 +459,12 @@ boost::any ConfigOptionsGroup::get_config_value(const DynamicPrintConfig& config
|
||||
else if (opt_key.compare("support_material_pattern") == 0){
|
||||
ret = static_cast<int>(config.option<ConfigOptionEnum<SupportMaterialPattern>>(opt_key)->value);
|
||||
}
|
||||
else if (opt_key.compare("seam_position") == 0)
|
||||
else if (opt_key.compare("seam_position") == 0){
|
||||
ret = static_cast<int>(config.option<ConfigOptionEnum<SeamPosition>>(opt_key)->value);
|
||||
}
|
||||
else if (opt_key.compare("host_type") == 0){
|
||||
ret = static_cast<int>(config.option<ConfigOptionEnum<PrintHostType>>(opt_key)->value);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case coPoints:
|
||||
|
@ -329,8 +329,8 @@ const std::vector<std::string>& Preset::printer_options()
|
||||
static std::vector<std::string> s_opts;
|
||||
if (s_opts.empty()) {
|
||||
s_opts = {
|
||||
"bed_shape", "z_offset", "gcode_flavor", "use_relative_e_distances", "serial_port", "serial_speed",
|
||||
"octoprint_host", "octoprint_apikey", "octoprint_cafile", "use_firmware_retraction", "use_volumetric_e", "variable_layer_height",
|
||||
"bed_shape", "z_offset", "gcode_flavor", "use_relative_e_distances", "serial_port", "serial_speed", "host_type",
|
||||
"print_host", "printhost_apikey", "printhost_cafile", "use_firmware_retraction", "use_volumetric_e", "variable_layer_height",
|
||||
"single_extruder_multi_material", "start_gcode", "end_gcode", "before_layer_gcode", "layer_gcode", "toolchange_gcode",
|
||||
"between_objects_gcode", "printer_vendor", "printer_model", "printer_variant", "printer_notes", "cooling_tube_retraction",
|
||||
"cooling_tube_length", "parking_pos_retraction", "extra_loading_move", "max_print_height", "default_print_profile", "inherits",
|
||||
|
@ -5,7 +5,8 @@
|
||||
#include "../../libslic3r/Utils.hpp"
|
||||
|
||||
#include "slic3r/Utils/Http.hpp"
|
||||
#include "slic3r/Utils/OctoPrint.hpp"
|
||||
#include "slic3r/Utils/PrintHostFactory.hpp"
|
||||
#include "slic3r/Utils/PrintHost.hpp"
|
||||
#include "slic3r/Utils/Serial.hpp"
|
||||
#include "BonjourDialog.hpp"
|
||||
#include "WipeTowerDialog.hpp"
|
||||
@ -1521,10 +1522,12 @@ void TabPrinter::build()
|
||||
optgroup->append_line(line);
|
||||
}
|
||||
|
||||
optgroup = page->new_optgroup(_(L("OctoPrint upload")));
|
||||
optgroup = page->new_optgroup(_(L("Printer Host upload")));
|
||||
|
||||
auto octoprint_host_browse = [this, optgroup] (wxWindow* parent) {
|
||||
auto btn = new wxButton(parent, wxID_ANY, _(L(" Browse "))+dots, wxDefaultPosition, wxDefaultSize, wxBU_LEFT);
|
||||
optgroup->append_single_option_line("host_type");
|
||||
|
||||
auto printhost_browse = [this, optgroup] (wxWindow* parent) {
|
||||
auto btn = m_printhost_browse_btn = new wxButton(parent, wxID_ANY, _(L(" Browse "))+dots, wxDefaultPosition, wxDefaultSize, wxBU_LEFT);
|
||||
btn->SetBitmap(wxBitmap(from_u8(Slic3r::var("zoom.png")), wxBITMAP_TYPE_PNG));
|
||||
auto sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
sizer->Add(btn);
|
||||
@ -1532,47 +1535,52 @@ void TabPrinter::build()
|
||||
btn->Bind(wxEVT_BUTTON, [this, parent, optgroup](wxCommandEvent e) {
|
||||
BonjourDialog dialog(parent);
|
||||
if (dialog.show_and_lookup()) {
|
||||
optgroup->set_value("octoprint_host", std::move(dialog.get_selected()), true);
|
||||
optgroup->set_value("print_host", std::move(dialog.get_selected()), true);
|
||||
}
|
||||
});
|
||||
|
||||
return sizer;
|
||||
};
|
||||
|
||||
auto octoprint_host_test = [this](wxWindow* parent) {
|
||||
auto btn = m_octoprint_host_test_btn = new wxButton(parent, wxID_ANY, _(L("Test")),
|
||||
auto print_host_test = [this](wxWindow* parent) {
|
||||
auto btn = m_print_host_test_btn = new wxButton(parent, wxID_ANY, _(L("Test")),
|
||||
wxDefaultPosition, wxDefaultSize, wxBU_LEFT | wxBU_EXACTFIT);
|
||||
btn->SetBitmap(wxBitmap(from_u8(Slic3r::var("wrench.png")), wxBITMAP_TYPE_PNG));
|
||||
auto sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
sizer->Add(btn);
|
||||
|
||||
btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent e) {
|
||||
OctoPrint octoprint(m_config);
|
||||
wxString msg;
|
||||
if (octoprint.test(msg)) {
|
||||
show_info(this, _(L("Connection to OctoPrint works correctly.")), _(L("Success!")));
|
||||
} else {
|
||||
const auto text = wxString::Format("%s: %s\n\n%s",
|
||||
_(L("Could not connect to OctoPrint")), msg, _(L("Note: OctoPrint version at least 1.1.0 is required."))
|
||||
);
|
||||
PrintHost *host = PrintHostFactory::get_print_host(m_config);
|
||||
if (host == NULL) {
|
||||
const auto text = wxString::Format("%s",
|
||||
_(L("Could not get a valid Printer Host reference")));
|
||||
show_error(this, text);
|
||||
return;
|
||||
}
|
||||
wxString msg;
|
||||
if (host->test(msg)) {
|
||||
show_info(this, host->get_test_ok_msg(), _(L("Success!")));
|
||||
} else {
|
||||
show_error(this, host->get_test_failed_msg(msg));
|
||||
}
|
||||
|
||||
delete (host);
|
||||
});
|
||||
|
||||
return sizer;
|
||||
};
|
||||
|
||||
Line host_line = optgroup->create_single_option_line("octoprint_host");
|
||||
host_line.append_widget(octoprint_host_browse);
|
||||
host_line.append_widget(octoprint_host_test);
|
||||
Line host_line = optgroup->create_single_option_line("print_host");
|
||||
host_line.append_widget(printhost_browse);
|
||||
host_line.append_widget(print_host_test);
|
||||
optgroup->append_line(host_line);
|
||||
optgroup->append_single_option_line("octoprint_apikey");
|
||||
optgroup->append_single_option_line("printhost_apikey");
|
||||
|
||||
if (Http::ca_file_supported()) {
|
||||
|
||||
Line cafile_line = optgroup->create_single_option_line("octoprint_cafile");
|
||||
Line cafile_line = optgroup->create_single_option_line("printhost_cafile");
|
||||
|
||||
auto octoprint_cafile_browse = [this, optgroup] (wxWindow* parent) {
|
||||
auto printhost_cafile_browse = [this, optgroup] (wxWindow* parent) {
|
||||
auto btn = new wxButton(parent, wxID_ANY, _(L(" Browse "))+dots, wxDefaultPosition, wxDefaultSize, wxBU_LEFT);
|
||||
btn->SetBitmap(wxBitmap(from_u8(Slic3r::var("zoom.png")), wxBITMAP_TYPE_PNG));
|
||||
auto sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
@ -1582,17 +1590,17 @@ void TabPrinter::build()
|
||||
static const auto filemasks = _(L("Certificate files (*.crt, *.pem)|*.crt;*.pem|All files|*.*"));
|
||||
wxFileDialog openFileDialog(this, _(L("Open CA certificate file")), "", "", filemasks, wxFD_OPEN | wxFD_FILE_MUST_EXIST);
|
||||
if (openFileDialog.ShowModal() != wxID_CANCEL) {
|
||||
optgroup->set_value("octoprint_cafile", std::move(openFileDialog.GetPath()), true);
|
||||
optgroup->set_value("printhost_cafile", std::move(openFileDialog.GetPath()), true);
|
||||
}
|
||||
});
|
||||
|
||||
return sizer;
|
||||
};
|
||||
|
||||
cafile_line.append_widget(octoprint_cafile_browse);
|
||||
cafile_line.append_widget(printhost_cafile_browse);
|
||||
optgroup->append_line(cafile_line);
|
||||
|
||||
auto octoprint_cafile_hint = [this, optgroup] (wxWindow* parent) {
|
||||
auto printhost_cafile_hint = [this, optgroup] (wxWindow* parent) {
|
||||
auto txt = new wxStaticText(parent, wxID_ANY,
|
||||
_(L("HTTPS CA file is optional. It is only needed if you use HTTPS with a self-signed certificate.")));
|
||||
auto sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
@ -1602,7 +1610,7 @@ void TabPrinter::build()
|
||||
|
||||
Line cafile_hint { "", "" };
|
||||
cafile_hint.full_width = 1;
|
||||
cafile_hint.widget = std::move(octoprint_cafile_hint);
|
||||
cafile_hint.widget = std::move(printhost_cafile_hint);
|
||||
optgroup->append_line(cafile_hint);
|
||||
|
||||
}
|
||||
@ -1897,7 +1905,10 @@ void TabPrinter::update(){
|
||||
m_serial_test_btn->Disable();
|
||||
}
|
||||
|
||||
m_octoprint_host_test_btn->Enable(!m_config->opt_string("octoprint_host").empty());
|
||||
PrintHost *host = PrintHostFactory::get_print_host(m_config);
|
||||
m_print_host_test_btn->Enable(!m_config->opt_string("print_host").empty() && host->can_test());
|
||||
m_printhost_browse_btn->Enable(host->have_auto_discovery());
|
||||
delete (host);
|
||||
|
||||
bool have_multiple_extruders = m_extruders_count > 1;
|
||||
get_field("toolchange_gcode")->toggle(have_multiple_extruders);
|
||||
|
@ -321,7 +321,8 @@ class TabPrinter : public Tab
|
||||
bool m_rebuild_kinematics_page = false;
|
||||
public:
|
||||
wxButton* m_serial_test_btn;
|
||||
wxButton* m_octoprint_host_test_btn;
|
||||
wxButton* m_print_host_test_btn;
|
||||
wxButton* m_printhost_browse_btn;
|
||||
|
||||
size_t m_extruders_count;
|
||||
size_t m_extruders_count_old = 0;
|
||||
|
281
xs/src/slic3r/Utils/Duet.cpp
Normal file
281
xs/src/slic3r/Utils/Duet.cpp
Normal file
@ -0,0 +1,281 @@
|
||||
#include "Duet.hpp"
|
||||
#include "PrintHostSendDialog.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
#include <boost/property_tree/json_parser.hpp>
|
||||
|
||||
#include <wx/frame.h>
|
||||
#include <wx/event.h>
|
||||
#include <wx/progdlg.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/stattext.h>
|
||||
#include <wx/textctrl.h>
|
||||
#include <wx/checkbox.h>
|
||||
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
#include "slic3r/GUI/GUI.hpp"
|
||||
#include "slic3r/GUI/MsgDialog.hpp"
|
||||
#include "Http.hpp"
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
namespace pt = boost::property_tree;
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
Duet::Duet(DynamicPrintConfig *config) :
|
||||
host(config->opt_string("print_host")),
|
||||
password(config->opt_string("printhost_apikey"))
|
||||
{}
|
||||
|
||||
bool Duet::test(wxString &msg) const
|
||||
{
|
||||
bool connected = connect(msg);
|
||||
if (connected) {
|
||||
disconnect();
|
||||
}
|
||||
|
||||
return connected;
|
||||
}
|
||||
|
||||
wxString Duet::get_test_ok_msg () const
|
||||
{
|
||||
return wxString::Format("%s", _(L("Connection to Duet works correctly.")));
|
||||
}
|
||||
|
||||
wxString Duet::get_test_failed_msg (wxString &msg) const
|
||||
{
|
||||
return wxString::Format("%s: %s",
|
||||
_(L("Could not connect to Duet")), msg);
|
||||
}
|
||||
|
||||
bool Duet::send_gcode(const std::string &filename) const
|
||||
{
|
||||
enum { PROGRESS_RANGE = 1000 };
|
||||
|
||||
const auto errortitle = _(L("Error while uploading to the Duet"));
|
||||
fs::path filepath(filename);
|
||||
|
||||
PrintHostSendDialog send_dialog(filepath.filename(), true);
|
||||
if (send_dialog.ShowModal() != wxID_OK) { return false; }
|
||||
|
||||
const bool print = send_dialog.print();
|
||||
const auto upload_filepath = send_dialog.filename();
|
||||
const auto upload_filename = upload_filepath.filename();
|
||||
const auto upload_parent_path = upload_filepath.parent_path();
|
||||
|
||||
wxProgressDialog progress_dialog(
|
||||
_(L("Duet upload")),
|
||||
_(L("Sending G-code file to Duet...")),
|
||||
PROGRESS_RANGE, nullptr, wxPD_AUTO_HIDE | wxPD_APP_MODAL | wxPD_CAN_ABORT);
|
||||
progress_dialog.Pulse();
|
||||
|
||||
wxString connect_msg;
|
||||
if (!connect(connect_msg)) {
|
||||
auto errormsg = wxString::Format("%s: %s", errortitle, connect_msg);
|
||||
GUI::show_error(&progress_dialog, std::move(errormsg));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool res = true;
|
||||
|
||||
|
||||
auto upload_cmd = get_upload_url(upload_filepath.string());
|
||||
BOOST_LOG_TRIVIAL(info) << boost::format("Duet: Uploading file %1%, filename: %2%, path: %3%, print: %4%, command: %5%")
|
||||
% filepath.string()
|
||||
% upload_filename.string()
|
||||
% upload_parent_path.string()
|
||||
% print
|
||||
% upload_cmd;
|
||||
|
||||
auto http = Http::post(std::move(upload_cmd));
|
||||
http.postfield_add_file(filename)
|
||||
.on_complete([&](std::string body, unsigned status) {
|
||||
BOOST_LOG_TRIVIAL(debug) << boost::format("Duet: File uploaded: HTTP %1%: %2%") % status % body;
|
||||
progress_dialog.Update(PROGRESS_RANGE);
|
||||
|
||||
int err_code = get_err_code_from_body(body);
|
||||
switch (err_code) {
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
auto msg = format_error(body, L("Unknown error occured"), 0);
|
||||
GUI::show_error(&progress_dialog, std::move(msg));
|
||||
res = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (err_code == 0 && print) {
|
||||
wxString errormsg;
|
||||
res = start_print(errormsg, upload_filepath.string());
|
||||
if (!res) {
|
||||
GUI::show_error(&progress_dialog, std::move(errormsg));
|
||||
}
|
||||
}
|
||||
})
|
||||
.on_error([&](std::string body, std::string error, unsigned status) {
|
||||
BOOST_LOG_TRIVIAL(error) << boost::format("Duet: Error uploading file: %1%, HTTP %2%, body: `%3%`") % error % status % body;
|
||||
auto errormsg = wxString::Format("%s: %s", errortitle, format_error(body, error, status));
|
||||
GUI::show_error(&progress_dialog, std::move(errormsg));
|
||||
res = false;
|
||||
})
|
||||
.on_progress([&](Http::Progress progress, bool &cancel) {
|
||||
if (cancel) {
|
||||
// Upload was canceled
|
||||
res = false;
|
||||
} else if (progress.ultotal > 0) {
|
||||
int value = PROGRESS_RANGE * progress.ulnow / progress.ultotal;
|
||||
cancel = !progress_dialog.Update(std::min(value, PROGRESS_RANGE - 1)); // Cap the value to prevent premature dialog closing
|
||||
} else {
|
||||
cancel = !progress_dialog.Pulse();
|
||||
}
|
||||
})
|
||||
.perform_sync();
|
||||
|
||||
disconnect();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool Duet::have_auto_discovery() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Duet::can_test() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Duet::connect(wxString &msg) const
|
||||
{
|
||||
bool res = false;
|
||||
auto url = get_connect_url();
|
||||
|
||||
auto http = Http::get(std::move(url));
|
||||
http.on_error([&](std::string body, std::string error, unsigned status) {
|
||||
BOOST_LOG_TRIVIAL(error) << boost::format("Duet: Error connecting: %1%, HTTP %2%, body: `%3%`") % error % status % body;
|
||||
msg = format_error(body, error, status);
|
||||
})
|
||||
.on_complete([&](std::string body, unsigned) {
|
||||
BOOST_LOG_TRIVIAL(debug) << boost::format("Duet: Got: %1%") % body;
|
||||
|
||||
int err_code = get_err_code_from_body(body);
|
||||
switch (err_code) {
|
||||
case 0:
|
||||
res = true;
|
||||
break;
|
||||
case 1:
|
||||
msg = format_error(body, L("Wrong password"), 0);
|
||||
break;
|
||||
case 2:
|
||||
msg = format_error(body, L("Could not get resources to create a new connection"), 0);
|
||||
break;
|
||||
default:
|
||||
msg = format_error(body, L("Unknown error occured"), 0);
|
||||
break;
|
||||
}
|
||||
|
||||
})
|
||||
.perform_sync();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void Duet::disconnect() const
|
||||
{
|
||||
auto url = (boost::format("%1%rr_disconnect")
|
||||
% get_base_url()).str();
|
||||
|
||||
auto http = Http::get(std::move(url));
|
||||
http.on_error([&](std::string body, std::string error, unsigned status) {
|
||||
// we don't care about it, if disconnect is not working Duet will disconnect automatically after some time
|
||||
BOOST_LOG_TRIVIAL(error) << boost::format("Duet: Error disconnecting: %1%, HTTP %2%, body: `%3%`") % error % status % body;
|
||||
})
|
||||
.perform_sync();
|
||||
|
||||
}
|
||||
|
||||
std::string Duet::get_upload_url(const std::string &filename) const
|
||||
{
|
||||
return (boost::format("%1%rr_upload?name=0:/gcodes/%2%&%3%")
|
||||
% get_base_url()
|
||||
% filename
|
||||
% timestamp_str()).str();
|
||||
}
|
||||
|
||||
std::string Duet::get_connect_url() const
|
||||
{
|
||||
return (boost::format("%1%rr_connect?password=%2%&%3%")
|
||||
% get_base_url()
|
||||
% (password.empty() ? "reprap" : password)
|
||||
% timestamp_str()).str();
|
||||
}
|
||||
|
||||
std::string Duet::get_base_url() const
|
||||
{
|
||||
if (host.find("http://") == 0 || host.find("https://") == 0) {
|
||||
if (host.back() == '/') {
|
||||
return host;
|
||||
} else {
|
||||
return (boost::format("%1%/") % host).str();
|
||||
}
|
||||
} else {
|
||||
return (boost::format("http://%1%/") % host).str();
|
||||
}
|
||||
}
|
||||
|
||||
std::string Duet::timestamp_str() const
|
||||
{
|
||||
auto t = std::time(nullptr);
|
||||
auto tm = *std::localtime(&t);
|
||||
std::stringstream ss;
|
||||
ss << "time=" << std::put_time(&tm, "%Y-%d-%mT%H:%M:%S");
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
wxString Duet::format_error(const std::string &body, const std::string &error, unsigned status)
|
||||
{
|
||||
if (status != 0) {
|
||||
auto wxbody = wxString::FromUTF8(body.data());
|
||||
return wxString::Format("HTTP %u: %s", status, wxbody);
|
||||
} else {
|
||||
return wxString::FromUTF8(error.data());
|
||||
}
|
||||
}
|
||||
|
||||
bool Duet::start_print(wxString &msg, const std::string &filename) const {
|
||||
bool res = false;
|
||||
auto url = (boost::format("%1%rr_gcode?gcode=M32%%20\"%2%\"")
|
||||
% get_base_url()
|
||||
% filename).str();
|
||||
|
||||
auto http = Http::get(std::move(url));
|
||||
http.on_error([&](std::string body, std::string error, unsigned status) {
|
||||
BOOST_LOG_TRIVIAL(error) << boost::format("Duet: Error starting print: %1%, HTTP %2%, body: `%3%`") % error % status % body;
|
||||
msg = format_error(body, error, status);
|
||||
})
|
||||
.on_complete([&](std::string body, unsigned) {
|
||||
BOOST_LOG_TRIVIAL(debug) << boost::format("Duet: Got: %1%") % body;
|
||||
res = true;
|
||||
})
|
||||
.perform_sync();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int Duet::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<int>("err", 0);
|
||||
}
|
||||
|
||||
|
||||
}
|
46
xs/src/slic3r/Utils/Duet.hpp
Normal file
46
xs/src/slic3r/Utils/Duet.hpp
Normal file
@ -0,0 +1,46 @@
|
||||
#ifndef slic3r_Duet_hpp_
|
||||
#define slic3r_Duet_hpp_
|
||||
|
||||
#include <string>
|
||||
#include <wx/string.h>
|
||||
|
||||
#include "PrintHost.hpp"
|
||||
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
|
||||
class DynamicPrintConfig;
|
||||
class Http;
|
||||
|
||||
class Duet : public PrintHost
|
||||
{
|
||||
public:
|
||||
Duet(DynamicPrintConfig *config);
|
||||
|
||||
bool test(wxString &curl_msg) const;
|
||||
wxString get_test_ok_msg () const;
|
||||
wxString get_test_failed_msg (wxString &msg) const;
|
||||
// Send gcode file to duet, filename is expected to be in UTF-8
|
||||
bool send_gcode(const std::string &filename) const;
|
||||
bool have_auto_discovery() const;
|
||||
bool can_test() const;
|
||||
private:
|
||||
std::string host;
|
||||
std::string password;
|
||||
|
||||
std::string get_upload_url(const std::string &filename) const;
|
||||
std::string get_connect_url() const;
|
||||
std::string get_base_url() const;
|
||||
std::string timestamp_str() const;
|
||||
bool connect(wxString &msg) const;
|
||||
void disconnect() const;
|
||||
bool start_print(wxString &msg, const std::string &filename) const;
|
||||
int get_err_code_from_body(const std::string &body) const;
|
||||
static wxString format_error(const std::string &body, const std::string &error, unsigned status);
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -4,6 +4,7 @@
|
||||
#include <functional>
|
||||
#include <thread>
|
||||
#include <deque>
|
||||
#include <sstream>
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
#include <boost/format.hpp>
|
||||
|
||||
@ -42,6 +43,7 @@ struct Http::priv
|
||||
// Used for storing file streams added as multipart form parts
|
||||
// Using a deque here because unlike vector it doesn't ivalidate pointers on insertion
|
||||
std::deque<fs::ifstream> form_files;
|
||||
std::string postfields;
|
||||
size_t limit;
|
||||
bool cancel;
|
||||
|
||||
@ -60,6 +62,7 @@ struct Http::priv
|
||||
static size_t form_file_read_cb(char *buffer, size_t size, size_t nitems, void *userp);
|
||||
|
||||
void form_add_file(const char *name, const fs::path &path, const char* filename);
|
||||
void postfield_add_file(const fs::path &path);
|
||||
|
||||
std::string curl_error(CURLcode curlcode);
|
||||
std::string body_size_error();
|
||||
@ -187,6 +190,16 @@ void Http::priv::form_add_file(const char *name, const fs::path &path, const cha
|
||||
}
|
||||
}
|
||||
|
||||
void Http::priv::postfield_add_file(const fs::path &path)
|
||||
{
|
||||
std::ifstream f (path.string());
|
||||
std::string file_content { std::istreambuf_iterator<char>(f), std::istreambuf_iterator<char>() };
|
||||
if (!postfields.empty()) {
|
||||
postfields += "&";
|
||||
}
|
||||
postfields += file_content;
|
||||
}
|
||||
|
||||
std::string Http::priv::curl_error(CURLcode curlcode)
|
||||
{
|
||||
return (boost::format("%1% (%2%)")
|
||||
@ -229,6 +242,11 @@ void Http::priv::http_perform()
|
||||
::curl_easy_setopt(curl, CURLOPT_HTTPPOST, form);
|
||||
}
|
||||
|
||||
if (!postfields.empty()) {
|
||||
::curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postfields.c_str());
|
||||
::curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE, postfields.size());
|
||||
}
|
||||
|
||||
CURLcode res = ::curl_easy_perform(curl);
|
||||
|
||||
if (res != CURLE_OK) {
|
||||
@ -338,6 +356,12 @@ Http& Http::form_add_file(const std::string &name, const fs::path &path, const s
|
||||
return *this;
|
||||
}
|
||||
|
||||
Http& Http::postfield_add_file(const fs::path &path)
|
||||
{
|
||||
if (p) { p->postfield_add_file(path);}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Http& Http::on_complete(CompleteFn fn)
|
||||
{
|
||||
if (p) { p->completefn = std::move(fn); }
|
||||
|
@ -73,6 +73,9 @@ public:
|
||||
// Same as above except also override the file's filename with a custom one
|
||||
Http& form_add_file(const std::string &name, const boost::filesystem::path &path, const std::string &filename);
|
||||
|
||||
// Add the file as POSTFIELD to the request, this can be used for hosts which do not support multipart requests
|
||||
Http& postfield_add_file(const boost::filesystem::path &path);
|
||||
|
||||
// Callback called on HTTP request complete
|
||||
Http& on_complete(CompleteFn fn);
|
||||
// Callback called on an error occuring at any stage of the requests: Url parsing, DNS lookup,
|
||||
|
@ -1,21 +1,11 @@
|
||||
#include "OctoPrint.hpp"
|
||||
#include "PrintHostSendDialog.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/log/trivial.hpp>
|
||||
|
||||
#include <wx/frame.h>
|
||||
#include <wx/event.h>
|
||||
#include <wx/progdlg.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/stattext.h>
|
||||
#include <wx/textctrl.h>
|
||||
#include <wx/checkbox.h>
|
||||
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
#include "slic3r/GUI/GUI.hpp"
|
||||
#include "slic3r/GUI/MsgDialog.hpp"
|
||||
#include "Http.hpp"
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
@ -23,47 +13,10 @@ namespace fs = boost::filesystem;
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
|
||||
struct SendDialog : public GUI::MsgDialog
|
||||
{
|
||||
wxTextCtrl *txt_filename;
|
||||
wxCheckBox *box_print;
|
||||
|
||||
SendDialog(const fs::path &path) :
|
||||
MsgDialog(nullptr, _(L("Send G-Code to printer")), _(L("Upload to OctoPrint with the following filename:")), wxID_NONE),
|
||||
txt_filename(new wxTextCtrl(this, wxID_ANY, path.filename().wstring())),
|
||||
box_print(new wxCheckBox(this, wxID_ANY, _(L("Start printing after upload"))))
|
||||
{
|
||||
auto *label_dir_hint = new wxStaticText(this, wxID_ANY, _(L("Use forward slashes ( / ) as a directory separator if needed.")));
|
||||
label_dir_hint->Wrap(CONTENT_WIDTH);
|
||||
|
||||
content_sizer->Add(txt_filename, 0, wxEXPAND);
|
||||
content_sizer->Add(label_dir_hint);
|
||||
content_sizer->AddSpacer(VERT_SPACING);
|
||||
content_sizer->Add(box_print, 0, wxBOTTOM, 2*VERT_SPACING);
|
||||
|
||||
btn_sizer->Add(CreateStdDialogButtonSizer(wxOK | wxCANCEL));
|
||||
|
||||
txt_filename->SetFocus();
|
||||
wxString stem(path.stem().wstring());
|
||||
txt_filename->SetSelection(0, stem.Length());
|
||||
|
||||
Fit();
|
||||
}
|
||||
|
||||
fs::path filename() const {
|
||||
return fs::path(txt_filename->GetValue().wx_str());
|
||||
}
|
||||
|
||||
bool print() const { return box_print->GetValue(); }
|
||||
};
|
||||
|
||||
|
||||
|
||||
OctoPrint::OctoPrint(DynamicPrintConfig *config) :
|
||||
host(config->opt_string("octoprint_host")),
|
||||
apikey(config->opt_string("octoprint_apikey")),
|
||||
cafile(config->opt_string("octoprint_cafile"))
|
||||
host(config->opt_string("print_host")),
|
||||
apikey(config->opt_string("printhost_apikey")),
|
||||
cafile(config->opt_string("printhost_cafile"))
|
||||
{}
|
||||
|
||||
bool OctoPrint::test(wxString &msg) const
|
||||
@ -91,6 +44,17 @@ bool OctoPrint::test(wxString &msg) const
|
||||
return res;
|
||||
}
|
||||
|
||||
wxString OctoPrint::get_test_ok_msg () const
|
||||
{
|
||||
return wxString::Format("%s", _(L("Connection to OctoPrint works correctly.")));
|
||||
}
|
||||
|
||||
wxString OctoPrint::get_test_failed_msg (wxString &msg) const
|
||||
{
|
||||
return wxString::Format("%s: %s\n\n%s",
|
||||
_(L("Could not connect to OctoPrint")), msg, _(L("Note: OctoPrint version at least 1.1.0 is required.")));
|
||||
}
|
||||
|
||||
bool OctoPrint::send_gcode(const std::string &filename) const
|
||||
{
|
||||
enum { PROGRESS_RANGE = 1000 };
|
||||
@ -98,7 +62,7 @@ bool OctoPrint::send_gcode(const std::string &filename) const
|
||||
const auto errortitle = _(L("Error while uploading to the OctoPrint server"));
|
||||
fs::path filepath(filename);
|
||||
|
||||
SendDialog send_dialog(filepath.filename());
|
||||
PrintHostSendDialog send_dialog(filepath.filename(), true);
|
||||
if (send_dialog.ShowModal() != wxID_OK) { return false; }
|
||||
|
||||
const bool print = send_dialog.print();
|
||||
@ -161,6 +125,16 @@ bool OctoPrint::send_gcode(const std::string &filename) const
|
||||
return res;
|
||||
}
|
||||
|
||||
bool OctoPrint::have_auto_discovery() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OctoPrint::can_test() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void OctoPrint::set_auth(Http &http) const
|
||||
{
|
||||
http.header("X-Api-Key", apikey);
|
||||
|
@ -4,6 +4,8 @@
|
||||
#include <string>
|
||||
#include <wx/string.h>
|
||||
|
||||
#include "PrintHost.hpp"
|
||||
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
@ -11,14 +13,18 @@ namespace Slic3r {
|
||||
class DynamicPrintConfig;
|
||||
class Http;
|
||||
|
||||
class OctoPrint
|
||||
class OctoPrint : public PrintHost
|
||||
{
|
||||
public:
|
||||
OctoPrint(DynamicPrintConfig *config);
|
||||
|
||||
bool test(wxString &curl_msg) const;
|
||||
wxString get_test_ok_msg () const;
|
||||
wxString get_test_failed_msg (wxString &msg) const;
|
||||
// Send gcode file to octoprint, filename is expected to be in UTF-8
|
||||
bool send_gcode(const std::string &filename) const;
|
||||
bool have_auto_discovery() const;
|
||||
bool can_test() const;
|
||||
private:
|
||||
std::string host;
|
||||
std::string apikey;
|
||||
|
31
xs/src/slic3r/Utils/PrintHost.hpp
Normal file
31
xs/src/slic3r/Utils/PrintHost.hpp
Normal file
@ -0,0 +1,31 @@
|
||||
#ifndef slic3r_PrintHost_hpp_
|
||||
#define slic3r_PrintHost_hpp_
|
||||
|
||||
#include <string>
|
||||
#include <wx/string.h>
|
||||
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
|
||||
class DynamicPrintConfig;
|
||||
|
||||
class PrintHost
|
||||
{
|
||||
public:
|
||||
|
||||
virtual bool test(wxString &curl_msg) const = 0;
|
||||
virtual wxString get_test_ok_msg () const = 0;
|
||||
virtual wxString get_test_failed_msg (wxString &msg) const = 0;
|
||||
// Send gcode file to print host, filename is expected to be in UTF-8
|
||||
virtual bool send_gcode(const std::string &filename) const = 0;
|
||||
virtual bool have_auto_discovery() const = 0;
|
||||
virtual bool can_test() const = 0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
21
xs/src/slic3r/Utils/PrintHostFactory.cpp
Normal file
21
xs/src/slic3r/Utils/PrintHostFactory.cpp
Normal file
@ -0,0 +1,21 @@
|
||||
#include "PrintHostFactory.hpp"
|
||||
#include "OctoPrint.hpp"
|
||||
#include "Duet.hpp"
|
||||
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
|
||||
PrintHost * PrintHostFactory::get_print_host(DynamicPrintConfig *config)
|
||||
{
|
||||
PrintHostType kind = config->option<ConfigOptionEnum<PrintHostType>>("host_type")->value;
|
||||
if (kind == htOctoPrint) {
|
||||
return new OctoPrint(config);
|
||||
} else if (kind == htDuet) {
|
||||
return new Duet(config);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
}
|
24
xs/src/slic3r/Utils/PrintHostFactory.hpp
Normal file
24
xs/src/slic3r/Utils/PrintHostFactory.hpp
Normal file
@ -0,0 +1,24 @@
|
||||
#ifndef slic3r_PrintHostFactory_hpp_
|
||||
#define slic3r_PrintHostFactory_hpp_
|
||||
|
||||
#include <string>
|
||||
#include <wx/string.h>
|
||||
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class DynamicPrintConfig;
|
||||
class PrintHost;
|
||||
|
||||
class PrintHostFactory
|
||||
{
|
||||
public:
|
||||
PrintHostFactory() {};
|
||||
~PrintHostFactory() {};
|
||||
static PrintHost * get_print_host(DynamicPrintConfig *config);
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
54
xs/src/slic3r/Utils/PrintHostSendDialog.cpp
Normal file
54
xs/src/slic3r/Utils/PrintHostSendDialog.cpp
Normal file
@ -0,0 +1,54 @@
|
||||
#include "PrintHostSendDialog.hpp"
|
||||
|
||||
#include <wx/frame.h>
|
||||
#include <wx/event.h>
|
||||
#include <wx/progdlg.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/stattext.h>
|
||||
#include <wx/textctrl.h>
|
||||
#include <wx/checkbox.h>
|
||||
|
||||
#include "slic3r/GUI/GUI.hpp"
|
||||
#include "slic3r/GUI/MsgDialog.hpp"
|
||||
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
PrintHostSendDialog::PrintHostSendDialog(const fs::path &path, bool can_start_print) :
|
||||
MsgDialog(nullptr, _(L("Send G-Code to printer host")), _(L("Upload to Printer Host with the following filename:")), wxID_NONE),
|
||||
txt_filename(new wxTextCtrl(this, wxID_ANY, path.filename().wstring())),
|
||||
box_print(new wxCheckBox(this, wxID_ANY, _(L("Start printing after upload")))),
|
||||
can_start_print(can_start_print)
|
||||
{
|
||||
auto *label_dir_hint = new wxStaticText(this, wxID_ANY, _(L("Use forward slashes ( / ) as a directory separator if needed.")));
|
||||
label_dir_hint->Wrap(CONTENT_WIDTH);
|
||||
|
||||
content_sizer->Add(txt_filename, 0, wxEXPAND);
|
||||
content_sizer->Add(label_dir_hint);
|
||||
content_sizer->AddSpacer(VERT_SPACING);
|
||||
content_sizer->Add(box_print, 0, wxBOTTOM, 2*VERT_SPACING);
|
||||
|
||||
btn_sizer->Add(CreateStdDialogButtonSizer(wxOK | wxCANCEL));
|
||||
|
||||
txt_filename->SetFocus();
|
||||
wxString stem(path.stem().wstring());
|
||||
txt_filename->SetSelection(0, stem.Length());
|
||||
|
||||
if (!can_start_print) {
|
||||
box_print->Disable();
|
||||
}
|
||||
|
||||
Fit();
|
||||
}
|
||||
|
||||
fs::path PrintHostSendDialog::filename() const
|
||||
{
|
||||
return fs::path(txt_filename->GetValue().wx_str());
|
||||
}
|
||||
|
||||
bool PrintHostSendDialog::print() const
|
||||
{
|
||||
return box_print->GetValue(); }
|
||||
}
|
40
xs/src/slic3r/Utils/PrintHostSendDialog.hpp
Normal file
40
xs/src/slic3r/Utils/PrintHostSendDialog.hpp
Normal file
@ -0,0 +1,40 @@
|
||||
#ifndef slic3r_PrintHostSendDialog_hpp_
|
||||
#define slic3r_PrintHostSendDialog_hpp_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <boost/filesystem/path.hpp>
|
||||
|
||||
#include <wx/string.h>
|
||||
#include <wx/frame.h>
|
||||
#include <wx/event.h>
|
||||
#include <wx/progdlg.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/stattext.h>
|
||||
#include <wx/textctrl.h>
|
||||
#include <wx/checkbox.h>
|
||||
|
||||
#include "slic3r/GUI/GUI.hpp"
|
||||
#include "slic3r/GUI/MsgDialog.hpp"
|
||||
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class PrintHostSendDialog : public GUI::MsgDialog
|
||||
{
|
||||
|
||||
private:
|
||||
wxTextCtrl *txt_filename;
|
||||
wxCheckBox *box_print;
|
||||
bool can_start_print;
|
||||
|
||||
public:
|
||||
|
||||
PrintHostSendDialog(const boost::filesystem::path &path, bool can_start_print);
|
||||
boost::filesystem::path filename() const;
|
||||
bool print() const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -1,13 +0,0 @@
|
||||
%module{Slic3r::XS};
|
||||
|
||||
%{
|
||||
#include <xsinit.h>
|
||||
#include "slic3r/Utils/OctoPrint.hpp"
|
||||
%}
|
||||
|
||||
%name{Slic3r::OctoPrint} class OctoPrint {
|
||||
OctoPrint(DynamicPrintConfig *config);
|
||||
~OctoPrint();
|
||||
|
||||
bool send_gcode(std::string filename) const;
|
||||
};
|
10
xs/xsp/Utils_PrintHost.xsp
Normal file
10
xs/xsp/Utils_PrintHost.xsp
Normal file
@ -0,0 +1,10 @@
|
||||
%module{Slic3r::XS};
|
||||
|
||||
%{
|
||||
#include <xsinit.h>
|
||||
#include "slic3r/Utils/PrintHost.hpp"
|
||||
%}
|
||||
|
||||
%name{Slic3r::PrintHost} class PrintHost {
|
||||
bool send_gcode(std::string filename) const;
|
||||
};
|
13
xs/xsp/Utils_PrintHostFactory.xsp
Normal file
13
xs/xsp/Utils_PrintHostFactory.xsp
Normal file
@ -0,0 +1,13 @@
|
||||
%module{Slic3r::XS};
|
||||
|
||||
%{
|
||||
#include <xsinit.h>
|
||||
#include "slic3r/Utils/PrintHostFactory.hpp"
|
||||
%}
|
||||
|
||||
%name{Slic3r::PrintHostFactory} class PrintHostFactory {
|
||||
PrintHostFactory();
|
||||
~PrintHostFactory();
|
||||
|
||||
static PrintHost * get_print_host(DynamicPrintConfig *config);
|
||||
};
|
@ -239,9 +239,11 @@ Ref<TabIface> O_OBJECT_SLIC3R_T
|
||||
PresetUpdater* O_OBJECT_SLIC3R
|
||||
Ref<PresetUpdater> O_OBJECT_SLIC3R_T
|
||||
|
||||
OctoPrint* O_OBJECT_SLIC3R
|
||||
Ref<OctoPrint> O_OBJECT_SLIC3R_T
|
||||
Clone<OctoPrint> O_OBJECT_SLIC3R_T
|
||||
PrintHostFactory* O_OBJECT_SLIC3R
|
||||
Ref<PrintHostFactory> O_OBJECT_SLIC3R_T
|
||||
Clone<PrintHostFactory> O_OBJECT_SLIC3R_T
|
||||
|
||||
PrintHost* O_OBJECT_SLIC3R
|
||||
|
||||
Axis T_UV
|
||||
ExtrusionLoopRole T_UV
|
||||
|
@ -270,3 +270,4 @@
|
||||
};
|
||||
%typemap{AppController*};
|
||||
%typemap{PrintController*};
|
||||
%typemap{PrintHost*};
|
||||
|
Loading…
Reference in New Issue
Block a user