Added friendly names to serial ports, added automatic selection of Prusa's printers in the firmware updater dialog

This commit is contained in:
bubnikv 2018-05-21 16:14:20 +02:00 committed by Vojtech Kral
parent 7f8265e2be
commit 33f21422e6
8 changed files with 187 additions and 94 deletions

View File

@ -220,6 +220,8 @@ add_library(libslic3r_gui STATIC
${LIBDIR}/slic3r/Config/Version.hpp ${LIBDIR}/slic3r/Config/Version.hpp
${LIBDIR}/slic3r/Utils/ASCIIFolding.cpp ${LIBDIR}/slic3r/Utils/ASCIIFolding.cpp
${LIBDIR}/slic3r/Utils/ASCIIFolding.hpp ${LIBDIR}/slic3r/Utils/ASCIIFolding.hpp
${LIBDIR}/slic3r/Utils/Serial.cpp
${LIBDIR}/slic3r/Utils/Serial.hpp
${LIBDIR}/slic3r/GUI/ConfigWizard.cpp ${LIBDIR}/slic3r/GUI/ConfigWizard.cpp
${LIBDIR}/slic3r/GUI/ConfigWizard.hpp ${LIBDIR}/slic3r/GUI/ConfigWizard.hpp
${LIBDIR}/slic3r/GUI/MsgDialog.cpp ${LIBDIR}/slic3r/GUI/MsgDialog.cpp
@ -440,7 +442,7 @@ endif()
# Add the OpenGL and GLU libraries. # Add the OpenGL and GLU libraries.
if (SLIC3R_GUI) if (SLIC3R_GUI)
if (MSVC) if (MSVC)
target_link_libraries(XS OpenGL32.Lib GlU32.Lib) target_link_libraries(XS user32.lib Setupapi.lib OpenGL32.Lib GlU32.Lib)
elseif (MINGW) elseif (MINGW)
target_link_libraries(XS -lopengl32) target_link_libraries(XS -lopengl32)
elseif (APPLE) elseif (APPLE)

View File

@ -23,6 +23,7 @@
#include "libslic3r/Utils.hpp" #include "libslic3r/Utils.hpp"
#include "avrdude/avrdude-slic3r.hpp" #include "avrdude/avrdude-slic3r.hpp"
#include "GUI.hpp" #include "GUI.hpp"
#include "../Utils/Serial.hpp"
namespace fs = boost::filesystem; namespace fs = boost::filesystem;
@ -58,6 +59,7 @@ struct FirmwareDialog::priv
FirmwareDialog *q; // PIMPL back pointer ("Q-Pointer") FirmwareDialog *q; // PIMPL back pointer ("Q-Pointer")
wxComboBox *port_picker; wxComboBox *port_picker;
std::vector<Utils::SerialPortInfo> ports;
wxFilePickerCtrl *hex_picker; wxFilePickerCtrl *hex_picker;
wxStaticText *txt_status; wxStaticText *txt_status;
wxStaticText *txt_progress; wxStaticText *txt_progress;
@ -95,13 +97,22 @@ struct FirmwareDialog::priv
void FirmwareDialog::priv::find_serial_ports() void FirmwareDialog::priv::find_serial_ports()
{ {
auto ports = GUI::scan_serial_ports(); auto new_ports = Utils::scan_serial_ports_extended();
if (new_ports != this->ports) {
port_picker->Clear(); this->ports = new_ports;
for (const auto &port : ports) { port_picker->Append(port); } port_picker->Clear();
for (const auto &port : this->ports)
if (ports.size() > 0 && port_picker->GetValue().IsEmpty()) { port_picker->Append(port.friendly_name);
port_picker->SetSelection(0); if (ports.size() > 0) {
int idx = port_picker->GetValue().IsEmpty() ? 0 : -1;
for (int i = 0; i < (int)this->ports.size(); ++ i)
if (this->ports[i].is_printer) {
idx = i;
break;
}
if (idx != -1)
port_picker->SetSelection(idx);
}
} }
} }
@ -140,9 +151,15 @@ void FirmwareDialog::priv::flashing_status(bool value, AvrDudeComplete complete)
void FirmwareDialog::priv::perform_upload() void FirmwareDialog::priv::perform_upload()
{ {
auto filename = hex_picker->GetPath(); auto filename = hex_picker->GetPath();
auto port = port_picker->GetValue(); std::string port = port_picker->GetValue().ToStdString();
if (filename.IsEmpty() || port.IsEmpty()) { return; } int selection = port_picker->GetSelection();
if (selection != -1) {
// Verify whether the combo box list selection equals to the combo box edit value.
if (this->ports[selection].friendly_name == port)
port = this->ports[selection].port;
}
if (filename.IsEmpty() || port.empty()) { return; }
flashing_status(true); flashing_status(true);
@ -150,7 +167,7 @@ void FirmwareDialog::priv::perform_upload()
"-v", "-v",
"-p", "atmega2560", "-p", "atmega2560",
"-c", "wiring", "-c", "wiring",
"-P", port.ToStdString(), "-P", port,
"-b", "115200", // XXX: is this ok to hardcode? "-b", "115200", // XXX: is this ok to hardcode?
"-D", "-D",
"-U", (boost::format("flash:w:%1%:i") % filename.ToStdString()).str() "-U", (boost::format("flash:w:%1%:i") % filename.ToStdString()).str()

View File

@ -4,7 +4,6 @@
#include <assert.h> #include <assert.h>
#include <cmath> #include <cmath>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#include <boost/algorithm/string/split.hpp> #include <boost/algorithm/string/split.hpp>
@ -25,7 +24,6 @@
#undef max #undef max
#endif #endif
#include "boost/nowide/convert.hpp" #include "boost/nowide/convert.hpp"
#pragma comment(lib, "user32.lib")
#endif #endif
#include <wx/app.h> #include <wx/app.h>
@ -88,83 +86,6 @@ void enable_screensaver()
#endif #endif
} }
std::vector<std::string> scan_serial_ports()
{
std::vector<std::string> out;
#ifdef _WIN32
// 1) Open the registry key SERIALCOM.
HKEY hKey;
LONG lRes = ::RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"HARDWARE\\DEVICEMAP\\SERIALCOMM", 0, KEY_READ, &hKey);
assert(lRes == ERROR_SUCCESS);
if (lRes == ERROR_SUCCESS) {
// 2) Get number of values of SERIALCOM key.
DWORD cValues; // number of values for key
{
TCHAR achKey[255]; // buffer for subkey name
DWORD cbName; // size of name string
TCHAR achClass[MAX_PATH] = TEXT(""); // buffer for class name
DWORD cchClassName = MAX_PATH; // size of class string
DWORD cSubKeys=0; // number of subkeys
DWORD cbMaxSubKey; // longest subkey size
DWORD cchMaxClass; // longest class string
DWORD cchMaxValue; // longest value name
DWORD cbMaxValueData; // longest value data
DWORD cbSecurityDescriptor; // size of security descriptor
FILETIME ftLastWriteTime; // last write time
// Get the class name and the value count.
lRes = RegQueryInfoKey(
hKey, // key handle
achClass, // buffer for class name
&cchClassName, // size of class string
NULL, // reserved
&cSubKeys, // number of subkeys
&cbMaxSubKey, // longest subkey size
&cchMaxClass, // longest class string
&cValues, // number of values for this key
&cchMaxValue, // longest value name
&cbMaxValueData, // longest value data
&cbSecurityDescriptor, // security descriptor
&ftLastWriteTime); // last write time
assert(lRes == ERROR_SUCCESS);
}
// 3) Read the SERIALCOM values.
{
DWORD dwIndex = 0;
for (int i = 0; i < cValues; ++ i, ++ dwIndex) {
wchar_t valueName[2048];
DWORD valNameLen = 2048;
DWORD dataType;
wchar_t data[2048];
DWORD dataSize = 4096;
lRes = ::RegEnumValueW(hKey, dwIndex, valueName, &valNameLen, nullptr, &dataType, (BYTE*)&data, &dataSize);
if (lRes == ERROR_SUCCESS && dataType == REG_SZ && valueName[0] != 0)
out.emplace_back(boost::nowide::narrow(data));
}
}
::RegCloseKey(hKey);
}
#else
// UNIX and OS X
std::initializer_list<const char*> prefixes { "ttyUSB" , "ttyACM", "tty.", "cu.", "rfcomm" };
for (auto &dir_entry : boost::filesystem::directory_iterator(boost::filesystem::path("/dev"))) {
std::string name = dir_entry.path().filename().string();
for (const char *prefix : prefixes) {
if (boost::starts_with(name, prefix)) {
out.emplace_back(dir_entry.path().string());
break;
}
}
}
#endif
out.erase(std::remove_if(out.begin(), out.end(),
[](const std::string &key){
return boost::starts_with(key, "Bluetooth") || boost::starts_with(key, "FireFly");
}),
out.end());
return out;
}
bool debugged() bool debugged()
{ {
#ifdef _WIN32 #ifdef _WIN32

View File

@ -68,7 +68,6 @@ inline t_file_wild_card& get_file_wild_card() {
void disable_screensaver(); void disable_screensaver();
void enable_screensaver(); void enable_screensaver();
std::vector<std::string> scan_serial_ports();
bool debugged(); bool debugged();
void break_to_debugger(); void break_to_debugger();

View File

@ -6,6 +6,7 @@
#include "slic3r/Utils/Http.hpp" #include "slic3r/Utils/Http.hpp"
#include "slic3r/Utils/OctoPrint.hpp" #include "slic3r/Utils/OctoPrint.hpp"
#include "slic3r/Utils/Serial.hpp"
#include "BonjourDialog.hpp" #include "BonjourDialog.hpp"
#include "WipeTowerDialog.hpp" #include "WipeTowerDialog.hpp"
#include "ButtonsDescription.hpp" #include "ButtonsDescription.hpp"
@ -1693,7 +1694,7 @@ void TabPrinter::build()
void TabPrinter::update_serial_ports(){ void TabPrinter::update_serial_ports(){
Field *field = get_field("serial_port"); Field *field = get_field("serial_port");
Choice *choice = static_cast<Choice *>(field); Choice *choice = static_cast<Choice *>(field);
choice->set_values(scan_serial_ports()); choice->set_values(Utils::scan_serial_ports());
} }
void TabPrinter::extruders_count_changed(size_t extruders_count){ void TabPrinter::extruders_count_changed(size_t extruders_count){

View File

@ -0,0 +1,122 @@
#include "Serial.hpp"
#include <algorithm>
#include <string>
#include <vector>
#include <boost/algorithm/string/predicate.hpp>
#if _WIN32
#include <Windows.h>
#include <Setupapi.h>
#include <initguid.h>
#include <devguid.h>
// Undefine min/max macros incompatible with the standard library
// For example, std::numeric_limits<std::streamsize>::max()
// produces some weird errors
#ifdef min
#undef min
#endif
#ifdef max
#undef max
#endif
#include "boost/nowide/convert.hpp"
#pragma comment(lib, "user32.lib")
#endif
namespace Slic3r {
namespace Utils {
static bool looks_like_printer(const std::string &friendly_name)
{
return friendly_name.find("Original Prusa") != std::string::npos;
}
std::vector<SerialPortInfo> scan_serial_ports_extended()
{
std::vector<SerialPortInfo> output;
#ifdef _WIN32
SP_DEVINFO_DATA devInfoData = { 0 };
devInfoData.cbSize = sizeof(devInfoData);
// Get the tree containing the info for the ports.
HDEVINFO hDeviceInfo = SetupDiGetClassDevs(&GUID_DEVCLASS_PORTS, 0, nullptr, DIGCF_PRESENT);
if (hDeviceInfo != INVALID_HANDLE_VALUE) {
// Iterate over all the devices in the tree.
for (int nDevice = 0; SetupDiEnumDeviceInfo(hDeviceInfo, nDevice, &devInfoData); ++ nDevice) {
SerialPortInfo port_info = {};
// Get the registry key which stores the ports settings.
HKEY hDeviceKey = SetupDiOpenDevRegKey(hDeviceInfo, &devInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_QUERY_VALUE);
if (hDeviceKey) {
// Read in the name of the port.
wchar_t pszPortName[4096];
DWORD dwSize = sizeof(pszPortName);
DWORD dwType = 0;
if (RegQueryValueEx(hDeviceKey, L"PortName", NULL, &dwType, (LPBYTE)pszPortName, &dwSize) == ERROR_SUCCESS)
port_info.port = boost::nowide::narrow(pszPortName);
RegCloseKey(hDeviceKey);
if (port_info.port.empty())
continue;
}
// Find the size required to hold the device info.
DWORD regDataType;
DWORD reqSize = 0;
SetupDiGetDeviceRegistryProperty(hDeviceInfo, &devInfoData, SPDRP_HARDWAREID, nullptr, nullptr, 0, &reqSize);
std::vector<wchar_t> hardware_id(reqSize > 1 ? reqSize : 1);
// Now store it in a buffer.
if (! SetupDiGetDeviceRegistryProperty(hDeviceInfo, &devInfoData, SPDRP_HARDWAREID, &regDataType, (BYTE*)hardware_id.data(), reqSize, nullptr))
continue;
port_info.hardware_id = boost::nowide::narrow(hardware_id.data());
// Find the size required to hold the friendly name.
reqSize = 0;
SetupDiGetDeviceRegistryProperty(hDeviceInfo, &devInfoData, SPDRP_FRIENDLYNAME, nullptr, nullptr, 0, &reqSize);
std::vector<wchar_t> friendly_name;
friendly_name.reserve(reqSize > 1 ? reqSize : 1);
// Now store it in a buffer.
if (! SetupDiGetDeviceRegistryProperty(hDeviceInfo, &devInfoData, SPDRP_FRIENDLYNAME, nullptr, (BYTE*)friendly_name.data(), reqSize, nullptr)) {
port_info.friendly_name = port_info.port;
} else {
port_info.friendly_name = boost::nowide::narrow(friendly_name.data());
port_info.is_printer = looks_like_printer(port_info.friendly_name);
}
output.emplace_back(std::move(port_info));
}
}
#else
// UNIX and OS X
std::initializer_list<const char*> prefixes { "ttyUSB" , "ttyACM", "tty.", "cu.", "rfcomm" };
for (auto &dir_entry : boost::filesystem::directory_iterator(boost::filesystem::path("/dev"))) {
std::string name = dir_entry.path().filename().string();
for (const char *prefix : prefixes) {
if (boost::starts_with(name, prefix)) {
SerialPortInfo spi;
spi.port = dir_entry.path().string();
spi.hardware_id = port;
spi.friendly_name = spi.port;
out.emplace_back(std::move(spi));
break;
}
}
}
#endif
output.erase(std::remove_if(output.begin(), output.end(),
[](const SerialPortInfo &info) {
return boost::starts_with(info.port, "Bluetooth") || boost::starts_with(info.port, "FireFly");
}),
output.end());
return output;
}
std::vector<std::string> scan_serial_ports()
{
std::vector<SerialPortInfo> ports = scan_serial_ports_extended();
std::vector<std::string> output;
output.reserve(ports.size());
for (const SerialPortInfo &spi : ports)
output.emplace_back(std::move(spi.port));
return output;
}
} // namespace Utils
} // namespace Slic3r

View File

@ -0,0 +1,30 @@
#ifndef slic3r_GUI_Utils_Serial_hpp_
#define slic3r_GUI_Utils_Serial_hpp_
#include <memory>
#include <vector>
namespace Slic3r {
namespace Utils {
struct SerialPortInfo {
std::string port;
std::string hardware_id;
std::string friendly_name;
bool is_printer;
};
inline bool operator==(const SerialPortInfo &sp1, const SerialPortInfo &sp2)
{
return sp1.port == sp2.port &&
sp1.hardware_id == sp2.hardware_id &&
sp1.is_printer == sp2.is_printer;
}
extern std::vector<std::string> scan_serial_ports();
extern std::vector<SerialPortInfo> scan_serial_ports_extended();
} // Utils
} // Slic3r
#endif /* slic3r_GUI_Utils_Serial_hpp_ */

View File

@ -4,6 +4,7 @@
#include <xsinit.h> #include <xsinit.h>
#include "slic3r/GUI/GUI.hpp" #include "slic3r/GUI/GUI.hpp"
#include "slic3r/Utils/ASCIIFolding.hpp" #include "slic3r/Utils/ASCIIFolding.hpp"
#include "slic3r/Utils/Serial.hpp"
%} %}
@ -19,7 +20,7 @@ void enable_screensaver()
%code{% Slic3r::GUI::enable_screensaver(); %}; %code{% Slic3r::GUI::enable_screensaver(); %};
std::vector<std::string> scan_serial_ports() std::vector<std::string> scan_serial_ports()
%code{% RETVAL=Slic3r::GUI::scan_serial_ports(); %}; %code{% RETVAL=Slic3r::Utils::scan_serial_ports(); %};
bool debugged() bool debugged()
%code{% RETVAL=Slic3r::GUI::debugged(); %}; %code{% RETVAL=Slic3r::GUI::debugged(); %};