From 2de6f796354ad029e9e786027210fcf1b02868e2 Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Fri, 26 Oct 2012 15:52:39 -0700 Subject: [PATCH 1/3] Improve the dive computer device selection We try to identify devices that are connected and their matching device names (and mount paths in the case of the Uemis Zurich). Those are presented as a drop down menu to choose from. The user can still override this by simply entering a different device / path name. On Windows this is not functional. How do I find out which drive letter corresponds to the USB device named "UEMISSDA"? Similarly we need code that finds serial ports that are present. For now we once again default to COM3 (so this isn't a step back, but of course it's far from what we want). Signed-off-by: Dirk Hohndel --- display-gtk.h | 4 +++- gtk-gui.c | 48 ++++++++++++++++++++++++----------------- linux.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++-- macos.c | 52 +++++++++++++++++++++++++++++++++++++++++++-- windows.c | 13 ++++++++++-- 5 files changed, 149 insertions(+), 27 deletions(-) diff --git a/display-gtk.h b/display-gtk.h index 7b2ce5f2e..f4961b301 100644 --- a/display-gtk.h +++ b/display-gtk.h @@ -45,12 +45,14 @@ extern const void *subsurface_get_conf(char *name, pref_type_t type); extern void subsurface_flush_conf(void); extern void subsurface_close_conf(void); -extern const char *subsurface_USB_name(void); +extern int subsurface_fill_device_list(GtkListStore *store); extern const char *subsurface_icon_name(void); extern void subsurface_ui_setup(GtkSettings *settings, GtkWidget *menubar, GtkWidget *vbox, GtkUIManager *ui_manager); extern void quit(GtkWidget *w, gpointer data); +extern int is_default_dive_computer_device(const char *name); + extern visible_cols_t visible_cols; extern const char *divelist_font; diff --git a/gtk-gui.c b/gtk-gui.c index d5569893d..80cbd30fd 100644 --- a/gtk-gui.c +++ b/gtk-gui.c @@ -49,7 +49,7 @@ static int is_default_dive_computer(const char *vendor, const char *product) default_dive_computer_product && !strcmp(product, default_dive_computer_product); } -static int is_default_dive_computer_device(const char *name) +int is_default_dive_computer_device(const char *name) { return default_dive_computer_device && !strcmp(name, default_dive_computer_device); } @@ -1360,29 +1360,31 @@ static GtkComboBox *dive_computer_selector(GtkWidget *vbox) return GTK_COMBO_BOX(combo_box); } -const char *subsurface_device_name() +static GtkComboBox *dc_device_selector(GtkWidget *vbox) { - if (!default_dive_computer_device || !*default_dive_computer_device) - return subsurface_USB_name(); - else - return default_dive_computer_device; -} - -static GtkEntry *dive_computer_device(GtkWidget *vbox) -{ - GtkWidget *hbox, *entry, *frame; + GtkWidget *hbox, *combo_box, *frame; + GtkListStore *model; + GtkCellRenderer *renderer; + int default_index; hbox = gtk_hbox_new(FALSE, 6); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 3); - frame = gtk_frame_new(_("Device name")); + model = gtk_list_store_new(1, G_TYPE_STRING); + default_index = subsurface_fill_device_list(model); + + frame = gtk_frame_new(_("Device or mount point")); gtk_box_pack_start(GTK_BOX(hbox), frame, FALSE, TRUE, 3); - entry = gtk_entry_new(); - gtk_container_add(GTK_CONTAINER(frame), entry); - gtk_entry_set_text(GTK_ENTRY(entry), subsurface_device_name()); + combo_box = gtk_combo_box_entry_new_with_model(GTK_TREE_MODEL(model), 0); + gtk_container_add(GTK_CONTAINER(frame), combo_box); - return GTK_ENTRY(entry); + renderer = gtk_cell_renderer_text_new(); + gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo_box), renderer, TRUE); + + gtk_combo_box_set_active(GTK_COMBO_BOX(combo_box), default_index); + + return GTK_COMBO_BOX(combo_box); } static void do_import_file(gpointer data, gpointer user_data) @@ -1498,9 +1500,8 @@ void download_dialog(GtkWidget *w, gpointer data) { int result; GtkWidget *dialog, *button, *hbox, *vbox, *label, *info = NULL; - GtkComboBox *computer; + GtkComboBox *computer, *device; GtkTreeIter iter; - GtkEntry *device; device_data_t devicedata = { .devname = NULL, }; @@ -1516,7 +1517,7 @@ void download_dialog(GtkWidget *w, gpointer data) label = gtk_label_new(_(" Please select dive computer and device. ")); gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 3); computer = dive_computer_selector(vbox); - device = dive_computer_device(vbox); + device = dc_device_selector(vbox); hbox = gtk_hbox_new(FALSE, 6); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 3); devicedata.progress.bar = gtk_progress_bar_new(); @@ -1552,7 +1553,14 @@ repeat: devicedata.descriptor = descriptor; devicedata.vendor = vendor; devicedata.product = product; - devicedata.devname = gtk_entry_get_text(device); + + if (!gtk_combo_box_get_active_iter(device, &iter)) + break; + + model = gtk_combo_box_get_model(device); + gtk_tree_model_get(model, &iter, + 0, &devicedata.devname, + -1); set_default_dive_computer(vendor, product); set_default_dive_computer_device(devicedata.devname); info = import_dive_computer(&devicedata, GTK_DIALOG(dialog)); diff --git a/linux.c b/linux.c index b32bde8c1..45fb02da4 100644 --- a/linux.c +++ b/linux.c @@ -56,9 +56,64 @@ void subsurface_close_conf(void) /* this is a no-op */ } -const char *subsurface_USB_name() +int subsurface_fill_device_list(GtkListStore *store) { - return "/dev/ttyUSB0"; + int i = 0; + int index = -1; + GtkTreeIter iter; + GDir *dev; + const char *name; + char *buffer; + gsize length; + + dev = g_dir_open("/dev", 0, NULL); + while (dev && (name = g_dir_read_name(dev)) != NULL) { + if (strstr(name, "USB")) { + int len = strlen(name) + 6; + char *devicename = malloc(len); + snprintf(devicename, len, "/dev/%s", name); + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, + 0, devicename, -1); + if (is_default_dive_computer_device(devicename)) + index = i; + i++; + } + } + if (dev) + g_dir_close(dev); + if (g_file_get_contents("/proc/mounts", &buffer, &length, NULL) && + length > 0) { + char *ptr = strstr(buffer, "UEMISSDA"); + if (ptr) { + char *end = ptr, *start = ptr; + while (start > buffer && *start != ' ') + start--; + if (*start == ' ') + start++; + while (*end != ' ' && *end != '\0') + end++; + *end = '\0'; + name = strdup(start); + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, + 0, name, -1); + if (is_default_dive_computer_device(name)) + index = i; + i++; + free((void *)name); + } + g_free(buffer); + } + if (i == 0) { + /* if we can't find anything, use the default */ + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, + 0, "/dev/ttyUSB0", -1); + if (is_default_dive_computer_device("/dev/ttyUSB0")) + index = i; + } + return index; } const char *subsurface_icon_name() diff --git a/macos.c b/macos.c index 6727c1053..56b5b3bdf 100644 --- a/macos.c +++ b/macos.c @@ -72,9 +72,57 @@ void subsurface_close_conf(void) /* Nothing */ } -const char *subsurface_USB_name() +Int subsurface_fill_device_list(GtkListStore *store) { - return "/dev/tty.SLAB_USBtoUART"; + int i = 0; + int index = -1; + GtkTreeIter iter; + GDir *dev; + const char *name; + char *buffer; + gsize length; + + dev = g_dir_open("/dev", 0, NULL); + while (dev && (name = g_dir_read_name(dev)) != NULL) { + if (strstr(name, "usbserial")) { + int len = strlen(name) + 6; + char *devicename = malloc(len); + snprintf(devicename, len, "/dev/%s", name); + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, + 0, devicename, -1); + if (is_default_dive_computer_device(devicename)) + index = i; + i++; + } + } + if (dev) + g_dir_close(dev); + dev = g_dir_open("/Volumes", 0, NULL); + while (dev && (name = g_dir_read_name(dev)) != NULL) { + if (strstr(name, "UEMISSDA")) { + int len = strlen(name) + 10; + char *devicename = malloc(len); + snprintf(devicename, len, "/Volumes/%s", name); + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, + 0, devicename, -1); + if (is_default_dive_computer_device(devicename)) + index = i; + i++; + } + } + if (dev) + g_dir_close(dev); + if (i == 0) { + /* if we can't find anything, use the default */ + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, + 0, "/dev/tty.SLAB_USBtoUART", -1); + if (is_default_dive_computer_device("/dev/tty.SLAB_USBtoUART")) + index = i; + } + return index; } const char *subsurface_icon_name() diff --git a/windows.c b/windows.c index 2127614bd..df136085f 100644 --- a/windows.c +++ b/windows.c @@ -119,9 +119,18 @@ void subsurface_close_conf(void) RegCloseKey(hkey); } -const char *subsurface_USB_name() +int subsurface_fill_device_list(GtkListStore *store) { - return "COM3"; + GtkTreeIter iter; + int index = -1; + + /* if we can't find anything, use the default */ + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, + 0, "COM3", -1); + if (is_default_dive_computer_device("COM3")) + index = 0; + return index; } const char *subsurface_icon_name() From ab8af0bdeb09f35f0d40b455601995f833811b12 Mon Sep 17 00:00:00 2001 From: "Lubomir I. Ivanov" Date: Mon, 29 Oct 2012 21:48:43 +0200 Subject: [PATCH 2/3] windows.c: added device retrieval from subsurface_fill_device_list() subsurface_fill_device_list() now goes trough the list of registry entries in the SERIALCOMM key and adds all present values (such as COM1, COM2) to a GtkListStore. Once done the function compares all logic drive label to a static list of known DC labels, such a 'UEMISSDA', which is the only present one at the moment and adds any matching drive letters (e.g. C:\, H:\) to the list store as well. If no serial ports were added or no matching logical drives were found the function simply adds a default entry named "COM1". Signed-off-by: Lubomir I. Ivanov --- windows.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 57 insertions(+), 6 deletions(-) diff --git a/windows.c b/windows.c index df136085f..1189fae5a 100644 --- a/windows.c +++ b/windows.c @@ -121,15 +121,66 @@ void subsurface_close_conf(void) int subsurface_fill_device_list(GtkListStore *store) { + const int bufdef = 512; + const char *dlabels[] = {"UEMISSDA", NULL}; + const char *devdef = "COM1"; GtkTreeIter iter; - int index = -1; + int index = -1, nentries = 0, ret, i; + char bufname[bufdef], bufval[bufdef], *p; + DWORD nvalues, bufval_len, bufname_len; + HKEY key; + /* add serial ports */ + ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "HARDWARE\\DEVICEMAP\\SERIALCOMM", + 0, KEY_READ, &key); + if (ret == ERROR_SUCCESS) { + ret = RegQueryInfoKeyA(key, NULL, NULL, NULL, NULL, NULL, NULL, &nvalues, + NULL, NULL, NULL, NULL); + if (ret == ERROR_SUCCESS) + for (i = 0; i < nvalues; i++) { + memset(bufval, 0, bufdef); + memset(bufname, 0, bufdef); + bufname_len = bufdef; + bufval_len = bufdef; + ret = RegEnumValueA(key, i, bufname, &bufname_len, NULL, NULL, bufval, + &bufval_len); + if (ret == ERROR_SUCCESS) { + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, 0, bufval, -1); + if (is_default_dive_computer_device(bufval)) + index = nentries; + nentries++; + } + } + } + /* add drive letters that match labels */ + memset(bufname, 0, bufdef); + bufname_len = bufdef; + if (GetLogicalDriveStringsA(bufname_len, bufname)) { + p = bufname; + while (*p) { + memset(bufval, 0, bufdef); + if (GetVolumeInformationA(p, bufval, bufdef, NULL, NULL, NULL, NULL, 0)) { + for (i = 0; dlabels[i] != NULL; i++) + if (!strcmp(bufval, dlabels[i])) { + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, 0, p, -1); + if (is_default_dive_computer_device(p)) + index = nentries; + nentries++; + } + } + p = &p[strlen(p) + 1]; + } + } /* if we can't find anything, use the default */ - gtk_list_store_append(store, &iter); - gtk_list_store_set(store, &iter, - 0, "COM3", -1); - if (is_default_dive_computer_device("COM3")) - index = 0; + if (!nentries) { + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, + 0, devdef, -1); + if (is_default_dive_computer_device(devdef)) + index = 0; + } return index; } From ee5c31d2921c0b8970303a1230586391dd06df4a Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Wed, 31 Oct 2012 16:51:04 -0700 Subject: [PATCH 3/3] Show drive name after the drive letter on Windows In the device selector when downloading from a divecomputer add the drive name that we have been looking for (so far that's only "UEMISSDA") to the drive letter - this should make it easier for people to figure out why there is a drive letter offered as an option. Signed-off-by: Dirk Hohndel --- windows.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/windows.c b/windows.c index 1189fae5a..372e03b14 100644 --- a/windows.c +++ b/windows.c @@ -163,8 +163,10 @@ int subsurface_fill_device_list(GtkListStore *store) if (GetVolumeInformationA(p, bufval, bufdef, NULL, NULL, NULL, NULL, 0)) { for (i = 0; dlabels[i] != NULL; i++) if (!strcmp(bufval, dlabels[i])) { + char name[80]; + snprintf(name, sizeof(name), "%s (%s)", p, dlabels[i]); gtk_list_store_append(store, &iter); - gtk_list_store_set(store, &iter, 0, p, -1); + gtk_list_store_set(store, &iter, 0, name, -1); if (is_default_dive_computer_device(p)) index = nentries; nentries++;