mirror of
https://github.com/QIDITECH/QIDISlicer.git
synced 2026-02-02 00:48:43 +03:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0503b60f30 | ||
|
|
bcfcfdf58d | ||
|
|
e318ad1cc3 | ||
|
|
144552bd81 | ||
|
|
529153d41d | ||
|
|
d761a503ca | ||
|
|
b4fa60892c | ||
|
|
f1b81b3d38 | ||
|
|
9dbc216996 |
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,5 @@
|
|||||||
|
min_slic3r_version = 1.0.4
|
||||||
|
1.0.4 Modify start code
|
||||||
min_slic3r_version = 1.0.3
|
min_slic3r_version = 1.0.3
|
||||||
1.0.3 Delete filament property
|
1.0.3 Delete filament property
|
||||||
min_slic3r_version = 1.0.2
|
min_slic3r_version = 1.0.2
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
name = QIDI Technology
|
name = QIDI Technology
|
||||||
# Configuration version of this file. Config file will only be installed, if the config_version differs.
|
# Configuration version of this file. Config file will only be installed, if the config_version differs.
|
||||||
# This means, the server may force the PrusaSlicer configuration to be downgraded.
|
# This means, the server may force the PrusaSlicer configuration to be downgraded.
|
||||||
config_version = 1.0.3
|
config_version = 1.0.4
|
||||||
# Where to get the updates from?
|
# Where to get the updates from?
|
||||||
config_update_url = https://github.com/QIDITECH/QIDISlicer/releases/download/QIDITechnology/
|
config_update_url = https://github.com/QIDITECH/QIDISlicer/releases/download/QIDITechnology/
|
||||||
changelog_url = https://qidi3d.com/pages/software-firmware
|
changelog_url = https://qidi3d.com/pages/software-firmware
|
||||||
@@ -338,7 +338,7 @@ inherits = *common*
|
|||||||
advance_pressure = 0.021
|
advance_pressure = 0.021
|
||||||
bed_temperature = 100
|
bed_temperature = 100
|
||||||
enable_auxiliary_fan = 0
|
enable_auxiliary_fan = 0
|
||||||
enable_volume_fan = 0
|
enable_volume_fan = 100
|
||||||
extrusion_multiplier = 0.95
|
extrusion_multiplier = 0.95
|
||||||
filament_colour = #FFC800
|
filament_colour = #FFC800
|
||||||
filament_density = 1.02
|
filament_density = 1.02
|
||||||
@@ -470,7 +470,7 @@ inherits = *common*
|
|||||||
advance_pressure = 0.021
|
advance_pressure = 0.021
|
||||||
bed_temperature = 100
|
bed_temperature = 100
|
||||||
enable_auxiliary_fan = 0
|
enable_auxiliary_fan = 0
|
||||||
enable_volume_fan = 0
|
enable_volume_fan = 100
|
||||||
extrusion_multiplier = 0.95
|
extrusion_multiplier = 0.95
|
||||||
filament_colour = #FFFF00
|
filament_colour = #FFFF00
|
||||||
filament_density = 1.04
|
filament_density = 1.04
|
||||||
@@ -747,7 +747,7 @@ retract_restart_extra_toolchange = 0
|
|||||||
retract_speed = 30
|
retract_speed = 30
|
||||||
silent_mode = 0
|
silent_mode = 0
|
||||||
single_extruder_multi_material = 0
|
single_extruder_multi_material = 0
|
||||||
start_gcode = G28\nM141 S0\nG0 Z50 F600\nM190 S[first_layer_bed_temperature]\nG28 Z\nG29\nG0 X0 Y0 Z50 F6000\nM109 S[first_layer_temperature]\nM83\nG0 X{max((min(print_bed_max[0], first_layer_print_min[0] + 80) - 85),0)} Y{max((min(print_bed_max[1], first_layer_print_min[1] + 80) - 85),0)} Z5 F6000\nG0 Z0.2 F600\nG1 E3 F1800\nG1 X{(min(print_bed_max[0], first_layer_print_min[0] + 80))} E{85 * 0.04} F3000\nG1 Y{max((min(print_bed_max[1], first_layer_print_min[1] + 80) - 85),0) + 2} E{2 * 0.04} F3000\nG1 X{max((min(print_bed_max[0], first_layer_print_min[0] + 80) - 85),0)} E{85 * 0.04} F3000\nG1 Y{max((min(print_bed_max[1], first_layer_print_min[1] + 80) - 85),0) + 85} E{83 * 0.04} F3000\nG1 X{max((min(print_bed_max[0], first_layer_print_min[0] + 80) - 85),0) + 2} E{2 * 0.04} F3000\nG1 Y{max((min(print_bed_max[1], first_layer_print_min[1] + 80) - 85),0) + 5} E{80 * 0.04} F3000
|
start_gcode = G28\nM141 S0\nG0 Z50 F600\nM190 S[first_layer_bed_temperature]\nG28 Z\nG29 ; mesh bed leveling ,comment this code to close it\nG0 X0 Y0 Z50 F6000\nM109 S[first_layer_temperature]\nM83\nG0 X{max((min(print_bed_max[0], first_layer_print_min[0] + 80) - 85),0)} Y{max((min(print_bed_max[1], first_layer_print_min[1] + 80) - 85),0)} Z5 F6000\nG0 Z0.2 F600\nG1 E3 F1800\nG1 X{(min(print_bed_max[0], first_layer_print_min[0] + 80))} E{85 * 0.04} F3000\nG1 Y{max((min(print_bed_max[1], first_layer_print_min[1] + 80) - 85),0) + 2} E{2 * 0.04} F3000\nG1 X{max((min(print_bed_max[0], first_layer_print_min[0] + 80) - 85),0)} E{85 * 0.04} F3000\nG1 Y{max((min(print_bed_max[1], first_layer_print_min[1] + 80) - 85),0) + 85} E{83 * 0.04} F3000\nG1 X{max((min(print_bed_max[0], first_layer_print_min[0] + 80) - 85),0) + 2} E{2 * 0.04} F3000\nG1 Y{max((min(print_bed_max[1], first_layer_print_min[1] + 80) - 85),0) + 3} E{82 * 0.04} F3000\nG1 X{max((min(print_bed_max[0], first_layer_print_min[0] + 80) - 85),0) + 12} E{-10 * 0.04} F3000\nG1 E{10 * 0.04} F3000
|
||||||
template_custom_gcode =
|
template_custom_gcode =
|
||||||
thumbnails =
|
thumbnails =
|
||||||
thumbnails_format = QIDI
|
thumbnails_format = QIDI
|
||||||
|
|||||||
@@ -287,6 +287,8 @@ set(SLIC3R_GUI_SOURCES
|
|||||||
Utils/PrintHost.hpp
|
Utils/PrintHost.hpp
|
||||||
Utils/Bonjour.cpp
|
Utils/Bonjour.cpp
|
||||||
Utils/Bonjour.hpp
|
Utils/Bonjour.hpp
|
||||||
|
Utils/Udp.cpp
|
||||||
|
Utils/Udp.hpp
|
||||||
Utils/PresetUpdater.cpp
|
Utils/PresetUpdater.cpp
|
||||||
Utils/PresetUpdater.hpp
|
Utils/PresetUpdater.hpp
|
||||||
Utils/Process.cpp
|
Utils/Process.cpp
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#include "slic3r/Utils/Bonjour.hpp" // On Windows, boost needs to be included before wxWidgets headers
|
#include "slic3r/Utils/Bonjour.hpp" // On Windows, boost needs to be included before wxWidgets headers
|
||||||
|
#include "slic3r/Utils/Udp.hpp"
|
||||||
#include "BonjourDialog.hpp"
|
#include "BonjourDialog.hpp"
|
||||||
|
|
||||||
#include <set>
|
#include <set>
|
||||||
@@ -19,6 +19,8 @@
|
|||||||
#include "slic3r/GUI/I18N.hpp"
|
#include "slic3r/GUI/I18N.hpp"
|
||||||
#include "slic3r/GUI/format.hpp"
|
#include "slic3r/GUI/format.hpp"
|
||||||
#include "slic3r/Utils/Bonjour.hpp"
|
#include "slic3r/Utils/Bonjour.hpp"
|
||||||
|
#include "slic3r/Utils/Udp.hpp"
|
||||||
|
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
@@ -38,13 +40,29 @@ public:
|
|||||||
return new BonjourReplyEvent(*this);
|
return new BonjourReplyEvent(*this);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
// B29
|
||||||
|
class UdpReplyEvent : public wxEvent
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
UdpReply reply;
|
||||||
|
|
||||||
|
UdpReplyEvent(wxEventType eventType, int winid, UdpReply &&reply) : wxEvent(winid, eventType), reply(std::move(reply)) {}
|
||||||
|
|
||||||
|
virtual wxEvent *Clone() const { return new UdpReplyEvent(*this); }
|
||||||
|
};
|
||||||
|
// B29
|
||||||
|
wxDEFINE_EVENT(EVT_UDP_REPLY, UdpReplyEvent);
|
||||||
|
|
||||||
wxDEFINE_EVENT(EVT_BONJOUR_REPLY, BonjourReplyEvent);
|
wxDEFINE_EVENT(EVT_BONJOUR_REPLY, BonjourReplyEvent);
|
||||||
|
|
||||||
|
wxDECLARE_EVENT(EVT_UDP_COMPLETE, wxCommandEvent);
|
||||||
|
wxDEFINE_EVENT(EVT_UDP_COMPLETE, wxCommandEvent);
|
||||||
|
|
||||||
wxDECLARE_EVENT(EVT_BONJOUR_COMPLETE, wxCommandEvent);
|
wxDECLARE_EVENT(EVT_BONJOUR_COMPLETE, wxCommandEvent);
|
||||||
wxDEFINE_EVENT(EVT_BONJOUR_COMPLETE, wxCommandEvent);
|
wxDEFINE_EVENT(EVT_BONJOUR_COMPLETE, wxCommandEvent);
|
||||||
|
|
||||||
class ReplySet: public std::set<BonjourReply> {};
|
class ReplySet: public std::set<BonjourReply> {};
|
||||||
|
class UdpReplySet : public std::set<UdpReply> {};
|
||||||
|
|
||||||
struct LifetimeGuard
|
struct LifetimeGuard
|
||||||
{
|
{
|
||||||
@@ -57,7 +75,8 @@ struct LifetimeGuard
|
|||||||
BonjourDialog::BonjourDialog(wxWindow *parent, Slic3r::PrinterTechnology tech)
|
BonjourDialog::BonjourDialog(wxWindow *parent, Slic3r::PrinterTechnology tech)
|
||||||
: wxDialog(parent, wxID_ANY, _(L("Network lookup")), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER)
|
: wxDialog(parent, wxID_ANY, _(L("Network lookup")), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER)
|
||||||
, list(new wxListView(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_REPORT|wxSIMPLE_BORDER))
|
, list(new wxListView(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_REPORT|wxSIMPLE_BORDER))
|
||||||
, replies(new ReplySet)
|
, replies(new ReplySet)
|
||||||
|
, udp_replies(new UdpReplySet)
|
||||||
, label(new wxStaticText(this, wxID_ANY, ""))
|
, label(new wxStaticText(this, wxID_ANY, ""))
|
||||||
, timer(new wxTimer())
|
, timer(new wxTimer())
|
||||||
, timer_state(0)
|
, timer_state(0)
|
||||||
@@ -72,8 +91,9 @@ BonjourDialog::BonjourDialog(wxWindow *parent, Slic3r::PrinterTechnology tech)
|
|||||||
|
|
||||||
list->SetSingleStyle(wxLC_SINGLE_SEL);
|
list->SetSingleStyle(wxLC_SINGLE_SEL);
|
||||||
list->SetSingleStyle(wxLC_SORT_DESCENDING);
|
list->SetSingleStyle(wxLC_SORT_DESCENDING);
|
||||||
list->AppendColumn(_(L("Address")), wxLIST_FORMAT_LEFT, 5 * em);
|
//B29
|
||||||
list->AppendColumn(_(L("Hostname")), wxLIST_FORMAT_LEFT, 10 * em);
|
list->AppendColumn(_(L("Address")), wxLIST_FORMAT_LEFT, 10 * em);
|
||||||
|
list->AppendColumn(_(L("Hostname")), wxLIST_FORMAT_LEFT, 15 * em);
|
||||||
list->AppendColumn(_(L("Service name")), wxLIST_FORMAT_LEFT, 20 * em);
|
list->AppendColumn(_(L("Service name")), wxLIST_FORMAT_LEFT, 20 * em);
|
||||||
if (tech == ptFFF) {
|
if (tech == ptFFF) {
|
||||||
list->AppendColumn(_(L("OctoPrint version")), wxLIST_FORMAT_LEFT, 5 * em);
|
list->AppendColumn(_(L("OctoPrint version")), wxLIST_FORMAT_LEFT, 5 * em);
|
||||||
@@ -91,9 +111,12 @@ BonjourDialog::BonjourDialog(wxWindow *parent, Slic3r::PrinterTechnology tech)
|
|||||||
|
|
||||||
Bind(EVT_BONJOUR_REPLY, &BonjourDialog::on_reply, this);
|
Bind(EVT_BONJOUR_REPLY, &BonjourDialog::on_reply, this);
|
||||||
|
|
||||||
Bind(EVT_BONJOUR_COMPLETE, [this](wxCommandEvent &) {
|
Bind(EVT_UDP_REPLY, &BonjourDialog::on_udp_reply, this);
|
||||||
this->timer_state = 0;
|
|
||||||
});
|
// B29
|
||||||
|
Bind(EVT_BONJOUR_COMPLETE, [this](wxCommandEvent &) {
|
||||||
|
this->timer_state = 0;
|
||||||
|
});
|
||||||
|
|
||||||
Bind(wxEVT_TIMER, &BonjourDialog::on_timer, this);
|
Bind(wxEVT_TIMER, &BonjourDialog::on_timer, this);
|
||||||
GUI::wxGetApp().UpdateDlgDarkUI(this);
|
GUI::wxGetApp().UpdateDlgDarkUI(this);
|
||||||
@@ -114,14 +137,41 @@ bool BonjourDialog::show_and_lookup()
|
|||||||
timer->Start(1000);
|
timer->Start(1000);
|
||||||
on_timer_process();
|
on_timer_process();
|
||||||
|
|
||||||
|
|
||||||
// The background thread needs to queue messages for this dialog
|
// The background thread needs to queue messages for this dialog
|
||||||
// and for that it needs a valid pointer to it (mandated by the wxWidgets API).
|
// and for that it needs a valid pointer to it (mandated by the wxWidgets API).
|
||||||
// Here we put the pointer under a shared_ptr and protect it by a mutex,
|
// Here we put the pointer under a shared_ptr and protect it by a mutex,
|
||||||
// so that both threads can access it safely.
|
// so that both threads can access it safely.
|
||||||
auto dguard = std::make_shared<LifetimeGuard>(this);
|
auto dguard = std::make_shared<LifetimeGuard>(this);
|
||||||
|
|
||||||
|
// B29
|
||||||
|
Udp::TxtKeys udp_txt_keys{"version", "model"};
|
||||||
|
|
||||||
|
udp = Udp("octoprint")
|
||||||
|
.set_txt_keys(std::move(udp_txt_keys))
|
||||||
|
.set_retries(3)
|
||||||
|
.set_timeout(4)
|
||||||
|
.on_udp_reply([dguard](UdpReply &&reply) {
|
||||||
|
std::lock_guard<std::mutex> lock_guard(dguard->mutex);
|
||||||
|
auto dialog = dguard->dialog;
|
||||||
|
if (dialog != nullptr) {
|
||||||
|
auto evt = new UdpReplyEvent(EVT_UDP_REPLY, dialog->GetId(), std::move(reply));
|
||||||
|
wxQueueEvent(dialog, evt);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.on_complete([dguard]() {
|
||||||
|
std::lock_guard<std::mutex> lock_guard(dguard->mutex);
|
||||||
|
auto dialog = dguard->dialog;
|
||||||
|
if (dialog != nullptr) {
|
||||||
|
auto evt = new wxCommandEvent(EVT_UDP_COMPLETE, dialog->GetId());
|
||||||
|
wxQueueEvent(dialog, evt);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.lookup();
|
||||||
|
|
||||||
|
|
||||||
// Note: More can be done here when we support discovery of hosts other than Octoprint and SL1
|
// Note: More can be done here when we support discovery of hosts other than Octoprint and SL1
|
||||||
Bonjour::TxtKeys txt_keys { "version", "model" };
|
Bonjour::TxtKeys txt_keys{"version", "model"};
|
||||||
|
|
||||||
bonjour = Bonjour("octoprint")
|
bonjour = Bonjour("octoprint")
|
||||||
.set_txt_keys(std::move(txt_keys))
|
.set_txt_keys(std::move(txt_keys))
|
||||||
@@ -165,56 +215,110 @@ wxString BonjourDialog::get_selected() const
|
|||||||
|
|
||||||
void BonjourDialog::on_reply(BonjourReplyEvent &e)
|
void BonjourDialog::on_reply(BonjourReplyEvent &e)
|
||||||
{
|
{
|
||||||
if (replies->find(e.reply) != replies->end()) {
|
if (replies->find(e.reply) != replies->end()) {
|
||||||
// We already have this reply
|
// We already have this reply
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filter replies based on selected technology
|
// Filter replies based on selected technology
|
||||||
const auto model = e.reply.txt_data.find("model");
|
const auto model = e.reply.txt_data.find("model");
|
||||||
const bool sl1 = model != e.reply.txt_data.end() && model->second == "SL1";
|
const bool sl1 = model != e.reply.txt_data.end() && model->second == "SL1";
|
||||||
if ((tech == ptFFF && sl1) || (tech == ptSLA && !sl1)) {
|
if ((tech == ptFFF && sl1) || (tech == ptSLA && !sl1)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
replies->insert(std::move(e.reply));
|
replies->insert(std::move(e.reply));
|
||||||
|
|
||||||
auto selected = get_selected();
|
auto selected = get_selected();
|
||||||
|
|
||||||
wxWindowUpdateLocker freeze_guard(this);
|
wxWindowUpdateLocker freeze_guard(this);
|
||||||
(void)freeze_guard;
|
(void) freeze_guard;
|
||||||
|
|
||||||
list->DeleteAllItems();
|
list->DeleteAllItems();
|
||||||
|
|
||||||
// The whole list is recreated so that we benefit from it already being sorted in the set.
|
// The whole list is recreated so that we benefit from it already being sorted in the set.
|
||||||
// (And also because wxListView's sorting API is bananas.)
|
// (And also because wxListView's sorting API is bananas.)
|
||||||
for (const auto &reply : *replies) {
|
for (const auto &reply : *replies) {
|
||||||
auto item = list->InsertItem(0, reply.full_address);
|
auto item = list->InsertItem(0, reply.full_address);
|
||||||
list->SetItem(item, 1, reply.hostname);
|
list->SetItem(item, 1, reply.hostname);
|
||||||
list->SetItem(item, 2, reply.service_name);
|
list->SetItem(item, 2, reply.service_name);
|
||||||
|
|
||||||
if (tech == ptFFF) {
|
if (tech == ptFFF) {
|
||||||
const auto it = reply.txt_data.find("version");
|
const auto it = reply.txt_data.find("version");
|
||||||
if (it != reply.txt_data.end()) {
|
if (it != reply.txt_data.end()) {
|
||||||
list->SetItem(item, 3, GUI::from_u8(it->second));
|
list->SetItem(item, 3, GUI::from_u8(it->second));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const int em = GUI::wxGetApp().em_unit();
|
const int em = GUI::wxGetApp().em_unit();
|
||||||
|
|
||||||
for (int i = 0; i < list->GetColumnCount(); i++) {
|
for (int i = 0; i < list->GetColumnCount(); i++) {
|
||||||
list->SetColumnWidth(i, wxLIST_AUTOSIZE);
|
list->SetColumnWidth(i, wxLIST_AUTOSIZE);
|
||||||
if (list->GetColumnWidth(i) < 10 * em) { list->SetColumnWidth(i, 10 * em); }
|
if (list->GetColumnWidth(i) < 10 * em) {
|
||||||
}
|
list->SetColumnWidth(i, 10 * em);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!selected.IsEmpty()) {
|
if (!selected.IsEmpty()) {
|
||||||
// Attempt to preserve selection
|
// Attempt to preserve selection
|
||||||
auto hit = list->FindItem(-1, selected);
|
auto hit = list->FindItem(-1, selected);
|
||||||
if (hit >= 0) { list->SetItemState(hit, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED); }
|
if (hit >= 0) {
|
||||||
}
|
list->SetItemState(hit, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// B29
|
||||||
|
void BonjourDialog::on_udp_reply(UdpReplyEvent &e)
|
||||||
|
{
|
||||||
|
if (udp_replies->find(e.reply) != udp_replies->end()) {
|
||||||
|
// We already have this reply
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//// Filter replies based on selected technology
|
||||||
|
// const auto model = e.reply.txt_data.find("model");
|
||||||
|
// const bool sl1 = model != e.reply.txt_data.end() && model->second == "SL1";
|
||||||
|
// if ((tech == ptFFF && sl1) || (tech == ptSLA && !sl1)) {
|
||||||
|
// return;
|
||||||
|
//}
|
||||||
|
|
||||||
|
udp_replies->insert(std::move(e.reply));
|
||||||
|
|
||||||
|
auto selected = get_selected();
|
||||||
|
|
||||||
|
wxWindowUpdateLocker freeze_guard(this);
|
||||||
|
(void) freeze_guard;
|
||||||
|
|
||||||
|
list->DeleteAllItems();
|
||||||
|
|
||||||
|
// The whole list is recreated so that we benefit from it already being sorted in the set.
|
||||||
|
// (And also because wxListView's sorting API is bananas.)
|
||||||
|
for (const auto &reply : *udp_replies) {
|
||||||
|
auto item = list->InsertItem(0, reply.service_name);
|
||||||
|
list->SetItem(item, 1, reply.hostname);
|
||||||
|
}
|
||||||
|
|
||||||
|
const int em = GUI::wxGetApp().em_unit();
|
||||||
|
|
||||||
|
for (int i = 0; i < list->GetColumnCount(); i++) {
|
||||||
|
list->SetColumnWidth(i, wxLIST_AUTOSIZE);
|
||||||
|
if (list->GetColumnWidth(i) < 10 * em) {
|
||||||
|
list->SetColumnWidth(i, 10 * em);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!selected.IsEmpty()) {
|
||||||
|
// Attempt to preserve selection
|
||||||
|
auto hit = list->FindItem(-1, selected);
|
||||||
|
if (hit >= 0) {
|
||||||
|
list->SetItemState(hit, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void BonjourDialog::on_timer(wxTimerEvent &)
|
void BonjourDialog::on_timer(wxTimerEvent &)
|
||||||
{
|
{
|
||||||
on_timer_process();
|
on_timer_process();
|
||||||
|
|||||||
@@ -20,9 +20,14 @@ class address;
|
|||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
class Bonjour;
|
class Bonjour;
|
||||||
|
//B29
|
||||||
|
class Udp;
|
||||||
class BonjourReplyEvent;
|
class BonjourReplyEvent;
|
||||||
|
//B29
|
||||||
|
class UdpReplyEvent;
|
||||||
class ReplySet;
|
class ReplySet;
|
||||||
|
//B29
|
||||||
|
class UdpReplySet;
|
||||||
|
|
||||||
class BonjourDialog: public wxDialog
|
class BonjourDialog: public wxDialog
|
||||||
{
|
{
|
||||||
@@ -39,13 +44,19 @@ public:
|
|||||||
private:
|
private:
|
||||||
wxListView *list;
|
wxListView *list;
|
||||||
std::unique_ptr<ReplySet> replies;
|
std::unique_ptr<ReplySet> replies;
|
||||||
|
//B29
|
||||||
|
std::unique_ptr<UdpReplySet> udp_replies;
|
||||||
wxStaticText *label;
|
wxStaticText *label;
|
||||||
std::shared_ptr<Bonjour> bonjour;
|
std::shared_ptr<Bonjour> bonjour;
|
||||||
|
//B29
|
||||||
|
std::shared_ptr<Udp> udp;
|
||||||
std::unique_ptr<wxTimer> timer;
|
std::unique_ptr<wxTimer> timer;
|
||||||
unsigned timer_state;
|
unsigned timer_state;
|
||||||
Slic3r::PrinterTechnology tech;
|
Slic3r::PrinterTechnology tech;
|
||||||
|
|
||||||
virtual void on_reply(BonjourReplyEvent &);
|
virtual void on_reply(BonjourReplyEvent &);
|
||||||
|
//B29
|
||||||
|
virtual void on_udp_reply(UdpReplyEvent &);
|
||||||
void on_timer(wxTimerEvent &);
|
void on_timer(wxTimerEvent &);
|
||||||
void on_timer_process();
|
void on_timer_process();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2085,13 +2085,15 @@ void MainFrame::select_tab(size_t tab/* = size_t(-1)*/)
|
|||||||
m_printer_view->load_url(url);
|
m_printer_view->load_url(url);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//B4
|
// B30
|
||||||
#ifdef __APPLE__
|
if (m_tabpanel->GetSelection() != (int) new_selection && m_tabpanel->GetSelection() < 4)
|
||||||
if (count == 0 && m_tabpanel->GetSelection() != (int) new_selection) {
|
|
||||||
m_tabpanel->SetSelection(new_selection);
|
m_tabpanel->SetSelection(new_selection);
|
||||||
count++;
|
//#ifdef __APPLE__
|
||||||
}
|
// if (count == 0 && m_tabpanel->GetSelection() != (int) new_selection) {
|
||||||
#endif
|
// m_tabpanel->SetSelection(new_selection);
|
||||||
|
// count++;
|
||||||
|
// }
|
||||||
|
//#endif
|
||||||
|
|
||||||
#ifdef _MSW_DARK_MODE
|
#ifdef _MSW_DARK_MODE
|
||||||
if (wxGetApp().tabs_as_menu()) {
|
if (wxGetApp().tabs_as_menu()) {
|
||||||
|
|||||||
@@ -377,9 +377,12 @@ void PresetComboBox::add_physical_printer()
|
|||||||
|
|
||||||
void PresetComboBox::open_physical_printer_url()
|
void PresetComboBox::open_physical_printer_url()
|
||||||
{
|
{
|
||||||
const PhysicalPrinter& pp = m_preset_bundle->physical_printers.get_selected_printer();
|
const PhysicalPrinter &pp = m_preset_bundle->physical_printers.get_selected_printer();
|
||||||
std::string host = pp.config.opt_string("print_host");
|
std::string host = pp.config.opt_string("print_host");
|
||||||
assert(!host.empty());
|
assert(!host.empty());
|
||||||
|
// B31
|
||||||
|
if (host.find(":10088") == -1)
|
||||||
|
host = host + ":10088";
|
||||||
wxGetApp().open_browser_with_warning_dialog(host);
|
wxGetApp().open_browser_with_warning_dialog(host);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
1228
src/slic3r/Utils/Udp.cpp
Normal file
1228
src/slic3r/Utils/Udp.cpp
Normal file
File diff suppressed because it is too large
Load Diff
289
src/slic3r/Utils/Udp.hpp
Normal file
289
src/slic3r/Utils/Udp.hpp
Normal file
@@ -0,0 +1,289 @@
|
|||||||
|
#ifndef slic3r_Udp_hpp_
|
||||||
|
#define slic3r_Udp_hpp_
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <set>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
#include <boost/asio.hpp>
|
||||||
|
#include <boost/asio/ip/address.hpp>
|
||||||
|
#include <boost/optional.hpp>
|
||||||
|
#include <boost/system/error_code.hpp>
|
||||||
|
#include <boost/shared_ptr.hpp>
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
struct UdpReply
|
||||||
|
{
|
||||||
|
typedef std::unordered_map<std::string, std::string> TxtData;
|
||||||
|
|
||||||
|
boost::asio::ip::address ip;
|
||||||
|
uint16_t port;
|
||||||
|
std::string service_name;
|
||||||
|
std::string hostname;
|
||||||
|
std::string full_address;
|
||||||
|
|
||||||
|
//TxtData txt_data;
|
||||||
|
|
||||||
|
UdpReply() = delete;
|
||||||
|
UdpReply(boost::asio::ip::address ip,
|
||||||
|
uint16_t port,
|
||||||
|
std::string service_name,
|
||||||
|
std::string hostname);
|
||||||
|
|
||||||
|
std::string path() const;
|
||||||
|
|
||||||
|
bool operator==(const UdpReply &other) const;
|
||||||
|
bool operator<(const UdpReply &other) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream &, const UdpReply &);
|
||||||
|
|
||||||
|
/// Udp lookup performer
|
||||||
|
class Udp : public std::enable_shared_from_this<Udp> {
|
||||||
|
private:
|
||||||
|
struct priv;
|
||||||
|
public:
|
||||||
|
typedef std::shared_ptr<Udp> Ptr;
|
||||||
|
typedef std::function<void(UdpReply &&)> ReplyFn;
|
||||||
|
typedef std::function<void()> CompleteFn;
|
||||||
|
typedef std::function<void(const std::vector<UdpReply>&)> ResolveFn;
|
||||||
|
typedef std::set<std::string> TxtKeys;
|
||||||
|
|
||||||
|
Udp(std::string service);
|
||||||
|
Udp(Udp &&other);
|
||||||
|
~Udp();
|
||||||
|
|
||||||
|
// Set requested service protocol, "tcp" by default
|
||||||
|
Udp& set_protocol(std::string protocol);
|
||||||
|
// Set which TXT key-values should be collected
|
||||||
|
// Note that "path" is always collected
|
||||||
|
Udp& set_txt_keys(TxtKeys txt_keys);
|
||||||
|
Udp& set_timeout(unsigned timeout);
|
||||||
|
Udp& set_retries(unsigned retries);
|
||||||
|
// ^ Note: By default there is 1 retry (meaning 1 broadcast is sent).
|
||||||
|
// Timeout is per one retry, ie. total time spent listening = retries * timeout.
|
||||||
|
// If retries > 1, then care needs to be taken as more than one reply from the same service may be received.
|
||||||
|
|
||||||
|
// sets hostname queried by resolve()
|
||||||
|
Udp& set_hostname(const std::string& hostname);
|
||||||
|
|
||||||
|
Udp& on_udp_reply(ReplyFn fn);
|
||||||
|
Udp& on_complete(CompleteFn fn);
|
||||||
|
|
||||||
|
Udp& on_resolve(ResolveFn fn);
|
||||||
|
// lookup all devices by given TxtKeys
|
||||||
|
// each correct reply is passed back in ReplyFn, finishes with CompleteFn
|
||||||
|
Ptr lookup();
|
||||||
|
// performs resolving of hostname into vector of ip adresses passed back by ResolveFn
|
||||||
|
// needs set_hostname and on_resolve to be called before.
|
||||||
|
Ptr resolve();
|
||||||
|
// resolve on the current thread
|
||||||
|
void resolve_sync();
|
||||||
|
private:
|
||||||
|
std::unique_ptr<priv> p;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UdpRequest
|
||||||
|
{
|
||||||
|
static const boost::asio::ip::address_v4 MCAST_IP4;
|
||||||
|
static const boost::asio::ip::address_v6 MCAST_IP6;
|
||||||
|
static const uint16_t MCAST_PORT;
|
||||||
|
|
||||||
|
std::vector<char> m_data;
|
||||||
|
|
||||||
|
static boost::optional<UdpRequest> make_PTR(const std::string& service, const std::string& protocol);
|
||||||
|
static boost::optional<UdpRequest> make_A(const std::string& hostname);
|
||||||
|
static boost::optional<UdpRequest> make_AAAA(const std::string& hostname);
|
||||||
|
private:
|
||||||
|
UdpRequest(std::vector<char>&& data) : m_data(std::move(data)) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class LookupUdpSocket;
|
||||||
|
class ResolveUdpUdpSocket;
|
||||||
|
|
||||||
|
// Session is created for each async_receive of socket. On receive, its handle_receive method is called (Thru io_service->post).
|
||||||
|
// ReplyFn is called if correct datagram was received.
|
||||||
|
class UdpUdpSession
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
UdpUdpSession(Udp::ReplyFn rfn);
|
||||||
|
virtual void handle_receive(const boost::system::error_code &error, size_t bytes, std::string pData) = 0;
|
||||||
|
std::vector<char> buffer;
|
||||||
|
boost::asio::ip::udp::endpoint remote_endpoint;
|
||||||
|
protected:
|
||||||
|
Udp::ReplyFn replyfn;
|
||||||
|
};
|
||||||
|
typedef std::shared_ptr<UdpUdpSession> SharedUdpSession;
|
||||||
|
// Session for LookupUdpSocket
|
||||||
|
class LookupUdpSession : public UdpUdpSession
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LookupUdpSession(const LookupUdpSocket *sckt, Udp::ReplyFn rfn) : UdpUdpSession(rfn), socket(sckt) {}
|
||||||
|
void handle_receive(const boost::system::error_code &error, size_t bytes, std::string pData) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// const pointer to socket to get needed data as txt_keys etc.
|
||||||
|
const LookupUdpSocket *socket;
|
||||||
|
};
|
||||||
|
// Session for ResolveUdpUdpSocket
|
||||||
|
class ResolveUdpSession : public UdpUdpSession
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ResolveUdpSession(const ResolveUdpUdpSocket* sckt, Udp::ReplyFn rfn) : UdpUdpSession(rfn), socket(sckt) {}
|
||||||
|
void handle_receive(const boost::system::error_code &error, size_t bytes, std::string pData) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// const pointer to seocket to get hostname during handle_receive
|
||||||
|
const ResolveUdpUdpSocket* socket;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Udp socket, starts receiving answers after first send() call until io_service is stopped.
|
||||||
|
class UdpUdpSocket
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Two constructors: 1st is with interface which must be resolved before calling this
|
||||||
|
UdpUdpSocket(Udp::ReplyFn replyfn
|
||||||
|
, const boost::asio::ip::address& multicast_address
|
||||||
|
, const boost::asio::ip::address& interface_address
|
||||||
|
, std::shared_ptr< boost::asio::io_service > io_service);
|
||||||
|
|
||||||
|
UdpUdpSocket(Udp::ReplyFn replyfn
|
||||||
|
, const boost::asio::ip::address& multicast_address
|
||||||
|
, std::shared_ptr< boost::asio::io_service > io_service);
|
||||||
|
|
||||||
|
void send();
|
||||||
|
void async_receive();
|
||||||
|
void cancel() { socket.cancel(); }
|
||||||
|
protected:
|
||||||
|
void receive_handler(SharedUdpSession session, const boost::system::error_code& error, size_t bytes);
|
||||||
|
virtual SharedUdpSession create_session() const = 0;
|
||||||
|
|
||||||
|
Udp::ReplyFn replyfn;
|
||||||
|
boost::asio::ip::address multicast_address;
|
||||||
|
boost::asio::ip::udp::socket socket;
|
||||||
|
boost::asio::ip::udp::endpoint mcast_endpoint;
|
||||||
|
std::shared_ptr< boost::asio::io_service > io_service;
|
||||||
|
std::vector<UdpRequest> requests;
|
||||||
|
boost::array<char, 81920> m_recvBuf;
|
||||||
|
};
|
||||||
|
|
||||||
|
class LookupUdpSocket : public UdpUdpSocket
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LookupUdpSocket(Udp::TxtKeys txt_keys
|
||||||
|
, std::string service
|
||||||
|
, std::string service_dn
|
||||||
|
, std::string protocol
|
||||||
|
, Udp::ReplyFn replyfn
|
||||||
|
, const boost::asio::ip::address& multicast_address
|
||||||
|
, const boost::asio::ip::address& interface_address
|
||||||
|
, std::shared_ptr< boost::asio::io_service > io_service)
|
||||||
|
: UdpUdpSocket(replyfn, multicast_address, interface_address, io_service)
|
||||||
|
, txt_keys(txt_keys)
|
||||||
|
, service(service)
|
||||||
|
, service_dn(service_dn)
|
||||||
|
, protocol(protocol)
|
||||||
|
{
|
||||||
|
assert(!service.empty() && replyfn);
|
||||||
|
create_request();
|
||||||
|
}
|
||||||
|
|
||||||
|
LookupUdpSocket(Udp::TxtKeys txt_keys
|
||||||
|
, std::string service
|
||||||
|
, std::string service_dn
|
||||||
|
, std::string protocol
|
||||||
|
, Udp::ReplyFn replyfn
|
||||||
|
, const boost::asio::ip::address& multicast_address
|
||||||
|
, std::shared_ptr< boost::asio::io_service > io_service)
|
||||||
|
: UdpUdpSocket(replyfn, multicast_address, io_service)
|
||||||
|
, txt_keys(txt_keys)
|
||||||
|
, service(service)
|
||||||
|
, service_dn(service_dn)
|
||||||
|
, protocol(protocol)
|
||||||
|
{
|
||||||
|
assert(!service.empty() && replyfn);
|
||||||
|
create_request();
|
||||||
|
}
|
||||||
|
|
||||||
|
const Udp::TxtKeys get_txt_keys() const { return txt_keys; }
|
||||||
|
const std::string get_service() const { return service; }
|
||||||
|
const std::string get_service_dn() const { return service_dn; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
SharedUdpSession create_session() const override;
|
||||||
|
void create_request()
|
||||||
|
{
|
||||||
|
requests.clear();
|
||||||
|
// create PTR request
|
||||||
|
if (auto rqst = UdpRequest::make_PTR(service, protocol); rqst)
|
||||||
|
requests.push_back(std::move(rqst.get()));
|
||||||
|
}
|
||||||
|
boost::optional<UdpRequest> request;
|
||||||
|
Udp::TxtKeys txt_keys;
|
||||||
|
std::string service;
|
||||||
|
std::string service_dn;
|
||||||
|
std::string protocol;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ResolveUdpUdpSocket : public UdpUdpSocket
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ResolveUdpUdpSocket(const std::string& hostname
|
||||||
|
, Udp::ReplyFn replyfn
|
||||||
|
, const boost::asio::ip::address& multicast_address
|
||||||
|
, const boost::asio::ip::address& interface_address
|
||||||
|
, std::shared_ptr< boost::asio::io_service > io_service)
|
||||||
|
: UdpUdpSocket(replyfn, multicast_address, interface_address, io_service)
|
||||||
|
, hostname(hostname)
|
||||||
|
|
||||||
|
{
|
||||||
|
assert(!hostname.empty() && replyfn);
|
||||||
|
create_requests();
|
||||||
|
}
|
||||||
|
|
||||||
|
ResolveUdpUdpSocket(const std::string& hostname
|
||||||
|
, Udp::ReplyFn replyfn
|
||||||
|
, const boost::asio::ip::address& multicast_address
|
||||||
|
, std::shared_ptr< boost::asio::io_service > io_service)
|
||||||
|
: UdpUdpSocket(replyfn, multicast_address, io_service)
|
||||||
|
, hostname(hostname)
|
||||||
|
|
||||||
|
{
|
||||||
|
assert(!hostname.empty() && replyfn);
|
||||||
|
create_requests();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string get_hostname() const { return hostname; }
|
||||||
|
protected:
|
||||||
|
SharedUdpSession create_session() const override;
|
||||||
|
void create_requests()
|
||||||
|
{
|
||||||
|
requests.clear();
|
||||||
|
// UdpRequest::make_A / AAAA is now implemented to add .local correctly after the hostname.
|
||||||
|
// If that is unsufficient, we need to change make_A / AAAA and pass full hostname.
|
||||||
|
std::string trimmed_hostname = hostname;
|
||||||
|
if (size_t dot_pos = trimmed_hostname.find_first_of('.'); dot_pos != std::string::npos)
|
||||||
|
trimmed_hostname = trimmed_hostname.substr(0, dot_pos);
|
||||||
|
if (auto rqst = UdpRequest::make_A(trimmed_hostname); rqst)
|
||||||
|
requests.push_back(std::move(rqst.get()));
|
||||||
|
|
||||||
|
trimmed_hostname = hostname;
|
||||||
|
if (size_t dot_pos = trimmed_hostname.find_first_of('.'); dot_pos != std::string::npos)
|
||||||
|
trimmed_hostname = trimmed_hostname.substr(0, dot_pos);
|
||||||
|
if (auto rqst = UdpRequest::make_AAAA(trimmed_hostname); rqst)
|
||||||
|
requests.push_back(std::move(rqst.get()));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string hostname;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
set(SLIC3R_APP_NAME "QIDISlicer")
|
set(SLIC3R_APP_NAME "QIDISlicer")
|
||||||
set(SLIC3R_APP_KEY "QIDISlicer")
|
set(SLIC3R_APP_KEY "QIDISlicer")
|
||||||
set(SLIC3R_VERSION "1.0.3")
|
set(SLIC3R_VERSION "1.0.4")
|
||||||
set(SLIC3R_BUILD_ID "QIDISlicer-${SLIC3R_VERSION}+Win64")
|
set(SLIC3R_BUILD_ID "QIDISlicer-${SLIC3R_VERSION}+Win64")
|
||||||
set(SLIC3R_RC_VERSION "1,0,3,0")
|
set(SLIC3R_RC_VERSION "1,0,4,0")
|
||||||
set(SLIC3R_RC_VERSION_DOTS "1.0.3.0")
|
set(SLIC3R_RC_VERSION_DOTS "1.0.4.0")
|
||||||
|
|||||||
Reference in New Issue
Block a user