Firmware updater: Support for CW1

This commit is contained in:
Vojtech Kral 2019-03-27 16:49:44 +01:00
parent e20ffbfd85
commit 75990923f7
3 changed files with 76 additions and 35 deletions

View File

@ -59,6 +59,8 @@ enum {
USB_PID_MK3 = 2, USB_PID_MK3 = 2,
USB_PID_MMU_BOOT = 3, USB_PID_MMU_BOOT = 3,
USB_PID_MMU_APP = 4, USB_PID_MMU_APP = 4,
USB_PID_CW1_BOOT = 7,
USB_PID_CW1_APP = 8,
}; };
// This enum discriminates the kind of information in EVT_AVRDUDE, // This enum discriminates the kind of information in EVT_AVRDUDE,
@ -77,6 +79,13 @@ wxDEFINE_EVENT(EVT_AVRDUDE, wxCommandEvent);
wxDECLARE_EVENT(EVT_ASYNC_DIALOG, wxCommandEvent); wxDECLARE_EVENT(EVT_ASYNC_DIALOG, wxCommandEvent);
wxDEFINE_EVENT(EVT_ASYNC_DIALOG, wxCommandEvent); wxDEFINE_EVENT(EVT_ASYNC_DIALOG, wxCommandEvent);
struct Avr109Pid
{
unsigned boot;
unsigned app;
Avr109Pid(unsigned boot, unsigned app) : boot(boot), app(app) {}
};
// Private // Private
@ -151,19 +160,21 @@ struct FirmwareDialog::priv
bool ask_model_id_mismatch(const std::string &printer_model); bool ask_model_id_mismatch(const std::string &printer_model);
bool check_model_id(); bool check_model_id();
void wait_for_mmu_bootloader(unsigned retries); void avr109_wait_for_bootloader(Avr109Pid usb_pid, unsigned retries);
void mmu_reboot(const SerialPortInfo &port); void avr109_reboot(const SerialPortInfo &port);
void lookup_port_mmu(); void avr109_lookup_port(Avr109Pid usb_pid);
void prepare_common(); void prepare_common();
void prepare_mk2(); void prepare_mk2();
void prepare_mk3(); void prepare_mk3();
void prepare_mm_control(); void prepare_avr109(Avr109Pid usb_pid);
void perform_upload(); void perform_upload();
void user_cancel(); void user_cancel();
void on_avrdude(const wxCommandEvent &evt); void on_avrdude(const wxCommandEvent &evt);
void on_async_dialog(const wxCommandEvent &evt); void on_async_dialog(const wxCommandEvent &evt);
void ensure_joined(); void ensure_joined();
static const char* avr109_dev_name(Avr109Pid usb_pid);
}; };
void FirmwareDialog::priv::find_serial_ports() void FirmwareDialog::priv::find_serial_ports()
@ -259,7 +270,8 @@ void FirmwareDialog::priv::enable_port_picker(bool enable)
void FirmwareDialog::priv::load_hex_file(const wxString &path) void FirmwareDialog::priv::load_hex_file(const wxString &path)
{ {
hex_file = HexFile(path.wx_str()); hex_file = HexFile(path.wx_str());
enable_port_picker(hex_file.device != HexFile::DEV_MM_CONTROL); const bool auto_lookup = hex_file.device == HexFile::DEV_MM_CONTROL || hex_file.device == HexFile::DEV_CW1;
enable_port_picker(! auto_lookup);
} }
void FirmwareDialog::priv::queue_status(wxString message) void FirmwareDialog::priv::queue_status(wxString message)
@ -356,7 +368,7 @@ bool FirmwareDialog::priv::check_model_id()
// return false; // return false;
} }
void FirmwareDialog::priv::wait_for_mmu_bootloader(unsigned retries) void FirmwareDialog::priv::avr109_wait_for_bootloader(Avr109Pid usb_pid, unsigned retries)
{ {
enum { enum {
SLEEP_MS = 500, SLEEP_MS = 500,
@ -367,61 +379,67 @@ void FirmwareDialog::priv::wait_for_mmu_bootloader(unsigned retries)
auto ports = Utils::scan_serial_ports_extended(); auto ports = Utils::scan_serial_ports_extended();
ports.erase(std::remove_if(ports.begin(), ports.end(), [=](const SerialPortInfo &port ) { ports.erase(std::remove_if(ports.begin(), ports.end(), [=](const SerialPortInfo &port ) {
return port.id_vendor != USB_VID_PRUSA || port.id_product != USB_PID_MMU_BOOT; return port.id_vendor != USB_VID_PRUSA || port.id_product != usb_pid.boot;
}), ports.end()); }), ports.end());
if (ports.size() == 1) { if (ports.size() == 1) {
port = ports[0]; port = ports[0];
return; return;
} else if (ports.size() > 1) { } else if (ports.size() > 1) {
BOOST_LOG_TRIVIAL(error) << "Several VID/PID 0x2c99/3 devices found"; BOOST_LOG_TRIVIAL(error) << boost::format("Several VID/PID 0x2c99/%1% devices found") % usb_pid.boot;
queue_error(_(L("Multiple Original Prusa i3 MMU 2.0 devices found. Please only connect one at a time for flashing."))); queue_error(wxString::Format(
_(L("Multiple %s devices found. Please only connect one at a time for flashing.")), avr109_dev_name(usb_pid)));
return; return;
} }
} }
} }
void FirmwareDialog::priv::mmu_reboot(const SerialPortInfo &port) void FirmwareDialog::priv::avr109_reboot(const SerialPortInfo &port)
{ {
asio::io_service io; asio::io_service io;
Serial serial(io, port.port, 1200); Serial serial(io, port.port, 1200);
std::this_thread::sleep_for(std::chrono::milliseconds(50)); std::this_thread::sleep_for(std::chrono::milliseconds(50));
} }
void FirmwareDialog::priv::lookup_port_mmu() void FirmwareDialog::priv::avr109_lookup_port(Avr109Pid usb_pid)
{ {
static const auto msg_not_found = const char *dev_name = avr109_dev_name(usb_pid);
"The Multi Material Control device was not found.\n" const wxString msg_not_found = wxString::Format(
"If the device is connected, please press the Reset button next to the USB connector ..."; _(L("The %s device was not found.\n"
"If the device is connected, please press the Reset button next to the USB connector ...")),
dev_name);
BOOST_LOG_TRIVIAL(info) << "Flashing MMU 2.0, looking for VID/PID 0x2c99/3 or 0x2c99/4 ..."; BOOST_LOG_TRIVIAL(info) << boost::format("Flashing %1%, looking for VID/PID 0x2c99/%2% or 0x2c99/%3% ...")
% dev_name
% usb_pid.boot
% usb_pid.app;
auto ports = Utils::scan_serial_ports_extended(); auto ports = Utils::scan_serial_ports_extended();
ports.erase(std::remove_if(ports.begin(), ports.end(), [=](const SerialPortInfo &port ) { ports.erase(std::remove_if(ports.begin(), ports.end(), [=](const SerialPortInfo &port ) {
return port.id_vendor != USB_VID_PRUSA || return port.id_vendor != USB_VID_PRUSA ||
port.id_product != USB_PID_MMU_BOOT && port.id_product != usb_pid.boot &&
port.id_product != USB_PID_MMU_APP; port.id_product != usb_pid.app;
}), ports.end()); }), ports.end());
if (ports.size() == 0) { if (ports.size() == 0) {
BOOST_LOG_TRIVIAL(info) << "MMU 2.0 device not found, asking the user to press Reset and waiting for the device to show up ..."; BOOST_LOG_TRIVIAL(info) << "Device not found, asking the user to press Reset and waiting for the device to show up ...";
queue_status(_(L(msg_not_found))); queue_status(msg_not_found);
wait_for_mmu_bootloader(30); avr109_wait_for_bootloader(usb_pid, 30);
} else if (ports.size() > 1) { } else if (ports.size() > 1) {
BOOST_LOG_TRIVIAL(error) << "Several VID/PID 0x2c99/3 devices found"; BOOST_LOG_TRIVIAL(error) << boost::format("Several VID/PID 0x2c99/%1% devices found") % usb_pid.boot;
queue_error(_(L("Multiple Original Prusa i3 MMU 2.0 devices found. Please only connect one at a time for flashing."))); queue_error(wxString::Format(_(L("Multiple %s devices found. Please only connect one at a time for flashing.")), dev_name));
} else { } else {
if (ports[0].id_product == USB_PID_MMU_APP) { if (ports[0].id_product == usb_pid.app) {
// The device needs to be rebooted into the bootloader mode // The device needs to be rebooted into the bootloader mode
BOOST_LOG_TRIVIAL(info) << boost::format("Found VID/PID 0x2c99/4 at `%1%`, rebooting the device ...") % ports[0].port; BOOST_LOG_TRIVIAL(info) << boost::format("Found VID/PID 0x2c99/%1% at `%2%`, rebooting the device ...") % usb_pid.app % ports[0].port;
mmu_reboot(ports[0]); avr109_reboot(ports[0]);
wait_for_mmu_bootloader(10); avr109_wait_for_bootloader(usb_pid, 10);
if (! port) { if (! port) {
// The device in bootloader mode was not found, inform the user and wait some more... // The device in bootloader mode was not found, inform the user and wait some more...
BOOST_LOG_TRIVIAL(info) << "MMU 2.0 bootloader device not found after reboot, asking the user to press Reset and waiting for the device to show up ..."; BOOST_LOG_TRIVIAL(info) << boost::format("%1% device not found after reboot, asking the user to press Reset and waiting for the device to show up ...") % dev_name;
queue_status(_(L(msg_not_found))); queue_status(msg_not_found);
wait_for_mmu_bootloader(30); avr109_wait_for_bootloader(usb_pid, 30);
} }
} else { } else {
port = ports[0]; port = ports[0];
@ -498,16 +516,16 @@ void FirmwareDialog::priv::prepare_mk3()
avrdude->push_args(std::move(args)); avrdude->push_args(std::move(args));
} }
void FirmwareDialog::priv::prepare_mm_control() void FirmwareDialog::priv::prepare_avr109(Avr109Pid usb_pid)
{ {
port = boost::none; port = boost::none;
lookup_port_mmu(); avr109_lookup_port(usb_pid);
if (! port) { if (! port) {
queue_error(_(L("The device could not have been found"))); queue_error(wxString::Format(_(L("The %s device could not have been found")), avr109_dev_name(usb_pid)));
return; return;
} }
BOOST_LOG_TRIVIAL(info) << boost::format("Found VID/PID 0x2c99/3 at `%1%`, flashing ...") % port->port; BOOST_LOG_TRIVIAL(info) << boost::format("Found VID/PID 0x2c99/%1% at `%2%`, flashing ...") % usb_pid.boot % port->port;
queue_status(label_status_flashing); queue_status(label_status_flashing);
std::vector<std::string> args {{ std::vector<std::string> args {{
@ -568,7 +586,11 @@ void FirmwareDialog::priv::perform_upload()
break; break;
case HexFile::DEV_MM_CONTROL: case HexFile::DEV_MM_CONTROL:
this->prepare_mm_control(); this->prepare_avr109(Avr109Pid(USB_PID_MMU_BOOT, USB_PID_MMU_APP));
break;
case HexFile::DEV_CW1:
this->prepare_avr109(Avr109Pid(USB_PID_CW1_BOOT, USB_PID_CW1_APP));
break; break;
default: default:
@ -576,7 +598,11 @@ void FirmwareDialog::priv::perform_upload()
break; break;
} }
} catch (const std::exception &ex) { } catch (const std::exception &ex) {
if (port) {
queue_error(wxString::Format(_(L("Error accessing port at %s: %s")), port->port, ex.what())); queue_error(wxString::Format(_(L("Error accessing port at %s: %s")), port->port, ex.what()));
} else {
queue_error(wxString::Format(_(L("Error: %s")), ex.what()));
}
} }
}) })
.on_message(std::move([q, extra_verbose](const char *msg, unsigned /* size */) { .on_message(std::move([q, extra_verbose](const char *msg, unsigned /* size */) {
@ -688,6 +714,19 @@ void FirmwareDialog::priv::ensure_joined()
avrdude.reset(); avrdude.reset();
} }
const char* FirmwareDialog::priv::avr109_dev_name(Avr109Pid usb_pid) {
switch (usb_pid.boot) {
case USB_PID_MMU_BOOT:
return "Prusa MMU 2.0 Control";
break;
case USB_PID_CW1_BOOT:
return "Prusa CurWa";
break;
default: throw std::runtime_error((boost::format("Invalid avr109 device USB PID: %1%") % usb_pid.boot).str());
}
}
// Public // Public

View File

@ -18,6 +18,7 @@ static HexFile::DeviceKind parse_device_kind(const std::string &str)
if (str == "mk2") { return HexFile::DEV_MK2; } if (str == "mk2") { return HexFile::DEV_MK2; }
else if (str == "mk3") { return HexFile::DEV_MK3; } else if (str == "mk3") { return HexFile::DEV_MK3; }
else if (str == "mm-control") { return HexFile::DEV_MM_CONTROL; } else if (str == "mm-control") { return HexFile::DEV_MM_CONTROL; }
else if (str == "cw1") { return HexFile::DEV_CW1; }
else { return HexFile::DEV_GENERIC; } else { return HexFile::DEV_GENERIC; }
} }

View File

@ -16,6 +16,7 @@ struct HexFile
DEV_MK2, DEV_MK2,
DEV_MK3, DEV_MK3,
DEV_MM_CONTROL, DEV_MM_CONTROL,
DEV_CW1,
}; };
boost::filesystem::path path; boost::filesystem::path path;