Firmware updater GUI

This commit is contained in:
Vojtech Kral 2018-05-04 16:04:43 +02:00
parent 3d09f2a980
commit af360d7097
9 changed files with 291 additions and 34 deletions

View File

@ -352,8 +352,8 @@ sub _init_menubar {
$menubar->Append($self->{object_menu}, L("&Object")) if $self->{object_menu}; $menubar->Append($self->{object_menu}, L("&Object")) if $self->{object_menu};
$menubar->Append($windowMenu, L("&Window")); $menubar->Append($windowMenu, L("&Window"));
$menubar->Append($self->{viewMenu}, L("&View")) if $self->{viewMenu}; $menubar->Append($self->{viewMenu}, L("&View")) if $self->{viewMenu};
# Add a configuration menu. # Add additional menus from C++
Slic3r::GUI::add_config_menu($menubar, $self->{preferences_event}, $self->{lang_ch_event}); Slic3r::GUI::add_menus($menubar, $self->{preferences_event}, $self->{lang_ch_event});
$menubar->Append($helpMenu, L("&Help")); $menubar->Append($helpMenu, L("&Help"));
$self->SetMenuBar($menubar); $self->SetMenuBar($menubar);
} }

View File

@ -226,6 +226,8 @@ add_library(libslic3r_gui STATIC
${LIBDIR}/slic3r/GUI/MsgDialog.hpp ${LIBDIR}/slic3r/GUI/MsgDialog.hpp
${LIBDIR}/slic3r/GUI/UpdateDialogs.cpp ${LIBDIR}/slic3r/GUI/UpdateDialogs.cpp
${LIBDIR}/slic3r/GUI/UpdateDialogs.hpp ${LIBDIR}/slic3r/GUI/UpdateDialogs.hpp
${LIBDIR}/slic3r/GUI/FirmwareDialog.cpp
${LIBDIR}/slic3r/GUI/FirmwareDialog.hpp
${LIBDIR}/slic3r/Utils/Http.cpp ${LIBDIR}/slic3r/Utils/Http.cpp
${LIBDIR}/slic3r/Utils/Http.hpp ${LIBDIR}/slic3r/Utils/Http.hpp
${LIBDIR}/slic3r/Utils/OctoPrint.cpp ${LIBDIR}/slic3r/Utils/OctoPrint.cpp

View File

@ -5,30 +5,39 @@ extern "C" {
#include "avrdude.h" #include "avrdude.h"
} }
namespace Slic3r { namespace Slic3r {
namespace AvrDude { namespace AvrDude {
static void avrdude_message_handler_ostream(const char *msg, unsigned size, void *user_p)
// Used by our custom code in avrdude to receive messages that avrdude normally outputs on stdout (see avrdude_message())
static void avrdude_message_handler_closure(const char *msg, unsigned size, void *user_p)
{ {
(void)size; auto *message_fn = reinterpret_cast<MessageFn*>(user_p);
std::ostream &os = *reinterpret_cast<std::ostream*>(user_p); (*message_fn)(msg, size);
os << msg;
} }
int main(std::vector<std::string> args, std::string sys_config, std::ostream &os) int main(std::vector<std::string> args, std::string sys_config, MessageFn message_fn)
{ {
std::vector<char *> c_args {{ const_cast<char*>(PACKAGE_NAME) }}; std::vector<char *> c_args {{ const_cast<char*>(PACKAGE_NAME) }};
for (const auto &arg : args) { for (const auto &arg : args) {
c_args.push_back(const_cast<char*>(arg.data())); c_args.push_back(const_cast<char*>(arg.data()));
} }
::avrdude_message_handler_set(avrdude_message_handler_ostream, reinterpret_cast<void*>(&os)); ::avrdude_message_handler_set(avrdude_message_handler_closure, reinterpret_cast<void*>(&message_fn));
const auto res = ::avrdude_main(static_cast<int>(c_args.size()), c_args.data(), sys_config.c_str()); const auto res = ::avrdude_main(static_cast<int>(c_args.size()), c_args.data(), sys_config.c_str());
::avrdude_message_handler_set(nullptr, nullptr); ::avrdude_message_handler_set(nullptr, nullptr);
return res; return res;
} }
int main(std::vector<std::string> args, std::string sys_config, std::ostream &os)
{
return main(std::move(args), std::move(sys_config), std::move([&os](const char *msg, unsigned /* size */) {
os << msg;
}));
}
} }

View File

@ -4,10 +4,14 @@
#include <vector> #include <vector>
#include <string> #include <string>
#include <ostream> #include <ostream>
#include <functional>
namespace Slic3r { namespace Slic3r {
namespace AvrDude { namespace AvrDude {
typedef std::function<void(const char * /* msg */, unsigned /* size */)> MessageFn;
int main(std::vector<std::string> args, std::string sys_config, MessageFn message_fn);
int main(std::vector<std::string> args, std::string sys_config, std::ostream &os); int main(std::vector<std::string> args, std::string sys_config, std::ostream &os);
} }

View File

@ -0,0 +1,197 @@
#include "FirmwareDialog.hpp"
#include <ostream>
#include <numeric>
#include <boost/format.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/log/trivial.hpp>
#include <wx/app.h>
#include <wx/sizer.h>
#include <wx/settings.h>
#include <wx/panel.h>
#include <wx/button.h>
#include <wx/filepicker.h>
#include <wx/textctrl.h>
#include <wx/stattext.h>
#include <wx/combobox.h>
#include "libslic3r/Utils.hpp"
#include "avrdude/avrdude-slic3r.hpp"
#include "GUI.hpp"
namespace fs = boost::filesystem;
namespace Slic3r {
// Private
struct FirmwareDialog::priv
{
std::string avrdude_config;
wxComboBox *port_picker;
wxFilePickerCtrl *hex_picker;
wxStaticText *status;
wxTextCtrl *txt_stdout;
wxButton *btn_flash;
priv() : avrdude_config((fs::path(::Slic3r::resources_dir()) / "avrdude" / "avrdude.conf").string()) {}
void find_serial_ports();
void perform_upload();
};
void FirmwareDialog::priv::find_serial_ports()
{
auto ports = GUI::scan_serial_ports();
port_picker->Clear();
for (const auto &port : ports) { port_picker->Append(port); }
if (ports.size() > 0 && port_picker->GetValue().IsEmpty()) {
port_picker->SetSelection(0);
}
}
void FirmwareDialog::priv::perform_upload()
{
auto filename = hex_picker->GetPath();
auto port = port_picker->GetValue();
if (filename.IsEmpty() || port.IsEmpty()) { return; }
// Note: we're not using wxTextCtrl's ability to act as a std::ostream
// because its imeplementation doesn't handle conversion from local charset
// which mangles error messages from perror().
auto message_fn = [this](const char *msg, unsigned /* size */) {
// TODO: also log into boost? (Problematic with progress bars.)
this->txt_stdout->AppendText(wxString(msg));
wxTheApp->Yield();
};
txt_stdout->SetValue(wxEmptyString);
status->SetLabel(_(L("Flashing in progress. Please do not disconnect the printer!")));
auto status_color_orig = status->GetForegroundColour();
status->SetForegroundColour(GUI::get_label_clr_modified());
btn_flash->Disable();
std::vector<std::string> args {{
"-v",
"-p", "atmega2560",
"-c", "wiring",
"-P", port.ToStdString(),
"-b", "115200", // XXX: is this ok to hardcode?
"-D",
"-U", (boost::format("flash:w:%1%:i") % filename.ToStdString()).str()
}};
BOOST_LOG_TRIVIAL(info) << "Invoking avrdude, arguments: "
<< std::accumulate(std::next(args.begin()), args.end(), args[0], [](std::string a, const std::string &b) {
return a + ' ' + b;
});
auto res = AvrDude::main(std::move(args), avrdude_config, std::move(message_fn));
BOOST_LOG_TRIVIAL(info) << "avrdude exit code: " << res;
btn_flash->Enable();
status->SetForegroundColour(status_color_orig);
status->SetLabel(
res == 0 ? _(L("Flashing succeeded!")) : _(L("Flashing failed. Please see the avrdude log below."))
);
}
// Public
FirmwareDialog::FirmwareDialog(wxWindow *parent) :
wxDialog(parent, wxID_ANY, _(L("Firmware flasher"))),
// p(new priv(this))
p(new priv())
{
enum {
DIALOG_MARGIN = 15,
SPACING = 10,
};
wxFont bold_font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
bold_font.MakeBold();
wxFont mono_font(wxFontInfo().Family(wxFONTFAMILY_TELETYPE));
mono_font.MakeSmaller();
auto *panel = new wxPanel(this);
wxBoxSizer *vsizer = new wxBoxSizer(wxVERTICAL);
panel->SetSizer(vsizer);
auto *txt_port_picker = new wxStaticText(panel, wxID_ANY, _(L("Serial port:")));
p->port_picker = new wxComboBox(panel, wxID_ANY);
auto *btn_rescan = new wxButton(panel, wxID_ANY, _(L("Rescan")));
auto *port_sizer = new wxBoxSizer(wxHORIZONTAL);
port_sizer->Add(p->port_picker, 1, wxEXPAND | wxRIGHT, SPACING);
port_sizer->Add(btn_rescan, 0);
auto *txt_hex_picker = new wxStaticText(panel, wxID_ANY, _(L("Firmware image:")));
p->hex_picker = new wxFilePickerCtrl(panel, wxID_ANY);
auto *txt_status = new wxStaticText(panel, wxID_ANY, _(L("Status:")));
p->status = new wxStaticText(panel, wxID_ANY, _(L("Ready")));
p->status->SetFont(bold_font);
auto *sizer_pickers = new wxFlexGridSizer(2, SPACING, SPACING);
sizer_pickers->AddGrowableCol(1);
sizer_pickers->Add(txt_port_picker, 0, wxALIGN_CENTER_VERTICAL);
sizer_pickers->Add(port_sizer, 0, wxEXPAND);
sizer_pickers->Add(txt_hex_picker, 0, wxALIGN_CENTER_VERTICAL);
sizer_pickers->Add(p->hex_picker, 0, wxEXPAND);
sizer_pickers->Add(txt_status, 0, wxALIGN_CENTER_VERTICAL);
sizer_pickers->Add(p->status, 0, wxEXPAND);
vsizer->Add(sizer_pickers, 0, wxEXPAND | wxBOTTOM, SPACING);
p->txt_stdout = new wxTextCtrl(panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE | wxTE_READONLY);
p->txt_stdout->SetFont(mono_font);
vsizer->Add(p->txt_stdout, 1, wxEXPAND | wxBOTTOM, SPACING);
p->btn_flash = new wxButton(panel, wxID_ANY, _(L("Flash!")));
auto *bsizer = new wxBoxSizer(wxHORIZONTAL);
bsizer->AddStretchSpacer();
bsizer->Add(p->btn_flash);
vsizer->Add(bsizer, 0, wxEXPAND);
auto *topsizer = new wxBoxSizer(wxVERTICAL);
topsizer->Add(panel, 1, wxEXPAND | wxALL, DIALOG_MARGIN);
SetSizerAndFit(topsizer);
SetMinSize(wxSize(400, 400));
SetSize(wxSize(800, 800));
p->find_serial_ports();
p->btn_flash->Bind(wxEVT_BUTTON, [this](wxCommandEvent &) { this->p->perform_upload(); });
btn_rescan->Bind(wxEVT_BUTTON, [this](wxCommandEvent &) { this->p->find_serial_ports(); });
// Bind(EVT_BONJOUR_REPLY, &FirmwareDialog::on_reply, this);
// Bind(EVT_BONJOUR_COMPLETE, [this](wxCommandEvent &) {
// this->timer_state = 0;
// });
// Bind(wxEVT_TIMER, &FirmwareDialog::on_timer, this);
}
FirmwareDialog::~FirmwareDialog()
{
// Needed bacuse of forward defs
}
void FirmwareDialog::run(wxWindow *parent)
{
FirmwareDialog dialog(parent);
dialog.ShowModal();
}
}

View File

@ -0,0 +1,31 @@
#ifndef slic3r_FirmwareDialog_hpp_
#define slic3r_FirmwareDialog_hpp_
#include <memory>
#include <wx/dialog.h>
namespace Slic3r {
class FirmwareDialog: public wxDialog
{
public:
FirmwareDialog(wxWindow *parent);
FirmwareDialog(FirmwareDialog &&) = delete;
FirmwareDialog(const FirmwareDialog &) = delete;
FirmwareDialog &operator=(FirmwareDialog &&) = delete;
FirmwareDialog &operator=(const FirmwareDialog &) = delete;
~FirmwareDialog();
static void run(wxWindow *parent);
private:
struct priv;
std::unique_ptr<priv> p;
};
}
#endif

View File

@ -1,7 +1,6 @@
#include "GUI.hpp" #include "GUI.hpp"
#include "WipeTowerDialog.hpp" #include "WipeTowerDialog.hpp"
#include <iostream> // XXX
#include <assert.h> #include <assert.h>
#include <cmath> #include <cmath>
@ -56,11 +55,11 @@
#include "Preferences.hpp" #include "Preferences.hpp"
#include "PresetBundle.hpp" #include "PresetBundle.hpp"
#include "UpdateDialogs.hpp" #include "UpdateDialogs.hpp"
#include "FirmwareDialog.hpp"
#include "../Utils/PresetUpdater.hpp" #include "../Utils/PresetUpdater.hpp"
#include "../Config/Snapshot.hpp" #include "../Config/Snapshot.hpp"
#include "avrdude/avrdude-slic3r.hpp" // XXX: TMP!
namespace Slic3r { namespace GUI { namespace Slic3r { namespace GUI {
@ -254,27 +253,6 @@ void set_app_config(AppConfig *app_config)
void set_preset_bundle(PresetBundle *preset_bundle) void set_preset_bundle(PresetBundle *preset_bundle)
{ {
g_PresetBundle = preset_bundle; g_PresetBundle = preset_bundle;
auto res = AvrDude::main({{
// "-h",
"-v",
"-p",
"atmega2560",
"-c",
"wiring",
"-P",
"COM1",
"-b115200",
"-D",
"-U",
"flash:w:c:\\local\\prusa3d_fw-3.2.0-RC2.534-1_75mm_MK3-EINSy10a-E3Dv6full.hex:i",
}},
"c:\\local\\Slic3r\\resources\\avrdude\\avrdude.conf", std::cerr
); // XXX: tmp
std::cerr << "AvrDude::main: " << res << std::endl;
exit(0);
} }
void set_preset_updater(PresetUpdater *updater) void set_preset_updater(PresetUpdater *updater)
@ -485,6 +463,42 @@ void add_config_menu(wxMenuBar *menu, int event_preferences_changed, int event_l
menu->Append(local_menu, _(L("&Configuration"))); menu->Append(local_menu, _(L("&Configuration")));
} }
enum FirmwareMenuIDs {
FirmwareMenuFlash,
FirmwareMenuDict,
FirmwareMenuCnt,
};
void add_firmware_menu(wxMenuBar *top_menu)
{
auto *menu = new wxMenu();
wxWindowID id_base = wxWindow::NewControlId(FirmwareMenuCnt);
menu->Append(id_base + FirmwareMenuFlash, _(L("Flash printer firmware")), _(L("Upload a firmware image into a Prusa printer")));
menu->Append(id_base + FirmwareMenuDict, _(L("Flash language file")), _(L("Upload a language dictionary file into a Prusa printer")));
menu->Bind(wxEVT_MENU, [id_base](wxEvent &event) {
switch (event.GetId() - id_base) {
case FirmwareMenuFlash:
FirmwareDialog::run(g_wxMainFrame);
break;
case FirmwareMenuDict:
// TODO
break;
default:
break;
}
});
top_menu->Append(menu, _(L("Fir&mware")));
}
void add_menus(wxMenuBar *menu, int event_preferences_changed, int event_language_change)
{
add_config_menu(menu, event_language_change, event_language_change);
add_firmware_menu(menu);
}
// This is called when closing the application, when loading a config file or when starting the config wizard // This is called when closing the application, when loading a config file or when starting the config wizard
// to notify the user whether he is aware that some preset changes will be lost. // to notify the user whether he is aware that some preset changes will be lost.
bool check_unsaved_changes() bool check_unsaved_changes()

View File

@ -91,7 +91,7 @@ unsigned get_colour_approx_luma(const wxColour &colour);
void set_label_clr_modified(const wxColour& clr); void set_label_clr_modified(const wxColour& clr);
void set_label_clr_sys(const wxColour& clr); void set_label_clr_sys(const wxColour& clr);
extern void add_config_menu(wxMenuBar *menu, int event_preferences_changed, int event_language_change); extern void add_menus(wxMenuBar *menu, int event_preferences_changed, int event_language_change);
// This is called when closing the application, when loading a config file or when starting the config wizard // This is called when closing the application, when loading a config file or when starting the config wizard
// to notify the user whether he is aware that some preset changes will be lost. // to notify the user whether he is aware that some preset changes will be lost.

View File

@ -36,8 +36,8 @@ void set_main_frame(SV *ui)
void set_tab_panel(SV *ui) void set_tab_panel(SV *ui)
%code%{ Slic3r::GUI::set_tab_panel((wxNotebook*)wxPli_sv_2_object(aTHX_ ui, "Wx::Notebook")); %}; %code%{ Slic3r::GUI::set_tab_panel((wxNotebook*)wxPli_sv_2_object(aTHX_ ui, "Wx::Notebook")); %};
void add_config_menu(SV *ui, int event_preferences_changed, int event_language_change) void add_menus(SV *ui, int event_preferences_changed, int event_language_change)
%code%{ Slic3r::GUI::add_config_menu((wxMenuBar*)wxPli_sv_2_object(aTHX_ ui, "Wx::MenuBar"), event_preferences_changed, event_language_change); %}; %code%{ Slic3r::GUI::add_menus((wxMenuBar*)wxPli_sv_2_object(aTHX_ ui, "Wx::MenuBar"), event_preferences_changed, event_language_change); %};
void create_preset_tabs(bool no_controller, int event_value_change, int event_presets_changed) void create_preset_tabs(bool no_controller, int event_value_change, int event_presets_changed)
%code%{ Slic3r::GUI::create_preset_tabs(no_controller, event_value_change, event_presets_changed); %}; %code%{ Slic3r::GUI::create_preset_tabs(no_controller, event_value_change, event_presets_changed); %};