Merge branch 'master' of https://github.com/yurovsky/stlink
authorFabien Le Mentec <texane@gmail.com>
Sun, 23 Jun 2013 11:48:38 +0000 (06:48 -0500)
committerFabien Le Mentec <texane@gmail.com>
Sun, 23 Jun 2013 11:48:38 +0000 (06:48 -0500)
Makefile.am
configure.ac
gdbserver/gdb-server.c
gui/Makefile.am [new file with mode: 0644]
gui/stlink-gui.c [new file with mode: 0644]
gui/stlink-gui.h [new file with mode: 0644]
gui/stlink-gui.ui [new file with mode: 0644]
src/st-term.c [new file with mode: 0644]
src/stlink-usb.c

index a315dd726419d2e3ac9daea21c6f093720b66dff..538db1a878f0f261b938eaf80fc81f1e5e27efd9 100644 (file)
@@ -1,19 +1,23 @@
 # Makefile.am -- Process this file with automake to produce Makefile.in
 
+SUBDIRS = . $(MAYBE_GUI)
+
 AUTOMAKE_OPTIONS = subdir-objects
 
-bin_PROGRAMS = st-flash st-util
+bin_PROGRAMS = st-flash st-util st-term
 
 noinst_LIBRARIES      = libstlink.a
 
 st_flash_SOURCES = flash/main.c
+st_term_SOURCES = src/st-term.c
 st_util_SOURCES = gdbserver/gdb-remote.c gdbserver/gdb-remote.h gdbserver/gdb-server.c mingw/mingw.c mingw/mingw.h
 
 CFILES = \
        src/stlink-common.c \
        src/stlink-usb.c \
        src/stlink-sg.c \
-       src/uglylogging.c
+       src/uglylogging.c \
+        src/st-term.c
 
 HFILES = \
        src/stlink-common.h \
@@ -33,5 +37,9 @@ st_flash_CPPFLAGS     = -std=gnu99 -Wall -Wextra -O2 -I$(top_srcdir)/src -I$(top_src
 st_util_LDADD  =       libstlink.a
 st_util_CPPFLAGS       = -std=gnu99 -Wall -Wextra -O2 -I$(top_srcdir)/src -I$(top_srcdir)/mingw
 
+st_term_LDADD   =       libstlink.a
+st_term_CPPFLAGS        = -std=gnu99 -Wall -Wextra -O2 -I$(top_srcdir)/src -I$(top_srcdir)/mingw
+
+
 EXTRA_DIST = autogen.sh
 
index e8923ed364a65dd2952e76159aefa2377dc00207..53f827893bda37e5128344c841cf83455ac57f89 100644 (file)
@@ -34,6 +34,17 @@ case "${host}" in
                CPPFLAGS="-D__USE_MINGW_ANSI_STDIO=1 $CPPFLAGS"
        ;;
 esac
+
+MAYBE_GUI=
+AC_ARG_WITH([gtk], AS_HELP_STRING([--with-gtk], [enable GTK+ gui]))
+if test "x$with_gtk" = "xyes"; then
+      PKG_CHECK_MODULES([GTK], [gtk+-3.0])
+      PKG_CHECK_MODULES([GLIB], [glib-2.0 > 2.32.0])
+      MAYBE_GUI=gui
+      AC_CONFIG_FILES([gui/Makefile])
+fi
+AC_SUBST([MAYBE_GUI])
+
 AC_CONFIG_FILES([Makefile])
 AC_OUTPUT
 
index ad7ce6570465237efc84873e03dd6da473af6dc5..f9c06f9831b17fee476e36b12e42472ad63ce4fe 100644 (file)
@@ -67,6 +67,8 @@ static void cleanup(int signal __attribute__((unused))) {
     exit(1);
 }
 
+
+
 int parse_options(int argc, char** argv, st_state_t *st) {
     static struct option long_options[] = {
         {"help", no_argument, NULL, 'h'},
@@ -186,6 +188,7 @@ int main(int argc, char** argv) {
 
     connected_stlink = sl;
     signal(SIGINT, &cleanup);
+    signal(SIGTERM, &cleanup);
 
        printf("Chip ID is %08x, Core ID is  %08x.\n", sl->chip_id, sl->core_id);
 
diff --git a/gui/Makefile.am b/gui/Makefile.am
new file mode 100644 (file)
index 0000000..19c0672
--- /dev/null
@@ -0,0 +1,30 @@
+bin_PROGRAMS = stlink-gui
+
+stlink_gui_SOURCES = \
+       stlink-gui.c \
+       stlink-gui.h
+
+stlink_gui_CPPFLAGS = \
+       -I$(top_srcdir) \
+       $(AM_CPPFLAGS) \
+       -I$(top_builddir)/src \
+       @GTK_CFLAGS@
+
+stlink_gui_CFLAGS = \
+       $(WARN_CFLAGS) \
+       $(AM_CFLAGS) \
+       -DSTLINK_UI_DIR="\"$(uidir)\""
+
+stlink_gui_LDFLAGS =  \
+       $(AM_LDFLAGS)
+
+stlink_gui_LDADD = \
+       $(INTLLIBS) \
+       $(top_builddir)/libstlink.a \
+       @GTK_LIBS@
+
+uidir = $(pkgdatadir)/ui
+ui_DATA = stlink-gui.ui
+EXTRA_DIST = $(ui_DATA)
+
+-include $(top_srcdir)/git.mk
diff --git a/gui/stlink-gui.c b/gui/stlink-gui.c
new file mode 100644 (file)
index 0000000..fde1d34
--- /dev/null
@@ -0,0 +1,955 @@
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <gtk/gtk.h>
+
+#include "stlink-common.h"
+#include "stlink-gui.h"
+
+#define MEM_READ_SIZE 1024
+
+#ifndef G_VALUE_INIT
+#define G_VALUE_INIT {0, {{0}}}
+#endif
+
+G_DEFINE_TYPE (STlinkGUI, stlink_gui, G_TYPE_OBJECT);
+
+static void
+stlink_gui_dispose (GObject *gobject)
+{
+       G_OBJECT_CLASS (stlink_gui_parent_class)->dispose (gobject);
+}
+
+static void
+stlink_gui_finalize (GObject *gobject)
+{
+  G_OBJECT_CLASS (stlink_gui_parent_class)->finalize (gobject);
+}
+
+static void
+stlink_gui_class_init (STlinkGUIClass *klass)
+{
+       GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+       gobject_class->dispose  = stlink_gui_dispose;
+       gobject_class->finalize = stlink_gui_finalize;
+}
+
+static void
+stlink_gui_init (STlinkGUI *self)
+{
+       self->sl       = NULL;
+       self->filename = NULL;
+
+       self->progress.activity_mode = FALSE;
+       self->progress.fraction      = 0;
+
+       self->flash_mem.memory = NULL;
+       self->flash_mem.size   = 0;
+       self->flash_mem.base   = 0;
+
+       self->file_mem.memory = NULL;
+       self->file_mem.size   = 0;
+       self->file_mem.base   = 0;
+}
+
+static gboolean
+set_info_error_message_idle (STlinkGUI *gui)
+{
+       if (gui->error_message != NULL) {
+               gchar *markup;
+
+               markup = g_markup_printf_escaped ("<b>%s</b>", gui->error_message);
+               gtk_label_set_markup (gui->infolabel, markup);
+               gtk_info_bar_set_message_type (gui->infobar, GTK_MESSAGE_ERROR);
+               gtk_widget_show (GTK_WIDGET (gui->infobar));
+
+               g_free (markup);
+               g_free (gui->error_message);
+               gui->error_message = NULL;
+       }
+       return FALSE;
+}
+
+static void
+stlink_gui_set_info_error_message (STlinkGUI *gui, const gchar *message)
+{
+       gui->error_message = g_strdup (message);
+       g_idle_add ((GSourceFunc) set_info_error_message_idle, gui);
+}
+
+static void
+stlink_gui_set_sensitivity (STlinkGUI *gui, gboolean sensitivity)
+{
+       gtk_widget_set_sensitive (GTK_WIDGET (gui->open_button), sensitivity);
+
+       if (sensitivity && gui->sl)
+               gtk_widget_set_sensitive (GTK_WIDGET (gui->disconnect_button), sensitivity);
+
+       if (sensitivity && !gui->sl)
+               gtk_widget_set_sensitive (GTK_WIDGET (gui->connect_button), sensitivity);
+
+       if (sensitivity && gui->sl && gui->filename)
+               gtk_widget_set_sensitive (GTK_WIDGET (gui->flash_button), sensitivity);
+}
+
+static void
+mem_view_init_headers (GtkTreeView *view)
+{
+       GtkCellRenderer *renderer;
+       gint             i;
+
+       g_return_if_fail (view != NULL);
+
+       renderer = gtk_cell_renderer_text_new ();
+       gtk_tree_view_insert_column_with_attributes (view,
+                                                    -1,
+                                                    "Address",
+                                                    renderer,
+                                                    "text",
+                                                    0, /* column */
+                                                    NULL);
+       for (i = 0; i < 4; i++) {
+               gchar *label;
+
+               label = g_strdup_printf ("%X", i * 4);
+               renderer = gtk_cell_renderer_text_new ();
+               gtk_tree_view_insert_column_with_attributes (view,
+                                                            -1,
+                                                            label,
+                                                            renderer,
+                                                            "text",
+                                                            (i + 1), /* column */
+                                                            NULL);
+               g_free (label);
+       }
+
+       for (i = 0; i < 5; i++) {
+               GtkTreeViewColumn *column = gtk_tree_view_get_column (view, i);
+               gtk_tree_view_column_set_expand (column, TRUE);
+       }
+}
+
+static void
+mem_view_add_as_hex (GtkListStore *store,
+                     GtkTreeIter  *iter,
+                     gint          column,
+                     guint32       value)
+{
+       gchar     *hex_str;
+
+       hex_str = g_strdup_printf ("0x%08X", value);
+       gtk_list_store_set (store, iter, column, hex_str, -1);
+       g_free (hex_str);
+}
+
+static void
+mem_view_add_buffer (GtkListStore *store,
+                     GtkTreeIter  *iter,
+                     guint32       address,
+                     guchar       *buffer,
+                     gint          len)
+{
+       guint32 *word;
+       gint     i, step;
+       gint     column = 0;
+
+       step = sizeof (*word);
+
+       for (i = 0; i < len; i += step) {
+               word = (guint *) &buffer[i];
+
+               if (column == 0) {
+                       /* new row */
+                       gtk_list_store_append (store, iter);
+
+                       /* add address */
+                       mem_view_add_as_hex (store, iter, column, (address + i));
+               }
+               mem_view_add_as_hex (store, iter, (column + 1), *word);
+               column = (column + 1) % step;
+       }
+}
+
+static guint32
+hexstr_to_guint32 (const gchar *str, GError **err)
+{
+       guint32  val;
+       gchar   *end_ptr;
+
+       val = strtoul (str, &end_ptr, 16);
+       if ((errno == ERANGE && val == LONG_MAX) || (errno != 0 && val == 0)) {
+               g_set_error (err,
+                            g_quark_from_string ("hextou32"),
+                            1,
+                            "Invalid hexstring");
+               return LONG_MAX;
+       }
+       if (end_ptr == str) {
+               g_set_error (err,
+                            g_quark_from_string ("hextou32"),
+                            2,
+                            "Invalid hexstring");
+               return LONG_MAX;
+       }
+       return val;
+}
+
+
+static void
+stlink_gui_update_mem_view (STlinkGUI *gui, struct mem_t *mem, GtkTreeView *view) {
+       GtkListStore *store;
+       GtkTreeIter   iter;
+
+       store = GTK_LIST_STORE (gtk_tree_view_get_model (view));
+
+       mem_view_add_buffer (store,
+                            &iter,
+                            mem->base,
+                            mem->memory,
+                            mem->size);
+
+       gtk_widget_hide (GTK_WIDGET (gui->progress.bar));
+       gtk_progress_bar_set_fraction (gui->progress.bar, 0);
+       stlink_gui_set_sensitivity (gui, TRUE);
+}
+
+static gboolean
+stlink_gui_update_devmem_view (STlinkGUI *gui)
+{
+       stlink_gui_update_mem_view (gui, &gui->flash_mem, gui->devmem_treeview);
+       return FALSE;
+}
+
+
+static void
+stlink_gui_populate_devmem_view (STlinkGUI *gui)
+{
+       guint            off;
+       stm32_addr_t     addr;
+
+       g_return_if_fail (gui != NULL);
+       g_return_if_fail (gui->sl != NULL);
+
+       addr = gui->sl->flash_base;
+
+       if (gui->flash_mem.memory) {
+               g_free (gui->flash_mem.memory);
+       }
+       gui->flash_mem.memory = g_malloc (gui->sl->flash_size);
+       gui->flash_mem.size   = gui->sl->flash_size;
+       gui->flash_mem.base   = gui->sl->flash_base;
+
+       for (off = 0; off < gui->sl->flash_size; off += MEM_READ_SIZE) {
+               guint   n_read = MEM_READ_SIZE;
+
+               if (off + MEM_READ_SIZE > gui->sl->flash_size) {
+                       n_read = gui->sl->flash_size - off;
+
+                       /* align if needed */
+                       if (n_read & 3) {
+                               n_read = (n_read + 4) & ~(3);
+                       }
+               }
+               /* reads to sl->q_buf */
+               stlink_read_mem32(gui->sl, addr + off, n_read);
+               if (gui->sl->q_len < 0) {
+                       stlink_gui_set_info_error_message (gui, "Failed to read memory");
+                       g_free (gui->flash_mem.memory);
+                       gui->flash_mem.memory = NULL;
+                       return;
+               }
+               memcpy (gui->flash_mem.memory + off, gui->sl->q_buf, n_read);
+               gui->progress.fraction = (gdouble) (off + n_read) / gui->sl->flash_size;
+       }
+       g_idle_add ((GSourceFunc) stlink_gui_update_devmem_view, gui);
+}
+
+static gboolean
+stlink_gui_update_filemem_view (STlinkGUI *gui)
+{
+       gchar *basename;
+
+       basename = g_path_get_basename (gui->filename);
+       gtk_notebook_set_tab_label_text (gui->notebook,
+                                        GTK_WIDGET (gtk_notebook_get_nth_page (gui->notebook, 1)),
+                                        basename);
+       g_free (basename);
+
+       stlink_gui_update_mem_view (gui, &gui->file_mem, gui->filemem_treeview);
+
+       return FALSE;
+}
+
+static gpointer
+stlink_gui_populate_filemem_view (STlinkGUI *gui)
+{
+       guchar        buffer[MEM_READ_SIZE];
+       GFile        *file;
+       GFileInfo    *file_info;
+       GInputStream *input_stream;
+       gint          off;
+       GError       *err = NULL;
+
+       g_return_val_if_fail (gui != NULL, NULL);
+       g_return_val_if_fail (gui->filename != NULL, NULL);
+
+       file = g_file_new_for_path (gui->filename);
+       input_stream = G_INPUT_STREAM (g_file_read (file, NULL, &err));
+       if (err) {
+               stlink_gui_set_info_error_message (gui, err->message);
+               g_error_free (err);
+               goto out;
+       }
+
+       file_info = g_file_input_stream_query_info (G_FILE_INPUT_STREAM (input_stream),
+                                                   G_FILE_ATTRIBUTE_STANDARD_SIZE, NULL, &err);
+       if (err) {
+               stlink_gui_set_info_error_message (gui, err->message);
+               g_error_free (err);
+               goto out_input;
+       }
+       if (gui->file_mem.memory) {
+               g_free (gui->file_mem.memory);
+       }
+       gui->file_mem.size   = g_file_info_get_size (file_info);
+       gui->file_mem.memory = g_malloc (gui->file_mem.size);
+
+       for (off = 0; off < gui->file_mem.size; off += MEM_READ_SIZE) {
+               guint   n_read = MEM_READ_SIZE;
+
+               if (off + MEM_READ_SIZE > gui->file_mem.size) {
+                       n_read = gui->file_mem.size - off;
+               }
+
+               if (g_input_stream_read (G_INPUT_STREAM (input_stream),
+                                        &buffer, n_read, NULL, &err) == -1) {
+                       stlink_gui_set_info_error_message (gui, err->message);
+                       g_error_free (err);
+                       goto out_input;
+               }
+               memcpy (gui->file_mem.memory + off, buffer, n_read);
+               gui->progress.fraction = (gdouble) (off + n_read) / gui->file_mem.size;
+       }
+       g_idle_add ((GSourceFunc) stlink_gui_update_filemem_view, gui);
+
+ out_input:
+       g_object_unref (input_stream);
+ out:
+       g_object_unref (file);
+       return NULL;
+}
+
+static void mem_jmp (GtkTreeView *view,
+                     GtkEntry    *entry,
+                     guint32      base_addr,
+                     gsize        size,
+                     GError     **err)
+{
+       GtkTreeModel *model;
+       guint32       jmp_addr;
+       GtkTreeIter   iter;
+
+       jmp_addr = hexstr_to_guint32 (gtk_entry_get_text (entry), err);
+       if (err && *err) {
+               return;
+       }
+
+       if (jmp_addr < base_addr || jmp_addr > base_addr + size) {
+               g_set_error (err,
+                            g_quark_from_string ("mem_jmp"),
+                            1,
+                            "Invalid address");
+               return;
+       }
+
+       model = gtk_tree_view_get_model (view);
+       if (!model) {
+               return;
+       }
+
+       if (gtk_tree_model_get_iter_first (model, &iter)) {
+               do {
+                       guint32 addr;
+                       GValue  value = G_VALUE_INIT;
+                       GError *err   = NULL;
+
+                       gtk_tree_model_get_value (model, &iter, 0, &value);
+                       if (G_VALUE_HOLDS_STRING (&value)) {
+                               addr = hexstr_to_guint32 (g_value_get_string (&value), &err);
+                               if (!err) {
+                                       if (addr == (jmp_addr & 0xFFFFFFF0)) {
+                                               GtkTreeSelection *selection;
+                                               GtkTreePath      *path;
+
+                                               selection = gtk_tree_view_get_selection (view);
+                                               path      = gtk_tree_model_get_path (model, &iter);
+
+                                               gtk_tree_selection_select_iter (selection, &iter);
+                                               gtk_tree_view_scroll_to_cell (view,
+                                                                             path,
+                                                                             NULL,
+                                                                             TRUE,
+                                                                             0.0,
+                                                                             0.0);
+                                               gtk_tree_path_free (path);
+                                       }
+                               }
+                       }
+                       g_value_unset (&value);
+               } while (gtk_tree_model_iter_next (model, &iter));
+       }
+}
+
+static void
+devmem_jmp_cb (GtkWidget *widget, gpointer data)
+{
+       STlinkGUI *gui;
+       GError    *err = NULL;
+
+       gui = STLINK_GUI (data);
+
+       mem_jmp (gui->devmem_treeview,
+                gui->devmem_jmp_entry,
+                gui->sl->flash_base,
+                gui->sl->flash_size,
+                &err);
+
+       if (err) {
+               stlink_gui_set_info_error_message (gui, err->message);
+               g_error_free (err);
+       }
+}
+
+static void
+filemem_jmp_cb (GtkWidget *widget, gpointer data)
+{
+       STlinkGUI *gui;
+       GError    *err = NULL;
+
+       gui = STLINK_GUI (data);
+
+       g_return_if_fail (gui->filename != NULL);
+
+       mem_jmp (gui->filemem_treeview,
+                gui->filemem_jmp_entry,
+                0,
+                gui->file_mem.size,
+                &err);
+
+       if (err) {
+               stlink_gui_set_info_error_message (gui, err->message);
+               g_error_free (err);
+       }
+}
+
+static gchar *
+dev_format_chip_id (guint32 chip_id)
+{
+       gint i;
+
+       for (i = 0; i < sizeof (devices) / sizeof (devices[0]); i++) {
+               if (chip_id == devices[i].chip_id) {
+                       return g_strdup (devices[i].description);
+               }
+       }
+       return g_strdup_printf ("0x%x", chip_id);
+}
+
+static gchar *
+dev_format_mem_size (gsize flash_size)
+{
+       return g_strdup_printf ("%u kB", flash_size / 1024);
+}
+
+
+static void
+stlink_gui_set_connected (STlinkGUI *gui)
+{
+       gchar        *tmp_str;
+       GtkListStore *store;
+       GtkTreeIter   iter;
+
+       gtk_statusbar_push (gui->statusbar,
+                           gtk_statusbar_get_context_id (gui->statusbar, "conn"),
+                           "Connected");
+
+       gtk_widget_set_sensitive (GTK_WIDGET (gui->device_frame), TRUE);
+       gtk_widget_set_sensitive (GTK_WIDGET (gui->devmem_box), TRUE);
+       gtk_widget_set_sensitive (GTK_WIDGET (gui->connect_button), FALSE);
+
+       if (gui->filename) {
+               gtk_widget_set_sensitive (GTK_WIDGET (gui->flash_button), TRUE);
+       }
+
+       tmp_str = dev_format_chip_id (gui->sl->chip_id);
+       gtk_label_set_text (gui->chip_id_label, tmp_str);
+       g_free (tmp_str);
+
+       tmp_str = g_strdup_printf ("0x%x", gui->sl->core_id);
+       gtk_label_set_text (gui->core_id_label, tmp_str);
+       g_free (tmp_str);
+
+       tmp_str = dev_format_mem_size (gui->sl->flash_size);
+       gtk_label_set_text (gui->flash_size_label, tmp_str);
+       g_free (tmp_str);
+
+       tmp_str = dev_format_mem_size (gui->sl->sram_size);
+       gtk_label_set_text (gui->ram_size_label, tmp_str);
+       g_free (tmp_str);
+
+       tmp_str = g_strdup_printf ("0x%08X", gui->sl->flash_base);
+       gtk_entry_set_text (gui->devmem_jmp_entry, tmp_str);
+       gtk_editable_set_editable (GTK_EDITABLE (gui->devmem_jmp_entry), TRUE);
+       g_free (tmp_str);
+
+       store = GTK_LIST_STORE (gtk_tree_view_get_model (gui->devmem_treeview));
+       if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter)) {
+               gtk_list_store_clear (store);
+       }
+
+       stlink_gui_set_sensitivity (gui, FALSE);
+       gtk_notebook_set_current_page (gui->notebook, PAGE_DEVMEM);
+       gtk_widget_show (GTK_WIDGET (gui->progress.bar));
+       gtk_progress_bar_set_text (gui->progress.bar, "Reading memory");
+
+       g_thread_new ("devmem", (GThreadFunc) stlink_gui_populate_devmem_view, gui);
+}
+
+static void
+connect_button_cb (GtkWidget *widget, gpointer data)
+{
+       STlinkGUI *gui;
+       gint       i;
+
+       gui = STLINK_GUI (data);
+
+       if (gui->sl != NULL)
+               return;
+
+       /* try version 1 then version 2 */
+       gui->sl = stlink_v1_open(0);
+       if (gui->sl == NULL) {
+           gui->sl = stlink_open_usb(0);
+       }
+       if (gui->sl == NULL) {
+               stlink_gui_set_info_error_message (gui, "Failed to connect to STLink.");                return;
+       }
+
+       /* code below taken from flash/main.c, refactoring might be in order */
+       if (stlink_current_mode(gui->sl) == STLINK_DEV_DFU_MODE)
+               stlink_exit_dfu_mode(gui->sl);
+
+       if (stlink_current_mode(gui->sl) != STLINK_DEV_DEBUG_MODE)
+               stlink_enter_swd_mode(gui->sl);
+
+       /* Disable DMA - Set All DMA CCR Registers to zero. - AKS 1/7/2013 */
+       if (gui->sl->chip_id == STM32_CHIPID_F4) {
+               memset(gui->sl->q_buf, 0, 4);
+               for (i = 0; i < 8; i++) {
+                       stlink_write_mem32(gui->sl, 0x40026000 + 0x10 + 0x18 * i, 4);
+                       stlink_write_mem32(gui->sl, 0x40026400 + 0x10 + 0x18 * i, 4);
+                       stlink_write_mem32(gui->sl, 0x40026000 + 0x24 + 0x18 * i, 4);
+                       stlink_write_mem32(gui->sl, 0x40026400 + 0x24 + 0x18 * i, 4);
+               }
+       }
+       stlink_gui_set_connected (gui);
+}
+
+static void stlink_gui_set_disconnected (STlinkGUI *gui)
+{
+       gtk_statusbar_push (gui->statusbar,
+                           gtk_statusbar_get_context_id (gui->statusbar, "conn"),
+                           "Disconnected");
+
+       gtk_widget_set_sensitive (GTK_WIDGET (gui->device_frame), FALSE);
+       gtk_widget_set_sensitive (GTK_WIDGET (gui->flash_button), FALSE);
+       gtk_widget_set_sensitive (GTK_WIDGET (gui->disconnect_button), FALSE);
+       gtk_widget_set_sensitive (GTK_WIDGET (gui->connect_button), TRUE);
+}
+
+static void
+disconnect_button_cb (GtkWidget *widget, gpointer data)
+{
+       STlinkGUI *gui;
+
+       gui = STLINK_GUI (data);
+
+       if (gui->sl != NULL) {
+               stlink_exit_debug_mode(gui->sl);
+               stlink_close(gui->sl);
+               gui->sl = NULL;
+       }
+       stlink_gui_set_disconnected (gui);
+}
+
+
+static void
+stlink_gui_open_file (STlinkGUI *gui)
+{
+       GtkWidget    *dialog;
+       GtkListStore *store;
+       GtkTreeIter   iter;
+
+       dialog = gtk_file_chooser_dialog_new ("Open file",
+                                             gui->window,
+                                             GTK_FILE_CHOOSER_ACTION_OPEN,
+                                             GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+                                             GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
+                                             NULL);
+
+       if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
+               gui->filename =
+                       gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
+
+               store = GTK_LIST_STORE (gtk_tree_view_get_model (gui->filemem_treeview));
+               if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter)) {
+                       gtk_list_store_clear (store);
+               }
+
+               stlink_gui_set_sensitivity (gui, FALSE);
+               gtk_notebook_set_current_page (gui->notebook, PAGE_FILEMEM);
+               gtk_widget_show (GTK_WIDGET (gui->progress.bar));
+               gtk_progress_bar_set_text (gui->progress.bar, "Reading file");
+               g_thread_new ("file", (GThreadFunc) stlink_gui_populate_filemem_view, gui);
+       }
+       gtk_widget_destroy (dialog);
+}
+
+static void
+open_button_cb (GtkWidget *widget, gpointer data)
+{
+       STlinkGUI    *gui;
+
+       gui = STLINK_GUI (data);
+
+       stlink_gui_open_file (gui);
+}
+
+static gboolean
+stlink_gui_write_flash_update (STlinkGUI *gui)
+{
+       stlink_gui_set_sensitivity (gui, TRUE);
+       gui->progress.activity_mode = FALSE;
+       gtk_widget_hide (GTK_WIDGET (gui->progress.bar));
+
+       return FALSE;
+}
+
+static void
+stlink_gui_write_flash (STlinkGUI *gui)
+{
+       g_return_if_fail (gui->sl != NULL);
+       g_return_if_fail (gui->filename != NULL);
+
+       if (stlink_fwrite_flash(gui->sl, gui->filename, gui->sl->flash_base) < 0) {
+               stlink_gui_set_info_error_message (gui, "Failed to write to flash");
+       }
+
+       g_idle_add ((GSourceFunc) stlink_gui_write_flash_update, gui);
+}
+
+static void
+flash_button_cb (GtkWidget *widget, gpointer data)
+{
+       STlinkGUI *gui;
+       gchar     *tmp_str;
+       guint32    address;
+       gint       result;
+       GError    *err = NULL;
+
+       gui = STLINK_GUI (data);
+       g_return_if_fail (gui->sl != NULL);
+
+       if (!g_strcmp0 (gtk_entry_get_text (gui->flash_dialog_entry), "")) {
+               tmp_str = g_strdup_printf ("0x%08X", gui->sl->flash_base);
+               gtk_entry_set_text (gui->flash_dialog_entry, tmp_str);
+               g_free (tmp_str);
+       }
+
+       result = gtk_dialog_run (gui->flash_dialog);
+       if (result == GTK_RESPONSE_OK) {
+               address = hexstr_to_guint32 (gtk_entry_get_text (gui->flash_dialog_entry),
+                                            &err);
+               if (err) {
+                       stlink_gui_set_info_error_message (gui, err->message);
+               } else {
+                       if (address > gui->sl->flash_base + gui->sl->flash_size ||
+                           address < gui->sl->flash_base) {
+                               stlink_gui_set_info_error_message (gui, "Invalid address");
+                       }
+                       else if (address + gui->file_mem.size >
+                                gui->sl->flash_base + gui->sl->flash_size) {
+                               stlink_gui_set_info_error_message (gui, "Binary overwrites flash");
+                       } else {
+                               stlink_gui_set_sensitivity (gui, FALSE);
+                               gtk_progress_bar_set_text (gui->progress.bar,
+                                                          "Writing to flash");
+                               gui->progress.activity_mode = TRUE;
+                               gtk_widget_show (GTK_WIDGET (gui->progress.bar));
+                               g_thread_new ("flash",
+                                             (GThreadFunc) stlink_gui_write_flash, gui);
+                       }
+               }
+       }
+}
+
+static gboolean
+progress_pulse_timeout (STlinkGUI *gui) {
+       if (gui->progress.activity_mode) {
+               gtk_progress_bar_pulse (gui->progress.bar);
+       } else {
+               gtk_progress_bar_set_fraction (gui->progress.bar, gui->progress.fraction);
+       }
+       return TRUE;
+}
+
+static void
+notebook_switch_page_cb (GtkNotebook *notebook,
+                         GtkWidget   *widget,
+                         guint        page_num,
+                         gpointer     data)
+{
+       STlinkGUI *gui;
+
+       gui = STLINK_GUI (data);
+
+       if (page_num == 1) {
+               if (gui->filename == NULL) {
+                       stlink_gui_open_file (gui);
+               }
+       }
+}
+
+static void
+dnd_received_cb (GtkWidget *widget,
+                 GdkDragContext *context,
+                 gint x,
+                 gint y,
+                 GtkSelectionData *selection_data,
+                 guint target_type,
+                 guint time,
+                 gpointer data)
+{
+       GFile        *file_uri;
+       gchar       **file_list;
+       const guchar *file_data;
+       STlinkGUI    *gui = STLINK_GUI (data);
+       GtkListStore *store;
+       GtkTreeIter   iter;
+
+       if (selection_data != NULL &&
+           gtk_selection_data_get_length (selection_data) > 0) {
+               switch (target_type) {
+               case TARGET_FILENAME:
+
+                       if (gui->filename) {
+                               g_free (gui->filename);
+                       }
+
+                       file_data = gtk_selection_data_get_data (selection_data);
+                       file_list = g_strsplit ((gchar *)file_data, "\r\n", 0);
+
+                       file_uri = g_file_new_for_uri (file_list[0]);
+                       gui->filename = g_file_get_path (file_uri);
+
+                       g_strfreev (file_list);
+                       g_object_unref (file_uri);
+
+
+                       store = GTK_LIST_STORE (gtk_tree_view_get_model (gui->devmem_treeview));
+                       if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter)) {
+                               gtk_list_store_clear (store);
+                       }
+
+                       stlink_gui_set_sensitivity (gui, FALSE);
+                       gtk_notebook_set_current_page (gui->notebook, PAGE_FILEMEM);
+                       gtk_widget_show (GTK_WIDGET (gui->progress.bar));
+                       gtk_progress_bar_set_text (gui->progress.bar, "Reading file");
+                       g_thread_new ("file", (GThreadFunc) stlink_gui_populate_filemem_view, gui);
+                       break;
+               }
+       }
+       gtk_drag_finish (context,
+                        TRUE,
+                        gdk_drag_context_get_suggested_action (context) == GDK_ACTION_MOVE,
+                        time);
+}
+
+void
+stlink_gui_init_dnd (STlinkGUI *gui)
+{
+       GtkTargetEntry target_list[] = {
+               { "text/uri-list", 0, TARGET_FILENAME },
+       };
+
+       gtk_drag_dest_set (GTK_WIDGET (gui->window),
+                          GTK_DEST_DEFAULT_ALL,
+                          target_list,
+                          G_N_ELEMENTS (target_list),
+                          GDK_ACTION_COPY);
+
+       g_signal_connect (gui->window, "drag-data-received",
+                         G_CALLBACK (dnd_received_cb), gui);
+}
+
+static void
+stlink_gui_build_ui (STlinkGUI *gui) {
+       GtkBuilder   *builder;
+       GtkListStore *devmem_store;
+       GtkListStore *filemem_store;
+       gchar *ui_file = STLINK_UI_DIR "/stlink-gui.ui";
+
+       if (!g_file_test (ui_file, G_FILE_TEST_EXISTS)) {
+               ui_file = "stlink-gui.ui";
+       }
+       builder = gtk_builder_new ();
+       if (!gtk_builder_add_from_file (builder, ui_file, NULL)) {
+               g_printerr ("Failed to load UI file: %s\n", ui_file);
+               exit (1);
+       }
+
+       gui->window = GTK_WINDOW (gtk_builder_get_object (builder, "window"));
+       g_signal_connect (G_OBJECT (gui->window), "destroy",
+                         G_CALLBACK (gtk_main_quit), NULL);
+
+       /* set up toolutton clicked callbacks */
+       gui->open_button =
+               GTK_TOOL_BUTTON (gtk_builder_get_object (builder, "open_button"));
+       g_signal_connect (G_OBJECT (gui->open_button), "clicked",
+                         G_CALLBACK (open_button_cb), gui);
+
+       gui->connect_button =
+               GTK_TOOL_BUTTON (gtk_builder_get_object (builder, "connect_button"));
+       g_signal_connect (G_OBJECT (gui->connect_button), "clicked",
+                         G_CALLBACK (connect_button_cb), gui);
+
+       gui->disconnect_button =
+               GTK_TOOL_BUTTON (gtk_builder_get_object (builder, "disconnect_button"));
+       g_signal_connect (G_OBJECT (gui->disconnect_button), "clicked",
+                         G_CALLBACK (disconnect_button_cb), gui);
+
+       gui->flash_button =
+               GTK_TOOL_BUTTON (gtk_builder_get_object (builder, "flash_button"));
+       g_signal_connect (G_OBJECT (gui->flash_button), "clicked",
+                         G_CALLBACK (flash_button_cb), gui);
+
+       gui->devmem_treeview =
+               GTK_TREE_VIEW (gtk_builder_get_object (builder, "devmem_treeview"));
+       gtk_tree_view_set_rules_hint (gui->devmem_treeview, TRUE);
+       mem_view_init_headers (gui->devmem_treeview);
+       devmem_store = gtk_list_store_new (5,
+                                          G_TYPE_STRING,
+                                          G_TYPE_STRING,
+                                          G_TYPE_STRING,
+                                          G_TYPE_STRING,
+                                          G_TYPE_STRING);
+       gtk_tree_view_set_model (gui->devmem_treeview, GTK_TREE_MODEL (devmem_store));
+       g_object_unref (devmem_store);
+
+       gui->filemem_treeview =
+               GTK_TREE_VIEW (gtk_builder_get_object (builder, "filemem_treeview"));
+       gtk_tree_view_set_rules_hint (gui->filemem_treeview, TRUE);
+       mem_view_init_headers (gui->filemem_treeview);
+       filemem_store = gtk_list_store_new (5,
+                                          G_TYPE_STRING,
+                                          G_TYPE_STRING,
+                                          G_TYPE_STRING,
+                                          G_TYPE_STRING,
+                                          G_TYPE_STRING);
+       gtk_tree_view_set_model (gui->filemem_treeview, GTK_TREE_MODEL (filemem_store));
+       g_object_unref (filemem_store);
+
+       gui->core_id_label =
+               GTK_LABEL (gtk_builder_get_object (builder, "core_id_value"));
+
+       gui->chip_id_label =
+               GTK_LABEL (gtk_builder_get_object (builder, "chip_id_value"));
+
+       gui->flash_size_label =
+               GTK_LABEL (gtk_builder_get_object (builder, "flash_size_value"));
+
+       gui->ram_size_label =
+               GTK_LABEL (gtk_builder_get_object (builder, "ram_size_value"));
+
+       gui->device_frame =
+               GTK_FRAME (gtk_builder_get_object (builder, "device_frame"));
+
+       gui->notebook =
+               GTK_NOTEBOOK (gtk_builder_get_object (builder, "mem_notebook"));
+       g_signal_connect (gui->notebook, "switch-page",
+                         G_CALLBACK (notebook_switch_page_cb), gui);
+
+       gui->devmem_box =
+               GTK_BOX (gtk_builder_get_object (builder, "devmem_box"));
+
+       gui->filemem_box =
+               GTK_BOX (gtk_builder_get_object (builder, "filemem_box"));
+
+       gui->devmem_jmp_entry =
+               GTK_ENTRY (gtk_builder_get_object (builder, "devmem_jmp_entry"));
+       g_signal_connect (gui->devmem_jmp_entry, "activate",
+                         G_CALLBACK (devmem_jmp_cb), gui);
+
+       gui->filemem_jmp_entry =
+               GTK_ENTRY (gtk_builder_get_object (builder, "filemem_jmp_entry"));
+       g_signal_connect (gui->filemem_jmp_entry, "activate",
+                         G_CALLBACK (filemem_jmp_cb), gui);
+       gtk_editable_set_editable (GTK_EDITABLE (gui->filemem_jmp_entry), TRUE);
+
+       gui->progress.bar =
+               GTK_PROGRESS_BAR (gtk_builder_get_object (builder, "progressbar"));
+       gtk_progress_bar_set_show_text (gui->progress.bar, TRUE);
+       gui->progress.timer = g_timeout_add (100,
+                                            (GSourceFunc) progress_pulse_timeout,
+                                            gui);
+
+       gui->statusbar =
+               GTK_STATUSBAR (gtk_builder_get_object (builder, "statusbar"));
+
+       gui->infobar =
+               GTK_INFO_BAR (gtk_builder_get_object (builder, "infobar"));
+       gtk_info_bar_add_button (gui->infobar, GTK_STOCK_OK, GTK_RESPONSE_OK);
+       gui->infolabel = GTK_LABEL (gtk_label_new (""));
+       gtk_container_add (GTK_CONTAINER (gtk_info_bar_get_content_area (gui->infobar)),
+                          GTK_WIDGET (gui->infolabel));
+       g_signal_connect (gui->infobar, "response", G_CALLBACK (gtk_widget_hide), NULL);
+
+       /* flash dialog */
+       gui->flash_dialog =
+               GTK_DIALOG (gtk_builder_get_object (builder, "flash_dialog"));
+       g_signal_connect_swapped (gui->flash_dialog, "response",
+                                 G_CALLBACK (gtk_widget_hide), gui->flash_dialog);
+
+       gui->flash_dialog_ok =
+               GTK_BUTTON (gtk_builder_get_object (builder, "flash_dialog_ok_button"));
+
+       gui->flash_dialog_cancel =
+               GTK_BUTTON (gtk_builder_get_object (builder, "flash_dialog_cancel_button"));
+
+       gui->flash_dialog_entry =
+               GTK_ENTRY (gtk_builder_get_object (builder, "flash_dialog_entry"));
+
+       /* make it so */
+       gtk_widget_show_all (GTK_WIDGET (gui->window));
+       gtk_widget_hide (GTK_WIDGET (gui->infobar));
+       gtk_widget_hide (GTK_WIDGET (gui->progress.bar));
+
+       stlink_gui_set_disconnected (gui);
+}
+
+int
+main (int argc, char **argv)
+{
+       STlinkGUI *gui;
+
+       gtk_init (&argc, &argv);
+
+       gui = g_object_new (STLINK_TYPE_GUI, NULL);
+       stlink_gui_build_ui (gui);
+       stlink_gui_init_dnd (gui);
+
+       gtk_main ();
+
+       return 0;
+}
diff --git a/gui/stlink-gui.h b/gui/stlink-gui.h
new file mode 100644 (file)
index 0000000..a91c869
--- /dev/null
@@ -0,0 +1,93 @@
+
+#ifndef __STLINK_GUI_H__
+#define __STLINK_GUI_H__
+
+#include <glib-object.h>
+
+#define STLINK_TYPE_GUI             (stlink_gui_get_type ())
+#define STLINK_GUI(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), STLINK_TYPE_GUI, STlinkGUI))
+#define STLINK_IS_GUI(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), STLINK_TYPE_GUI))
+#define STLINK_GUI_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), STLINK_TYPE_GUI, STlinkGUIClass))
+#define STLINK_IS_GUI_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), STLINK_TYPE_GUI))
+#define STLINK_GUI_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), STLINK_TYPE_GUI, STlinkGUIlass))
+#define STLINK_GUI_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), STLINK_TYPE_GUI, STlinkGUIPrivate))
+
+typedef struct _STlinkGUI        STlinkGUI;
+typedef struct _STlinkGUIClass   STlinkGUIClass;
+typedef struct _STlinkGUIPrivate STlinkGUIPrivate;
+
+enum stlink_gui_pages_t {
+       PAGE_DEVMEM,
+       PAGE_FILEMEM
+};
+
+enum stlink_gui_dnd_targets_t {
+       TARGET_FILENAME,
+       TARGET_ROOTWIN
+};
+
+struct progress_t {
+       GtkProgressBar *bar;
+       guint           timer;
+       gboolean        activity_mode;
+       gdouble         fraction;
+};
+
+struct mem_t {
+       guchar *memory;
+       gsize   size;
+       guint32 base;
+};
+
+struct _STlinkGUI
+{
+       GObject parent_instance;
+
+       /*< private >*/
+       GtkWindow      *window;
+       GtkTreeView    *devmem_treeview;
+       GtkTreeView    *filemem_treeview;
+       GtkSpinner     *spinner;
+       GtkStatusbar   *statusbar;
+       GtkInfoBar     *infobar;
+       GtkLabel       *infolabel;
+       GtkNotebook    *notebook;
+       GtkFrame       *device_frame;
+       GtkLabel       *chip_id_label;
+       GtkLabel       *core_id_label;
+       GtkLabel       *flash_size_label;
+       GtkLabel       *ram_size_label;
+       GtkBox         *devmem_box;
+       GtkEntry       *devmem_jmp_entry;
+       GtkBox         *filemem_box;
+       GtkEntry       *filemem_jmp_entry;
+       GtkToolButton  *connect_button;
+       GtkToolButton  *disconnect_button;
+       GtkToolButton  *flash_button;
+       GtkToolButton  *open_button;
+
+       /* flash dialog */
+       GtkDialog  *flash_dialog;
+       GtkButton  *flash_dialog_ok;
+       GtkButton  *flash_dialog_cancel;
+       GtkEntry   *flash_dialog_entry;
+
+       struct progress_t  progress;
+       struct mem_t       flash_mem;
+       struct mem_t       file_mem;
+
+       gchar    *error_message;
+       gchar    *filename;
+       stlink_t *sl;
+};
+
+struct _STlinkGUIClass
+{
+       GObjectClass parent_class;
+
+       /* class members */
+};
+
+GType stlink_gui_get_type (void);
+
+#endif
diff --git a/gui/stlink-gui.ui b/gui/stlink-gui.ui
new file mode 100644 (file)
index 0000000..193925c
--- /dev/null
@@ -0,0 +1,666 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <!-- interface-requires gtk+ 3.0 -->
+  <object class="GtkDialog" id="flash_dialog">
+    <property name="can_focus">False</property>
+    <property name="border_width">5</property>
+    <property name="title" translatable="yes">Flash device</property>
+    <property name="type_hint">dialog</property>
+    <child internal-child="vbox">
+      <object class="GtkBox" id="flash_dialog-vbox">
+        <property name="can_focus">False</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">2</property>
+        <child internal-child="action_area">
+          <object class="GtkButtonBox" id="dialog-action_area1">
+            <property name="can_focus">False</property>
+            <property name="layout_style">end</property>
+            <child>
+              <object class="GtkButton" id="flash_dialog_cancel_button">
+                <property name="label">gtk-cancel</property>
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="receives_default">True</property>
+                <property name="use_stock">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton" id="flash_dialog_ok_button">
+                <property name="label">gtk-ok</property>
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="receives_default">True</property>
+                <property name="use_stock">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="pack_type">end</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkGrid" id="flash_dialog_grid">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="margin_left">5</property>
+            <property name="margin_right">5</property>
+            <property name="margin_top">5</property>
+            <property name="margin_bottom">5</property>
+            <property name="column_spacing">5</property>
+            <property name="column_homogeneous">True</property>
+            <child>
+              <object class="GtkLabel" id="flash_dialog_label">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="label" translatable="yes">Address to write at:</property>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">0</property>
+                <property name="width">1</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkEntry" id="flash_dialog_entry">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="invisible_char">•</property>
+                <property name="width_chars">12</property>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="top_attach">0</property>
+                <property name="width">1</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">2</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <action-widgets>
+      <action-widget response="0">flash_dialog_cancel_button</action-widget>
+      <action-widget response="-5">flash_dialog_ok_button</action-widget>
+    </action-widgets>
+  </object>
+  <object class="GtkWindow" id="window">
+    <property name="can_focus">False</property>
+    <property name="title" translatable="yes">STlink GUI</property>
+    <property name="default_width">550</property>
+    <property name="default_height">480</property>
+    <child>
+      <object class="GtkGrid" id="maingrid">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="orientation">vertical</property>
+        <child>
+          <object class="GtkToolbar" id="toolbar">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="hexpand">True</property>
+            <child>
+              <object class="GtkToolButton" id="open_button">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="tooltip_text" translatable="yes">Open</property>
+                <property name="label" translatable="yes">Open</property>
+                <property name="use_underline">True</property>
+                <property name="stock_id">gtk-open</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="homogeneous">True</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkToolButton" id="connect_button">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="tooltip_text" translatable="yes">Connect</property>
+                <property name="label" translatable="yes">Connect</property>
+                <property name="use_underline">True</property>
+                <property name="stock_id">gtk-connect</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="homogeneous">True</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkToolButton" id="disconnect_button">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="tooltip_text" translatable="yes">Disconnect</property>
+                <property name="label" translatable="yes">Disconnect</property>
+                <property name="use_underline">True</property>
+                <property name="stock_id">gtk-disconnect</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="homogeneous">True</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkToolButton" id="flash_button">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="tooltip_text" translatable="yes">Flash</property>
+                <property name="label" translatable="yes">Flash</property>
+                <property name="use_underline">True</property>
+                <property name="stock_id">gtk-media-record</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="homogeneous">True</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkToolItem" id="toolProgressbar">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <child>
+                  <object class="GtkProgressBar" id="progressbar">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="halign">start</property>
+                    <property name="margin_top">5</property>
+                    <property name="margin_bottom">5</property>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="homogeneous">True</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">0</property>
+            <property name="width">1</property>
+            <property name="height">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkGrid" id="device_grid">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="margin_left">5</property>
+            <property name="margin_top">5</property>
+            <property name="margin_bottom">5</property>
+            <child>
+              <object class="GtkFrame" id="device_frame">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="opacity">0.98999999999999999</property>
+                <property name="margin_left">4</property>
+                <property name="margin_right">4</property>
+                <property name="border_width">1</property>
+                <property name="label_xalign">0</property>
+                <child>
+                  <object class="GtkAlignment" id="alignment1">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="left_padding">12</property>
+                    <property name="right_padding">12</property>
+                    <child>
+                      <object class="GtkGrid" id="devstatus_grid">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="row_spacing">2</property>
+                        <property name="column_spacing">6</property>
+                        <property name="row_homogeneous">True</property>
+                        <child>
+                          <object class="GtkLabel" id="chip_label">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="margin_right">1</property>
+                            <property name="margin_top">1</property>
+                            <property name="xalign">0</property>
+                            <property name="yalign">0</property>
+                            <property name="label" translatable="yes">Chip:</property>
+                          </object>
+                          <packing>
+                            <property name="left_attach">0</property>
+                            <property name="top_attach">0</property>
+                            <property name="width">1</property>
+                            <property name="height">1</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkLabel" id="core_label">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="xalign">0</property>
+                            <property name="yalign">0</property>
+                            <property name="label" translatable="yes">Core:</property>
+                          </object>
+                          <packing>
+                            <property name="left_attach">0</property>
+                            <property name="top_attach">1</property>
+                            <property name="width">1</property>
+                            <property name="height">1</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkLabel" id="flash_label">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="xalign">0</property>
+                            <property name="yalign">0</property>
+                            <property name="label" translatable="yes">Flash size:</property>
+                          </object>
+                          <packing>
+                            <property name="left_attach">0</property>
+                            <property name="top_attach">2</property>
+                            <property name="width">1</property>
+                            <property name="height">1</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkLabel" id="core_id_value">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="xalign">0</property>
+                            <property name="yalign">0</property>
+                            <property name="single_line_mode">True</property>
+                          </object>
+                          <packing>
+                            <property name="left_attach">1</property>
+                            <property name="top_attach">1</property>
+                            <property name="width">1</property>
+                            <property name="height">1</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkLabel" id="chip_id_value">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="xalign">0</property>
+                            <property name="yalign">0</property>
+                            <property name="width_chars">20</property>
+                          </object>
+                          <packing>
+                            <property name="left_attach">1</property>
+                            <property name="top_attach">0</property>
+                            <property name="width">1</property>
+                            <property name="height">1</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkLabel" id="flash_size_value">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="xalign">0</property>
+                            <property name="yalign">0</property>
+                          </object>
+                          <packing>
+                            <property name="left_attach">1</property>
+                            <property name="top_attach">2</property>
+                            <property name="width">1</property>
+                            <property name="height">1</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkLabel" id="ram_size_label">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="xalign">0</property>
+                            <property name="yalign">0</property>
+                            <property name="label" translatable="yes">Ram size:</property>
+                          </object>
+                          <packing>
+                            <property name="left_attach">0</property>
+                            <property name="top_attach">3</property>
+                            <property name="width">1</property>
+                            <property name="height">1</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkLabel" id="ram_size_value">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="xalign">0</property>
+                            <property name="yalign">0</property>
+                          </object>
+                          <packing>
+                            <property name="left_attach">1</property>
+                            <property name="top_attach">3</property>
+                            <property name="width">1</property>
+                            <property name="height">1</property>
+                          </packing>
+                        </child>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+                <child type="label">
+                  <object class="GtkLabel" id="device_frame_label">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="yalign">0.49000000953674316</property>
+                    <property name="xpad">2</property>
+                    <property name="label" translatable="yes">&lt;b&gt;Device&lt;/b&gt;</property>
+                    <property name="use_markup">True</property>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">0</property>
+                <property name="width">1</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">2</property>
+            <property name="width">1</property>
+            <property name="height">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkStatusbar" id="statusbar">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="margin_left">5</property>
+            <property name="margin_right">5</property>
+            <property name="margin_bottom">5</property>
+            <property name="orientation">vertical</property>
+            <property name="spacing">2</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">4</property>
+            <property name="width">1</property>
+            <property name="height">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkNotebook" id="mem_notebook">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="margin_left">5</property>
+            <property name="margin_right">5</property>
+            <property name="margin_top">5</property>
+            <property name="margin_bottom">5</property>
+            <child>
+              <object class="GtkBox" id="devmem_box">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="orientation">vertical</property>
+                <child>
+                  <object class="GtkGrid" id="devmem_jmp_grid">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <child>
+                      <object class="GtkLabel" id="devmem_jmp">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="halign">start</property>
+                        <property name="margin_left">5</property>
+                        <property name="margin_right">5</property>
+                        <property name="margin_top">5</property>
+                        <property name="margin_bottom">5</property>
+                        <property name="label" translatable="yes">Goto address:</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">0</property>
+                        <property name="top_attach">0</property>
+                        <property name="width">1</property>
+                        <property name="height">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkEntry" id="devmem_jmp_entry">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="margin_left">5</property>
+                        <property name="margin_right">5</property>
+                        <property name="margin_top">5</property>
+                        <property name="margin_bottom">5</property>
+                        <property name="max_length">15</property>
+                        <property name="invisible_char">•</property>
+                        <property name="width_chars">12</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="top_attach">0</property>
+                        <property name="width">1</property>
+                        <property name="height">1</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkScrolledWindow" id="devmem_scrolledwindow">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="vexpand">True</property>
+                    <property name="shadow_type">in</property>
+                    <child>
+                      <object class="GtkTreeView" id="devmem_treeview">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="rules_hint">True</property>
+                        <property name="enable_grid_lines">both</property>
+                        <child internal-child="selection">
+                          <object class="GtkTreeSelection" id="treeview-selection1"/>
+                        </child>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="menu_label">Device memory</property>
+              </packing>
+            </child>
+            <child type="tab">
+              <object class="GtkLabel" id="devmem_label">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="label" translatable="yes">Device memory</property>
+              </object>
+              <packing>
+                <property name="tab_fill">False</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkBox" id="filemem_box">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="orientation">vertical</property>
+                <child>
+                  <object class="GtkGrid" id="filemem_jmp_grid">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <child>
+                      <object class="GtkLabel" id="filemem_jmp">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="margin_left">5</property>
+                        <property name="margin_right">5</property>
+                        <property name="margin_top">5</property>
+                        <property name="margin_bottom">5</property>
+                        <property name="label" translatable="yes">Goto address:</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">0</property>
+                        <property name="top_attach">0</property>
+                        <property name="width">1</property>
+                        <property name="height">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkEntry" id="filemem_jmp_entry">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="margin_left">5</property>
+                        <property name="margin_right">5</property>
+                        <property name="margin_top">5</property>
+                        <property name="margin_bottom">5</property>
+                        <property name="max_length">15</property>
+                        <property name="invisible_char">•</property>
+                        <property name="width_chars">12</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="top_attach">0</property>
+                        <property name="width">1</property>
+                        <property name="height">1</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkScrolledWindow" id="filemem_scrolledwindow">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="vexpand">True</property>
+                    <property name="shadow_type">in</property>
+                    <child>
+                      <object class="GtkTreeView" id="filemem_treeview">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="rules_hint">True</property>
+                        <property name="enable_grid_lines">both</property>
+                        <child internal-child="selection">
+                          <object class="GtkTreeSelection" id="treeview-selection2"/>
+                        </child>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child type="tab">
+              <object class="GtkLabel" id="filemem_label">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="label" translatable="yes">No file</property>
+              </object>
+              <packing>
+                <property name="position">1</property>
+                <property name="tab_fill">False</property>
+              </packing>
+            </child>
+            <child>
+              <placeholder/>
+            </child>
+            <child type="tab">
+              <placeholder/>
+            </child>
+            <child>
+              <placeholder/>
+            </child>
+            <child type="tab">
+              <placeholder/>
+            </child>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">3</property>
+            <property name="width">1</property>
+            <property name="height">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkInfoBar" id="infobar">
+            <property name="visible">True</property>
+            <property name="app_paintable">True</property>
+            <property name="can_focus">False</property>
+            <property name="message_type">error</property>
+            <child internal-child="content_area">
+              <object class="GtkBox" id="infobar-content_area1">
+                <property name="can_focus">False</property>
+                <property name="border_width">8</property>
+                <property name="spacing">5</property>
+                <child>
+                  <placeholder/>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">True</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child internal-child="action_area">
+              <object class="GtkButtonBox" id="infobar-action_area1">
+                <property name="can_focus">False</property>
+                <property name="border_width">5</property>
+                <property name="orientation">vertical</property>
+                <property name="spacing">6</property>
+                <property name="layout_style">end</property>
+                <child>
+                  <placeholder/>
+                </child>
+                <child>
+                  <placeholder/>
+                </child>
+                <child>
+                  <placeholder/>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">1</property>
+            <property name="width">1</property>
+            <property name="height">1</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+  </object>
+</interface>
diff --git a/src/st-term.c b/src/st-term.c
new file mode 100644 (file)
index 0000000..f464393
--- /dev/null
@@ -0,0 +1,195 @@
+#include <stdio.h>
+/* According to POSIX.1-2001 */
+#include <sys/select.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <termios.h>
+#include <fcntl.h>
+#include <signal.h>
+#include "stlink-common.h"
+
+#define STLINKY_MAGIC 0xDEADF00D
+
+struct stlinky {
+       stlink_t *sl;
+       uint32_t off;
+       size_t bufsize;
+};
+
+
+/* Detects stlinky in RAM, returns handler */
+struct stlinky*  stlinky_detect(stlink_t* sl)
+{
+       static const uint32_t sram_base = 0x20000000;
+       struct stlinky* st = malloc(sizeof(struct stlinky));
+       st->sl = sl;
+       printf("sram: 0x%x bytes @ 0x%x\n", sl->sram_base, sl->sram_size);
+       uint32_t off;
+       for (off = 0; off < sl->sram_size; off += 4) {
+               stlink_read_mem32(sl, sram_base + off, 4);
+               if ( STLINKY_MAGIC== *(uint32_t*) sl->q_buf)
+               {
+                       printf("stlinky detected at 0x%x\n", sram_base + off);
+                       st->off = sram_base + off;
+                       stlink_read_mem32(sl, st->off + 4, 4);
+                       st->bufsize = (size_t) *(unsigned char*) sl->q_buf;
+                       printf("stlinky buffer size 0x%zu \n", st->bufsize);
+                       return st;
+               }
+       }
+       return NULL;
+}
+
+int stlinky_canrx(struct stlinky *st)
+{
+       stlink_read_mem32(st->sl, st->off+4, 4);
+       unsigned char tx = (unsigned char) st->sl->q_buf[1];
+       return (int) tx;
+}
+
+size_t stlinky_rx(struct stlinky *st, char* buffer)
+{
+       unsigned char tx = 0;
+       while(tx == 0) {
+               stlink_read_mem32(st->sl, st->off+4, 4);
+               tx = (unsigned char) st->sl->q_buf[1];
+       }
+       size_t rs = tx + (4 - (tx % 4)); /* voodoo */
+       stlink_read_mem32(st->sl, st->off+8, rs);
+       memcpy(buffer, st->sl->q_buf, (size_t) tx);
+       *st->sl->q_buf=0x0;
+       stlink_write_mem8(st->sl, st->off+5, 1);
+       return (size_t) tx;
+}
+
+size_t stlinky_tx(struct stlinky *st, char* buffer, size_t sz)
+{
+       unsigned char rx = 1;
+       while(rx != 0) {
+               stlink_read_mem32(st->sl, st->off+4, 4);
+               rx = (unsigned char) st->sl->q_buf[2];
+       }
+       memcpy(st->sl->q_buf, buffer, sz);
+       size_t rs = sz + (4 - (sz % 4)); /* voodoo */
+       stlink_write_mem32(st->sl, st->off+8+st->bufsize, rs);
+       *st->sl->q_buf=(unsigned char) sz;
+       stlink_write_mem8(st->sl, st->off+6, 1);
+       return (size_t) rx;
+}
+
+int kbhit()
+{
+       struct timeval tv;
+       fd_set fds;
+       tv.tv_sec = 0;
+       tv.tv_usec = 0;
+       FD_ZERO(&fds);
+       FD_SET(STDIN_FILENO, &fds); //STDIN_FILENO is 0
+       select(STDIN_FILENO+1, &fds, NULL, NULL, &tv);
+       return FD_ISSET(STDIN_FILENO, &fds);
+}
+
+void nonblock(int state)
+{
+       struct termios ttystate;
+
+       //get the terminal state
+       tcgetattr(STDIN_FILENO, &ttystate);
+
+       if (state==1)
+       {
+               //turn off canonical mode
+               ttystate.c_lflag &= ~ICANON;
+               ttystate.c_lflag &= ~ECHO;
+               //minimum of number input read.
+               ttystate.c_cc[VMIN] = 1;
+       }
+       else if (state==0)
+       {
+               //turn on canonical mode
+               ttystate.c_lflag |= ICANON | ECHO;
+       }
+       //set the terminal attributes.
+       tcsetattr(STDIN_FILENO, TCSANOW, &ttystate);
+
+}
+
+static int keep_running = 1;
+static int sigcount=0;
+void cleanup(int dummy)
+{
+       sigcount++;
+       keep_running = 0;
+       printf("\n\nGot a signal\n");
+       if (sigcount==2) {
+               printf("\n\nGot a second signal - bailing out\n");
+               exit(1);
+       }
+}
+
+
+int main(int ac, char** av) {
+       stlink_t* sl;
+
+       /* unused */
+       ac = ac;
+       av = av;
+       sl = stlink_open_usb(10);
+       if (sl != NULL) {
+               printf("ST-Linky proof-of-concept terminal :: Created by Necromant for lulz\n");
+               stlink_version(sl);
+               stlink_enter_swd_mode(sl);
+               printf("chip id: %#x\n", sl->chip_id);
+               printf("core_id: %#x\n", sl->core_id);
+
+               cortex_m3_cpuid_t cpuid;
+               stlink_cpu_id(sl, &cpuid);
+               printf("cpuid:impl_id = %0#x, variant = %#x\n", cpuid.implementer_id, cpuid.variant);
+               printf("cpuid:part = %#x, rev = %#x\n", cpuid.part, cpuid.revision);
+
+               stlink_reset(sl);
+               stlink_force_debug(sl);
+               stlink_run(sl);
+               stlink_status(sl);
+
+               /* wait for device to boot */
+               /* TODO: Make timeout adjustable via command line */
+               sleep(1);
+
+               struct stlinky *st = stlinky_detect(sl);
+               if (st == NULL)
+               {
+                       printf("stlinky magic not found in sram :(\n");
+                       goto bailout;
+               }
+               char* rxbuf = malloc(st->bufsize);
+               char* txbuf = malloc(st->bufsize);
+               size_t tmp;
+               nonblock(1);
+               int fd = fileno(stdin);
+               int saved_flags = fcntl(fd, F_GETFL);
+               fcntl(fd, F_SETFL, saved_flags & ~O_NONBLOCK);
+               signal(SIGINT, cleanup);
+               printf("Entering interactive terminal. CTRL+C to exit\n\n\n");
+               while(1) {
+                       if (stlinky_canrx(st)) {
+                               tmp = stlinky_rx(st, rxbuf);
+                               fwrite(rxbuf,tmp,1,stdout);
+                               fflush(stdout);
+                       }
+                       if (kbhit()) {
+                               tmp = read(fd, txbuf, st->bufsize);
+                               stlinky_tx(st,txbuf,tmp);
+                       }
+                       if (!keep_running)
+                               break;
+               }
+       bailout:
+               nonblock(0);
+               stlink_exit_debug_mode(sl);
+               stlink_close(sl);
+       }
+       return 0;
+}
index 277431a872979c6ef18d512882321701678d6b3f..d574584281e3f5668c532b84a75aba33cd81edc1 100644 (file)
@@ -729,15 +729,46 @@ stlink_t* stlink_open_usb(const int verbose) {
         goto on_error;
     }
     
-    slu->usb_handle = libusb_open_device_with_vid_pid(slu->libusb_ctx, USB_ST_VID, USB_STLINK_32L_PID);
-    if (slu->usb_handle == NULL) {
-       slu->usb_handle = libusb_open_device_with_vid_pid(slu->libusb_ctx, USB_ST_VID, USB_STLINK_PID);
-       if (slu->usb_handle == NULL) {
-           WLOG("Couldn't find any ST-Link/V2 devices\n");
+    libusb_device **list;
+    int cnt = libusb_get_device_list(slu->libusb_ctx, &list);
+    struct libusb_device_descriptor desc;
+    int devBus =0;
+    int devAddr=0;
+    
+    char *device = getenv("STLINK_DEVICE");
+    if (device) {
+       char *c = strchr(device,':');
+       if (c==NULL) {
+           WLOG("STLINK_DEVICE must be <USB_BUS>:<USB_ADDR> format\n");
            goto on_error;
        }
-       slu->protocoll = 1;
+       devBus=atoi(device);
+       *c++=0;
+       devAddr=atoi(c);
+       ILOG("bus %03d dev %03d\n",devBus, devAddr);
+    }
+    while (cnt){
+       cnt--;
+        libusb_get_device_descriptor( list[cnt], &desc );
+        if (desc.idVendor!=USB_ST_VID) continue;
+        if (devBus && devAddr)
+            if ((libusb_get_bus_number(list[cnt])!=devBus) || (libusb_get_device_address(list[cnt])!=devAddr)) continue;
+        if (desc.idProduct == USB_STLINK_32L_PID) break;
+        if (desc.idProduct == USB_STLINK_PID) slu->protocoll = 1; break;
+    }
+    
+    if (cnt < 0) {
+           WLOG ("Couldn't find %s ST-Link/V2 devices\n",(devBus && devAddr)?"matched":"any");
+           goto on_error;
+    } else {
+       if( libusb_open(list[cnt], &slu->usb_handle) !=0){
+           WLOG("Couldn't open ST-Link/V2 device %03d:%03d\n",libusb_get_bus_number(list[cnt]), libusb_get_device_address(list[cnt]));
+           goto on_error;
+       }
     }
+    
+    libusb_free_device_list(list, 1);
+    
 
     if (libusb_kernel_driver_active(slu->usb_handle, 0) == 1) {
         int r;