Added friendly names to serial ports, added automatic selection of Prusa's printers in the firmware updater dialog
This commit is contained in:
parent
7f8265e2be
commit
33f21422e6
@ -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)
|
||||||
|
@ -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()
|
||||||
|
@ -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
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
@ -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){
|
||||||
|
122
xs/src/slic3r/Utils/Serial.cpp
Normal file
122
xs/src/slic3r/Utils/Serial.cpp
Normal 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, ®DataType, (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
|
30
xs/src/slic3r/Utils/Serial.hpp
Normal file
30
xs/src/slic3r/Utils/Serial.hpp
Normal 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_ */
|
@ -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(); %};
|
||||||
|
Loading…
Reference in New Issue
Block a user