diff --git a/display.h b/display.h index b62ae3ba3..153a9368e 100644 --- a/display.h +++ b/display.h @@ -74,6 +74,10 @@ extern unsigned int amount_selected; extern int is_default_dive_computer_device(const char *); extern int is_default_dive_computer(const char *, const char *); + +typedef void (*device_callback_t) (const char *name, void *userdata); +int enumerate_devices (device_callback_t callback, void *userdata); + extern const char *default_dive_computer_vendor; extern const char *default_dive_computer_product; extern const char *default_dive_computer_device; diff --git a/linux.c b/linux.c index 33a846f9b..f8d645abc 100644 --- a/linux.c +++ b/linux.c @@ -7,6 +7,9 @@ #endif #include #include +#include +#include +#include const char system_divelist_default_font[] = "Sans 8"; @@ -211,3 +214,46 @@ gboolean subsurface_launch_for_uri(const char* uri) return TRUE; } #endif /* USE_GTK_UI */ + + +int enumerate_devices (device_callback_t callback, void *userdata) +{ + int index = -1; + DIR *dp = NULL; + struct dirent *ep = NULL; + size_t i; + const char *dirname = "/dev"; + const char *patterns[] = { + "ttyUSB*", + "ttyS*", + "ttyACM*", + "rfcomm*", + NULL + }; + + dp = opendir (dirname); + if (dp == NULL) { + return -1; + } + + while ((ep = readdir (dp)) != NULL) { + for (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); + if (is_default_dive_computer_device(filename)) + index = i; + break; + } + } + } + // TODO: list UEMIS mount point from /proc/mounts + + closedir (dp); + return index; +} diff --git a/macos.c b/macos.c index 75c86edf2..f5f883e5c 100644 --- a/macos.c +++ b/macos.c @@ -106,8 +106,8 @@ int subsurface_fill_device_list(GtkListStore *store) dev = g_dir_open("/dev", 0, NULL); while (dev && (name = g_dir_read_name(dev)) != NULL) { - if (strstr(name, "usbserial") || - (strstr(name, "SerialPort") && strstr(name, "cu"))) { + if (strstr(name, "usbserial") || + (strstr(name, "SerialPort") && strstr(name, "cu"))) { int len = strlen(name) + 6; char *devicename = malloc(len); snprintf(devicename, len, "/dev/%s", name); @@ -263,3 +263,43 @@ gboolean subsurface_launch_for_uri(const char* uri) return FALSE; return TRUE; } + +int enumerate_devices (device_callback_t callback, void *userdata) +{ + int index = -1; + DIR *dp = NULL; + struct dirent *ep = NULL; + size_t i; + const char *dirname = "/dev"; + const char *patterns[] = { + "tty.*", + "usbserial", + NULL + }; + + dp = opendir (dirname); + if (dp == NULL) { + return -1; + } + + while ((ep = readdir (dp)) != NULL) { + for (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", d irname, ep->d_name); + if (n >= sizeof (filename)) { + closedir (dp); + return -1; + } + callback (filename, userdata); + if (is_default_dive_computer_device(filename)) + index = i; + break; + } + } + } + // TODO: list UEMIS mount point from /proc/mounts + + closedir (dp); + return index; +} diff --git a/qt-ui/downloadfromdivecomputer.cpp b/qt-ui/downloadfromdivecomputer.cpp index acdca89d3..52ef77d48 100644 --- a/qt-ui/downloadfromdivecomputer.cpp +++ b/qt-ui/downloadfromdivecomputer.cpp @@ -51,6 +51,8 @@ DownloadFromDCWidget::DownloadFromDCWidget(QWidget* parent, Qt::WindowFlags f) : ui->progressBar->hide(); ui->progressBar->setMinimum(0); ui->progressBar->setMaximum(100); + + fill_device_list(); fill_computer_list(); vendorModel = new QStringListModel(vendorList); @@ -63,7 +65,7 @@ DownloadFromDCWidget::DownloadFromDCWidget(QWidget* parent, Qt::WindowFlags f) : ui->product->setCurrentIndex(ui->product->findText(default_dive_computer_product)); } if (default_dive_computer_device) - ui->device->setText(default_dive_computer_device); + ui->device->setEditText(default_dive_computer_device); timer->setInterval(200); connect(timer, SIGNAL(timeout()), this, SLOT(updateProgressBar())); @@ -89,6 +91,7 @@ void DownloadFromDCWidget::updateState(states state) return; if (state == INITIAL) { + fill_device_list(); ui->progressBar->hide(); markChildrenAsEnabled(); timer->stop(); @@ -217,7 +220,7 @@ void DownloadFromDCWidget::on_ok_clicked() thread->deleteLater(); } - data.devname = strdup(ui->device->text().toUtf8().data()); + data.devname = strdup(ui->device->currentText().toUtf8().data()); data.vendor = strdup(ui->vendor->currentText().toUtf8().data()); data.product = strdup(ui->product->currentText().toUtf8().data()); @@ -285,6 +288,21 @@ void DownloadFromDCWidget::markChildrenAsEnabled() ui->search->setDisabled(false); } +static void fillDeviceList(const char *name, void *data) +{ + QComboBox *comboBox = (QComboBox *)data; + comboBox->addItem(name); +} + +void DownloadFromDCWidget::fill_device_list() +{ + int deviceIndex; + ui->device->clear(); + deviceIndex = enumerate_devices(fillDeviceList, ui->device); + if (deviceIndex >= 0) + ui->device->setCurrentIndex(deviceIndex); +} + DownloadThread::DownloadThread(QObject* parent, device_data_t* data): QThread(parent), data(data) { diff --git a/qt-ui/downloadfromdivecomputer.h b/qt-ui/downloadfromdivecomputer.h index e10d61b38..bef3d541d 100644 --- a/qt-ui/downloadfromdivecomputer.h +++ b/qt-ui/downloadfromdivecomputer.h @@ -65,6 +65,7 @@ private: QStringListModel *vendorModel; QStringListModel *productModel; void fill_computer_list(); + void fill_device_list(); QTimer *timer; diff --git a/qt-ui/downloadfromdivecomputer.ui b/qt-ui/downloadfromdivecomputer.ui index 41f9a4751..72e9c5ea1 100644 --- a/qt-ui/downloadfromdivecomputer.ui +++ b/qt-ui/downloadfromdivecomputer.ui @@ -42,7 +42,11 @@ - + + + true + + diff --git a/windows.c b/windows.c index d6cb531ae..de2ef9a45 100644 --- a/windows.c +++ b/windows.c @@ -333,3 +333,56 @@ gboolean subsurface_os_feature_available(os_feature_t f) return TRUE; } } + +int enumerate_devices (device_callback_t callback, void *userdata) +{ + // Open the registry key. + HKEY hKey; + int index = -1; + LONG rc = RegOpenKeyEx (HKEY_LOCAL_MACHINE, "HARDWARE\\DEVICEMAP\\SERIALCOMM", 0, KEY_QUERY_VALUE, &hKey); + if (rc != ERROR_SUCCESS) { + 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); + index++; + if (is_default_dive_computer_device(filename)) + index = i; + } + + RegCloseKey(hKey); + return index; +}