diff --git a/src/serial.h b/src/serial.h index 1f84dcc..0962f4e 100644 --- a/src/serial.h +++ b/src/serial.h @@ -55,6 +55,10 @@ typedef enum serial_line_t { SERIAL_LINE_RNG, // Ring indicator } serial_line_t; +typedef void (*serial_callback_t) (const char *name, void *userdata); + +int serial_enumerate (serial_callback_t callback, void *userdata); + int serial_open (serial_t **device, dc_context_t *context, const char* name); int serial_close (serial_t *device); diff --git a/src/serial_posix.c b/src/serial_posix.c index 801b10c..f4cfa14 100644 --- a/src/serial_posix.c +++ b/src/serial_posix.c @@ -38,6 +38,10 @@ #ifdef HAVE_IOKIT_SERIAL_IOSS_H #include #endif +#include +#include +#include +#include #ifndef TIOCINQ #define TIOCINQ FIONREAD @@ -72,6 +76,52 @@ struct serial_t { unsigned int nbits; }; + +int +serial_enumerate (serial_callback_t callback, void *userdata) +{ + DIR *dp = NULL; + struct dirent *ep = NULL; + const char *dirname = "/dev"; + const char *patterns[] = { +#if defined (__APPLE__) + "tty.*", +#else + "ttyS*", + "ttyUSB*", + "ttyACM*", + "rfcomm*", +#endif + NULL + }; + + dp = opendir (dirname); + if (dp == NULL) { + return -1; + } + + while ((ep = readdir (dp)) != NULL) { + for (size_t i = 0; patterns[i] != NULL; ++i) { + if (fnmatch (patterns[i], ep->d_name, 0) == 0) { + char filename[1024]; + int n = snprintf (filename, sizeof (filename), "%s/%s", dirname, ep->d_name); + if (n >= sizeof (filename)) { + closedir (dp); + return -1; + } + + callback (filename, userdata); + break; + } + } + } + + closedir (dp); + + return 0; +} + + // // Open the serial port. // diff --git a/src/serial_win32.c b/src/serial_win32.c index fa4d00a..62cf486 100644 --- a/src/serial_win32.c +++ b/src/serial_win32.c @@ -47,6 +47,60 @@ struct serial_t { unsigned int nbits; }; +int +serial_enumerate (serial_callback_t callback, void *userdata) +{ + // Open the registry key. + HKEY hKey; + LONG rc = RegOpenKeyEx (HKEY_LOCAL_MACHINE, "HARDWARE\\DEVICEMAP\\SERIALCOMM", 0, KEY_QUERY_VALUE, &hKey); + if (rc != ERROR_SUCCESS) { + if (rc == ERROR_FILE_NOT_FOUND) + return 0; + else + return -1; + } + + // Get the number of values. + DWORD count = 0; + rc = RegQueryInfoKey (hKey, NULL, NULL, NULL, NULL, NULL, NULL, &count, NULL, NULL, NULL, NULL); + if (rc != ERROR_SUCCESS) { + RegCloseKey(hKey); + return -1; + } + + for (DWORD i = 0; i < count; ++i) { + // Get the value name, data and type. + char name[512], data[512]; + DWORD name_len = sizeof (name); + DWORD data_len = sizeof (data); + DWORD type = 0; + rc = RegEnumValue (hKey, i, name, &name_len, NULL, &type, (LPBYTE) data, &data_len); + if (rc != ERROR_SUCCESS) { + RegCloseKey(hKey); + return -1; + } + + // Ignore non-string values. + if (type != REG_SZ) + continue; + + // Prevent a possible buffer overflow. + if (data_len >= sizeof (data)) { + RegCloseKey(hKey); + return -1; + } + + // Null terminate the string. + data[data_len] = 0; + + callback (data, userdata); + } + + RegCloseKey(hKey); + + return 0; +} + // // Open the serial port. //