diff --git a/README.md b/README.md index 3b51804..437d7d5 100644 --- a/README.md +++ b/README.md @@ -24,12 +24,12 @@ This library is currently used by [Visual Pinball Standalone](https://github.com - **[WemosD1MPStripController](https://github.com/aetios50/PincabLedStrip)** - Wemos D1 Mini Pro based WS2812 LED strip controller - **[PacLED64](https://www.ultimarc.com/output/led-and-output-controllers/pacled64/)** - Ultimarc's 64-output LED controller with PWM support - **[LedWiz](https://groovygamegear.com/webstore/index.php?main_page=product_info&products_id=239)** - LED-Wiz's 32-port USB compatible lighting and output controller +- **[PinOne](https://www.clevelandsoftwaredesign.com/pinball-parts/pinone)** - Cleveland Software Design controller with 63 outputs ### **Implemented & Ready To Test** - **DudesCab** - RP2040-based controller with 128 PWM outputs - **ArtNet/DMX** - Professional lighting control via Ethernet (all platforms) - **PinControl** - Arduino-based controller with 10 outputs -- **PinOne** - Cleveland Software Design controller with 63 outputs - **FTDI Controllers** - FT245R bitbang controllers - **WS2811/WS2812 LED Strips** - Addressable LED strip support - **PAC Controllers** (PacDrive, PacUIO) - Cross-platform libusb implementation diff --git a/src/cab/out/pinone/PinOneAutoConfigurator.cpp b/src/cab/out/pinone/PinOneAutoConfigurator.cpp index de35ca4..558d99b 100644 --- a/src/cab/out/pinone/PinOneAutoConfigurator.cpp +++ b/src/cab/out/pinone/PinOneAutoConfigurator.cpp @@ -86,7 +86,6 @@ std::string PinOneAutoConfigurator::TestSerialPort(const char* portName) if (sp_get_port_by_name(portName, &port) != SP_OK) return ""; - // Check if port file actually exists before trying to open it std::string portPath(portName); std::ifstream portFile(portPath); if (!portFile.good()) @@ -102,7 +101,6 @@ std::string PinOneAutoConfigurator::TestSerialPort(const char* portName) return ""; } - // Set very short timeouts to prevent hanging sp_set_baudrate(port, 2000000); sp_set_bits(port, 8); sp_set_parity(port, SP_PARITY_NONE); @@ -127,6 +125,10 @@ std::string PinOneAutoConfigurator::TestSerialPort(const char* portName) { buffer[bytesRead] = '\0'; std::string result(buffer); + + while (!result.empty() && (result.back() == '\r' || result.back() == '\n')) + result.pop_back(); + if (result == "DEBUG,CSD Board Connected") { sp_close(port); @@ -135,7 +137,6 @@ std::string PinOneAutoConfigurator::TestSerialPort(const char* portName) } } - // Force flush and set non-blocking mode before closing to prevent hang sp_flush(port, SP_BUF_BOTH); sp_set_rts(port, SP_RTS_OFF); sp_set_dtr(port, SP_DTR_OFF); @@ -154,7 +155,7 @@ std::string PinOneAutoConfigurator::TestSerialPort(const char* portName) sp_set_dtr(port, SP_DTR_OFF); } catch (...) - { /* Ignore errors in cleanup */ + { } sp_close(port); @@ -162,7 +163,6 @@ std::string PinOneAutoConfigurator::TestSerialPort(const char* portName) } } - // Small delay to ensure port cleanup completes std::this_thread::sleep_for(std::chrono::milliseconds(10)); return ""; @@ -174,17 +174,12 @@ std::string PinOneAutoConfigurator::GetDevice() if (sp_list_ports(&portList) != SP_OK) return ""; - int portCount = 0; - while (portList[portCount] != nullptr) - portCount++; - for (int i = 0; portList[i] != nullptr; i++) { char* portName = sp_get_port_name(portList[i]); if (!portName) continue; - // Test each port synchronously with timeouts matching C# version (100ms) std::string result = TestSerialPort(portName); if (!result.empty()) { @@ -198,9 +193,7 @@ std::string PinOneAutoConfigurator::GetDevice() std::string comPort = ""; PinOneCommunication communication(""); if (communication.ConnectToServer()) - { comPort = communication.GetCOMPort(); - } return comPort; } diff --git a/src/general/StringExtensions.cpp b/src/general/StringExtensions.cpp index 8127252..6032cab 100644 --- a/src/general/StringExtensions.cpp +++ b/src/general/StringExtensions.cpp @@ -176,24 +176,25 @@ std::string ReplaceArgument(const std::string& format, int argIndex, const std:: std::string result = format; std::string pattern = "{" + std::to_string(argIndex); - size_t pos = result.find(pattern); - if (pos != std::string::npos) + size_t pos = 0; + while ((pos = result.find(pattern, pos)) != std::string::npos) { size_t endPos = result.find("}", pos); - if (endPos != std::string::npos) - { - std::string placeholder = result.substr(pos, endPos - pos + 1); - std::string formattedArg = arg; + if (endPos == std::string::npos) + break; - size_t colonPos = placeholder.find(":"); - if (colonPos != std::string::npos) - { - std::string formatSpec = placeholder.substr(colonPos + 1, placeholder.length() - colonPos - 2); - formattedArg = FormatArgument(arg, formatSpec); - } + std::string placeholder = result.substr(pos, endPos - pos + 1); + std::string formattedArg = arg; - result.replace(pos, endPos - pos + 1, formattedArg); + size_t colonPos = placeholder.find(":"); + if (colonPos != std::string::npos) + { + std::string formatSpec = placeholder.substr(colonPos + 1, placeholder.length() - colonPos - 2); + formattedArg = FormatArgument(arg, formatSpec); } + + result.replace(pos, endPos - pos + 1, formattedArg); + pos += formattedArg.length(); } return result; }