mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-30 12:11:15 -06:00 
			
		
		
		
	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
					
				
					 8 changed files with 187 additions and 94 deletions
				
			
		|  | @ -220,6 +220,8 @@ add_library(libslic3r_gui STATIC | |||
|     ${LIBDIR}/slic3r/Config/Version.hpp     | ||||
|     ${LIBDIR}/slic3r/Utils/ASCIIFolding.cpp | ||||
|     ${LIBDIR}/slic3r/Utils/ASCIIFolding.hpp | ||||
|     ${LIBDIR}/slic3r/Utils/Serial.cpp | ||||
|     ${LIBDIR}/slic3r/Utils/Serial.hpp | ||||
|     ${LIBDIR}/slic3r/GUI/ConfigWizard.cpp | ||||
|     ${LIBDIR}/slic3r/GUI/ConfigWizard.hpp | ||||
|     ${LIBDIR}/slic3r/GUI/MsgDialog.cpp | ||||
|  | @ -440,7 +442,7 @@ endif() | |||
| # Add the OpenGL and GLU libraries. | ||||
| if (SLIC3R_GUI) | ||||
|     if (MSVC) | ||||
|         target_link_libraries(XS OpenGL32.Lib GlU32.Lib) | ||||
|         target_link_libraries(XS user32.lib Setupapi.lib OpenGL32.Lib GlU32.Lib) | ||||
|     elseif (MINGW) | ||||
|         target_link_libraries(XS -lopengl32) | ||||
|     elseif (APPLE) | ||||
|  |  | |||
|  | @ -23,6 +23,7 @@ | |||
| #include "libslic3r/Utils.hpp" | ||||
| #include "avrdude/avrdude-slic3r.hpp" | ||||
| #include "GUI.hpp" | ||||
| #include "../Utils/Serial.hpp" | ||||
| 
 | ||||
| namespace fs = boost::filesystem; | ||||
| 
 | ||||
|  | @ -58,6 +59,7 @@ struct FirmwareDialog::priv | |||
| 	FirmwareDialog *q;      // PIMPL back pointer ("Q-Pointer")
 | ||||
| 
 | ||||
| 	wxComboBox *port_picker; | ||||
| 	std::vector<Utils::SerialPortInfo> ports; | ||||
| 	wxFilePickerCtrl *hex_picker; | ||||
| 	wxStaticText *txt_status; | ||||
| 	wxStaticText *txt_progress; | ||||
|  | @ -95,13 +97,22 @@ struct FirmwareDialog::priv | |||
| 
 | ||||
| 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); | ||||
| 	auto new_ports = Utils::scan_serial_ports_extended(); | ||||
| 	if (new_ports != this->ports) { | ||||
| 		this->ports = new_ports; | ||||
| 		port_picker->Clear(); | ||||
| 		for (const auto &port : this->ports) | ||||
| 			port_picker->Append(port.friendly_name); | ||||
| 		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() | ||||
| { | ||||
| 	auto filename = hex_picker->GetPath(); | ||||
| 	auto port = port_picker->GetValue(); | ||||
| 	if (filename.IsEmpty() || port.IsEmpty()) { return; } | ||||
| 	auto filename  = hex_picker->GetPath(); | ||||
| 	std::string port = port_picker->GetValue().ToStdString(); | ||||
| 	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); | ||||
| 
 | ||||
|  | @ -150,7 +167,7 @@ void FirmwareDialog::priv::perform_upload() | |||
| 		"-v", | ||||
| 		"-p", "atmega2560", | ||||
| 		"-c", "wiring", | ||||
| 		"-P", port.ToStdString(), | ||||
| 		"-P", port, | ||||
| 		"-b", "115200",   // XXX: is this ok to hardcode?
 | ||||
| 		"-D", | ||||
| 		"-U", (boost::format("flash:w:%1%:i") % filename.ToStdString()).str() | ||||
|  |  | |||
|  | @ -4,7 +4,6 @@ | |||
| #include <assert.h> | ||||
| #include <cmath> | ||||
| 
 | ||||
| #include <boost/algorithm/string/predicate.hpp> | ||||
| #include <boost/filesystem.hpp> | ||||
| #include <boost/lexical_cast.hpp> | ||||
| #include <boost/algorithm/string/split.hpp> | ||||
|  | @ -25,7 +24,6 @@ | |||
| #undef max | ||||
| #endif | ||||
| #include "boost/nowide/convert.hpp" | ||||
| #pragma comment(lib, "user32.lib") | ||||
| #endif | ||||
| 
 | ||||
| #include <wx/app.h> | ||||
|  | @ -88,83 +86,6 @@ void enable_screensaver() | |||
|     #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() | ||||
| { | ||||
|     #ifdef _WIN32 | ||||
|  |  | |||
|  | @ -68,7 +68,6 @@ inline t_file_wild_card& get_file_wild_card() { | |||
| 
 | ||||
| void disable_screensaver(); | ||||
| void enable_screensaver(); | ||||
| std::vector<std::string> scan_serial_ports(); | ||||
| bool debugged(); | ||||
| void break_to_debugger(); | ||||
| 
 | ||||
|  |  | |||
|  | @ -6,6 +6,7 @@ | |||
| 
 | ||||
| #include "slic3r/Utils/Http.hpp" | ||||
| #include "slic3r/Utils/OctoPrint.hpp" | ||||
| #include "slic3r/Utils/Serial.hpp" | ||||
| #include "BonjourDialog.hpp" | ||||
| #include "WipeTowerDialog.hpp" | ||||
| #include "ButtonsDescription.hpp" | ||||
|  | @ -1693,7 +1694,7 @@ void TabPrinter::build() | |||
| void TabPrinter::update_serial_ports(){ | ||||
| 	Field *field = get_field("serial_port"); | ||||
| 	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){ | ||||
|  |  | |||
							
								
								
									
										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 "slic3r/GUI/GUI.hpp" | ||||
| #include "slic3r/Utils/ASCIIFolding.hpp" | ||||
| #include "slic3r/Utils/Serial.hpp" | ||||
| %} | ||||
| 
 | ||||
| 
 | ||||
|  | @ -19,7 +20,7 @@ void enable_screensaver() | |||
|     %code{% Slic3r::GUI::enable_screensaver(); %}; | ||||
| 
 | ||||
| std::vector<std::string> scan_serial_ports() | ||||
|     %code{% RETVAL=Slic3r::GUI::scan_serial_ports(); %}; | ||||
|     %code{% RETVAL=Slic3r::Utils::scan_serial_ports(); %}; | ||||
| 
 | ||||
| bool debugged() | ||||
|     %code{% RETVAL=Slic3r::GUI::debugged(); %}; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 bubnikv
						bubnikv