diff --git a/src/emucore/SerialPort.hxx b/src/emucore/SerialPort.hxx index 5525a51c7..8736d14cd 100644 --- a/src/emucore/SerialPort.hxx +++ b/src/emucore/SerialPort.hxx @@ -65,6 +65,13 @@ class SerialPort */ virtual bool isCTS() { return true; } + /** + Get all valid serial ports detected on this system. + + @return The (possibly empty) list of detected serial ports + */ + virtual StringList portNames() { return StringList{}; } + private: // Following constructors and assignment operators not supported SerialPort(const SerialPort&) = delete; diff --git a/src/macos/SerialPortMACOS.cxx b/src/macos/SerialPortMACOS.cxx index 3a4d2530b..9006c2c74 100644 --- a/src/macos/SerialPortMACOS.cxx +++ b/src/macos/SerialPortMACOS.cxx @@ -25,6 +25,7 @@ #include #include +#include "FSNode.hxx" #include "SerialPortMACOS.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -92,3 +93,26 @@ bool SerialPortMACOS::isCTS() } return false; } + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +StringList SerialPortMACOS::portNames() +{ + StringList ports; + + // Get all possible devices in the '/dev' directory + FilesystemNode::NameFilter filter = [](const FilesystemNode& node) { + return BSPF::startsWithIgnoreCase(node.getPath(), "/dev/tty.usb"); + }; + FSList portList; + portList.reserve(16); + + FilesystemNode dev("/dev/"); + dev.getChildren(portList, FilesystemNode::ListMode::All, filter, false); + + // Add only those that can be opened + for(const auto& port: portList) + if(openPort(port.getPath())) + ports.emplace_back(port.getPath()); + + return ports; +} diff --git a/src/macos/SerialPortMACOS.hxx b/src/macos/SerialPortMACOS.hxx index 3fd9595d3..ea55ddc3d 100644 --- a/src/macos/SerialPortMACOS.hxx +++ b/src/macos/SerialPortMACOS.hxx @@ -21,8 +21,7 @@ #include "SerialPort.hxx" /** - Implement reading and writing from a serial port under macOS. For now, - reading isn't actually supported at all. + Implement reading and writing from a serial port under macOS. @author Stephen Anthony & D. Spice */ @@ -56,12 +55,19 @@ class SerialPortMACOS : public SerialPort */ bool writeByte(uInt8 data) override; - /** - Test for 'Clear To Send' enabled. + /** + Test for 'Clear To Send' enabled. - @return True if CTS signal enabled, else false - */ - bool isCTS() override; + @return True if CTS signal enabled, else false + */ + bool isCTS() override; + + /** + Get all valid serial ports detected on this system. + + @return The (possibly empty) list of detected serial ports + */ + StringList portNames() override; private: // File descriptor for serial connection diff --git a/src/unix/SerialPortUNIX.cxx b/src/unix/SerialPortUNIX.cxx index 7c39b3fb9..b155d5240 100644 --- a/src/unix/SerialPortUNIX.cxx +++ b/src/unix/SerialPortUNIX.cxx @@ -24,6 +24,7 @@ #include #include +#include "FSNode.hxx" #include "SerialPortUNIX.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -95,3 +96,28 @@ bool SerialPortUNIX::isCTS() } return false; } + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +StringList SerialPortUNIX::portNames() +{ + StringList ports; + + // Get all possible devices in the '/dev' directory + FilesystemNode::NameFilter filter = [](const FilesystemNode& node) { + return BSPF::startsWithIgnoreCase(node.getPath(), "/dev/ttyACM") || + BSPF::startsWithIgnoreCase(node.getPath(), "/dev/ttyS") || + BSPF::startsWithIgnoreCase(node.getPath(), "/dev/ttyUSB"); + }; + FSList portList; + portList.reserve(16); + + FilesystemNode dev("/dev/"); + dev.getChildren(portList, FilesystemNode::ListMode::All, filter, false); + + // Add only those that can be opened + for(const auto& port: portList) + if(openPort(port.getPath())) + ports.emplace_back(port.getPath()); + + return ports; +} diff --git a/src/unix/SerialPortUNIX.hxx b/src/unix/SerialPortUNIX.hxx index dbf5f3299..640ee9b85 100644 --- a/src/unix/SerialPortUNIX.hxx +++ b/src/unix/SerialPortUNIX.hxx @@ -22,7 +22,7 @@ /** Implement reading and writing from a serial port under UNIX. For now, - it seems to be Linux-only, and reading isn't actually supported at all. + it seems to be Linux-only. @author Stephen Anthony */ @@ -63,6 +63,13 @@ class SerialPortUNIX : public SerialPort */ bool isCTS() override; + /** + Get all valid serial ports detected on this system. + + @return The (possibly empty) list of detected serial ports + */ + StringList portNames() override; + private: // File descriptor for serial connection int myHandle{0}; diff --git a/src/windows/SerialPortWINDOWS.cxx b/src/windows/SerialPortWINDOWS.cxx index 2772821d6..8ec755091 100644 --- a/src/windows/SerialPortWINDOWS.cxx +++ b/src/windows/SerialPortWINDOWS.cxx @@ -112,3 +112,39 @@ bool SerialPortWINDOWS::isCTS() } return false; } + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +StringList SerialPortWINDOWS::portNames() +{ + StringList ports; + + HKEY hKey = NULL; + LSTATUS result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, + L"HARDWARE\\DEVICEMAP\\SERIALCOMM", 0, KEY_READ, &hKey); + if (result == ERROR_SUCCESS) + { + TCHAR deviceName[2048], friendlyName[32]; + DWORD numValues = 0; + + result = RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, NULL, NULL, + &numValues, NULL, NULL, NULL, NULL); + if (result == ERROR_SUCCESS) + { + DWORD type = 0; + DWORD deviceNameLen = 2047; + DWORD friendlyNameLen = 31; + + for (DWORD i = 0; i < numValues; ++i) + { + result = RegEnumValue(hKey, i, deviceName, &deviceNameLen, + NULL, &type, (LPBYTE)friendlyName, &friendlyNameLen); + + if (result == ERROR_SUCCESS && type == REG_SZ) + ports.emplace_back(friendlyName); + } + } + } + RegCloseKey(hKey); + + return ports; +} diff --git a/src/windows/SerialPortWINDOWS.hxx b/src/windows/SerialPortWINDOWS.hxx index 9a7aec2e6..8c2215c51 100644 --- a/src/windows/SerialPortWINDOWS.hxx +++ b/src/windows/SerialPortWINDOWS.hxx @@ -63,6 +63,13 @@ class SerialPortWINDOWS : public SerialPort */ bool isCTS() override; + /** + Get all valid serial ports detected on this system. + + @return The (possibly empty) list of detected serial ports + */ + StringList portNames() override; + private: // Handle to serial port HANDLE myHandle{0}; diff --git a/src/windows/Stella.vcxproj b/src/windows/Stella.vcxproj index f37614cda..843abc45d 100644 --- a/src/windows/Stella.vcxproj +++ b/src/windows/Stella.vcxproj @@ -1742,7 +1742,6 @@ - diff --git a/src/windows/Stella.vcxproj.filters b/src/windows/Stella.vcxproj.filters index 217dfaecf..35b428e4f 100644 --- a/src/windows/Stella.vcxproj.filters +++ b/src/windows/Stella.vcxproj.filters @@ -1829,9 +1829,6 @@ Header Files - - Header Files\emucore - Header Files\emucore