Merge pull request #159 from jonasdn/check-for-ui-file
[fw/stlink] / gui / stlink-gui.c
1 #include <string.h>
2 #include <stdlib.h>
3 #include <errno.h>
4 #include <gtk/gtk.h>
5
6 #include "stlink-common.h"
7 #include "stlink-gui.h"
8
9 #define MEM_READ_SIZE 1024
10
11 #ifndef G_VALUE_INIT
12 #define G_VALUE_INIT {0, {{0}}}
13 #endif
14
15 G_DEFINE_TYPE (STlinkGUI, stlink_gui, G_TYPE_OBJECT);
16
17 static void
18 stlink_gui_dispose (GObject *gobject)
19 {
20         G_OBJECT_CLASS (stlink_gui_parent_class)->dispose (gobject);
21 }
22
23 static void
24 stlink_gui_finalize (GObject *gobject)
25 {
26   G_OBJECT_CLASS (stlink_gui_parent_class)->finalize (gobject);
27 }
28
29 static void
30 stlink_gui_class_init (STlinkGUIClass *klass)
31 {
32         GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
33
34         gobject_class->dispose  = stlink_gui_dispose;
35         gobject_class->finalize = stlink_gui_finalize;
36 }
37
38 static void
39 stlink_gui_init (STlinkGUI *self)
40 {
41         self->sl       = NULL;
42         self->filename = NULL;
43
44         self->progress.activity_mode = FALSE;
45         self->progress.fraction      = 0;
46
47         self->flash_mem.memory = NULL;
48         self->flash_mem.size   = 0;
49         self->flash_mem.base   = 0;
50
51         self->file_mem.memory = NULL;
52         self->file_mem.size   = 0;
53         self->file_mem.base   = 0;
54 }
55
56 static gboolean
57 set_info_error_message_idle (STlinkGUI *gui)
58 {
59         if (gui->error_message != NULL) {
60                 gchar *markup;
61
62                 markup = g_markup_printf_escaped ("<b>%s</b>", gui->error_message);
63                 gtk_label_set_markup (gui->infolabel, markup);
64                 gtk_info_bar_set_message_type (gui->infobar, GTK_MESSAGE_ERROR);
65                 gtk_widget_show (GTK_WIDGET (gui->infobar));
66
67                 g_free (markup);
68                 g_free (gui->error_message);
69                 gui->error_message = NULL;
70         }
71         return FALSE;
72 }
73
74 static void
75 stlink_gui_set_info_error_message (STlinkGUI *gui, const gchar *message)
76 {
77         gui->error_message = g_strdup (message);
78         g_idle_add ((GSourceFunc) set_info_error_message_idle, gui);
79 }
80
81 static void
82 stlink_gui_set_sensitivity (STlinkGUI *gui, gboolean sensitivity)
83 {
84         gtk_widget_set_sensitive (GTK_WIDGET (gui->open_button), sensitivity);
85
86         if (sensitivity && gui->sl)
87                 gtk_widget_set_sensitive (GTK_WIDGET (gui->disconnect_button), sensitivity);
88
89         if (sensitivity && !gui->sl)
90                 gtk_widget_set_sensitive (GTK_WIDGET (gui->connect_button), sensitivity);
91
92         if (sensitivity && gui->sl && gui->filename)
93                 gtk_widget_set_sensitive (GTK_WIDGET (gui->flash_button), sensitivity);
94 }
95
96 static void
97 mem_view_init_headers (GtkTreeView *view)
98 {
99         GtkCellRenderer *renderer;
100         gint             i;
101
102         g_return_if_fail (view != NULL);
103
104         renderer = gtk_cell_renderer_text_new ();
105         gtk_tree_view_insert_column_with_attributes (view,
106                                                      -1,
107                                                      "Address",
108                                                      renderer,
109                                                      "text",
110                                                      0, /* column */
111                                                      NULL);
112         for (i = 0; i < 4; i++) {
113                 gchar *label;
114
115                 label = g_strdup_printf ("%X", i * 4);
116                 renderer = gtk_cell_renderer_text_new ();
117                 gtk_tree_view_insert_column_with_attributes (view,
118                                                              -1,
119                                                              label,
120                                                              renderer,
121                                                              "text",
122                                                              (i + 1), /* column */
123                                                              NULL);
124                 g_free (label);
125         }
126
127         for (i = 0; i < 5; i++) {
128                 GtkTreeViewColumn *column = gtk_tree_view_get_column (view, i);
129                 gtk_tree_view_column_set_expand (column, TRUE);
130         }
131 }
132
133 static void
134 mem_view_add_as_hex (GtkListStore *store,
135                      GtkTreeIter  *iter,
136                      gint          column,
137                      guint32       value)
138 {
139         gchar     *hex_str;
140
141         hex_str = g_strdup_printf ("0x%08X", value);
142         gtk_list_store_set (store, iter, column, hex_str, -1);
143         g_free (hex_str);
144 }
145
146 static void
147 mem_view_add_buffer (GtkListStore *store,
148                      GtkTreeIter  *iter,
149                      guint32       address,
150                      guchar       *buffer,
151                      gint          len)
152 {
153         guint32 *word;
154         gint     i, step;
155         gint     column = 0;
156
157         step = sizeof (*word);
158
159         for (i = 0; i < len; i += step) {
160                 word = (guint *) &buffer[i];
161
162                 if (column == 0) {
163                         /* new row */
164                         gtk_list_store_append (store, iter);
165
166                         /* add address */
167                         mem_view_add_as_hex (store, iter, column, (address + i));
168                 }
169                 mem_view_add_as_hex (store, iter, (column + 1), *word);
170                 column = (column + 1) % step;
171         }
172 }
173
174 static guint32
175 hexstr_to_guint32 (const gchar *str, GError **err)
176 {
177         guint32  val;
178         gchar   *end_ptr;
179
180         val = strtoul (str, &end_ptr, 16);
181         if ((errno == ERANGE && val == LONG_MAX) || (errno != 0 && val == 0)) {
182                 g_set_error (err,
183                              g_quark_from_string ("hextou32"),
184                              1,
185                              "Invalid hexstring");
186                 return LONG_MAX;
187         }
188         if (end_ptr == str) {
189                 g_set_error (err,
190                              g_quark_from_string ("hextou32"),
191                              2,
192                              "Invalid hexstring");
193                 return LONG_MAX;
194         }
195         return val;
196 }
197
198
199 static void
200 stlink_gui_update_mem_view (STlinkGUI *gui, struct mem_t *mem, GtkTreeView *view) {
201         GtkListStore *store;
202         GtkTreeIter   iter;
203
204         store = GTK_LIST_STORE (gtk_tree_view_get_model (view));
205
206         mem_view_add_buffer (store,
207                              &iter,
208                              mem->base,
209                              mem->memory,
210                              mem->size);
211
212         gtk_widget_hide (GTK_WIDGET (gui->progress.bar));
213         gtk_progress_bar_set_fraction (gui->progress.bar, 0);
214         stlink_gui_set_sensitivity (gui, TRUE);
215 }
216
217 static gboolean
218 stlink_gui_update_devmem_view (STlinkGUI *gui)
219 {
220         stlink_gui_update_mem_view (gui, &gui->flash_mem, gui->devmem_treeview);
221         return FALSE;
222 }
223
224
225 static void
226 stlink_gui_populate_devmem_view (STlinkGUI *gui)
227 {
228         guint            off;
229         stm32_addr_t     addr;
230
231         g_return_if_fail (gui != NULL);
232         g_return_if_fail (gui->sl != NULL);
233
234         addr = gui->sl->flash_base;
235
236         if (gui->flash_mem.memory) {
237                 g_free (gui->flash_mem.memory);
238         }
239         gui->flash_mem.memory = g_malloc (gui->sl->flash_size);
240         gui->flash_mem.size   = gui->sl->flash_size;
241         gui->flash_mem.base   = gui->sl->flash_base;
242
243         for (off = 0; off < gui->sl->flash_size; off += MEM_READ_SIZE) {
244                 guint   n_read = MEM_READ_SIZE;
245
246                 if (off + MEM_READ_SIZE > gui->sl->flash_size) {
247                         n_read = gui->sl->flash_size - off;
248
249                         /* align if needed */
250                         if (n_read & 3) {
251                                 n_read = (n_read + 4) & ~(3);
252                         }
253                 }
254                 /* reads to sl->q_buf */
255                 stlink_read_mem32(gui->sl, addr + off, n_read);
256                 if (gui->sl->q_len < 0) {
257                         stlink_gui_set_info_error_message (gui, "Failed to read memory");
258                         g_free (gui->flash_mem.memory);
259                         gui->flash_mem.memory = NULL;
260                         return;
261                 }
262                 memcpy (gui->flash_mem.memory + off, gui->sl->q_buf, n_read);
263                 gui->progress.fraction = (gdouble) (off + n_read) / gui->sl->flash_size;
264         }
265         g_idle_add ((GSourceFunc) stlink_gui_update_devmem_view, gui);
266 }
267
268 static gboolean
269 stlink_gui_update_filemem_view (STlinkGUI *gui)
270 {
271         gchar *basename;
272
273         basename = g_path_get_basename (gui->filename);
274         gtk_notebook_set_tab_label_text (gui->notebook,
275                                          GTK_WIDGET (gtk_notebook_get_nth_page (gui->notebook, 1)),
276                                          basename);
277         g_free (basename);
278
279         stlink_gui_update_mem_view (gui, &gui->file_mem, gui->filemem_treeview);
280
281         return FALSE;
282 }
283
284 static gpointer
285 stlink_gui_populate_filemem_view (STlinkGUI *gui)
286 {
287         guchar        buffer[MEM_READ_SIZE];
288         GFile        *file;
289         GFileInfo    *file_info;
290         GInputStream *input_stream;
291         gint          off;
292         GError       *err = NULL;
293
294         g_return_val_if_fail (gui != NULL, NULL);
295         g_return_val_if_fail (gui->filename != NULL, NULL);
296
297         file = g_file_new_for_path (gui->filename);
298         input_stream = G_INPUT_STREAM (g_file_read (file, NULL, &err));
299         if (err) {
300                 stlink_gui_set_info_error_message (gui, err->message);
301                 g_error_free (err);
302                 goto out;
303         }
304
305         file_info = g_file_input_stream_query_info (G_FILE_INPUT_STREAM (input_stream),
306                                                     G_FILE_ATTRIBUTE_STANDARD_SIZE, NULL, &err);
307         if (err) {
308                 stlink_gui_set_info_error_message (gui, err->message);
309                 g_error_free (err);
310                 goto out_input;
311         }
312         if (gui->file_mem.memory) {
313                 g_free (gui->file_mem.memory);
314         }
315         gui->file_mem.size   = g_file_info_get_size (file_info);
316         gui->file_mem.memory = g_malloc (gui->file_mem.size);
317
318         for (off = 0; off < gui->file_mem.size; off += MEM_READ_SIZE) {
319                 guint   n_read = MEM_READ_SIZE;
320
321                 if (off + MEM_READ_SIZE > gui->file_mem.size) {
322                         n_read = gui->file_mem.size - off;
323                 }
324
325                 if (g_input_stream_read (G_INPUT_STREAM (input_stream),
326                                          &buffer, n_read, NULL, &err) == -1) {
327                         stlink_gui_set_info_error_message (gui, err->message);
328                         g_error_free (err);
329                         goto out_input;
330                 }
331                 memcpy (gui->file_mem.memory + off, buffer, n_read);
332                 gui->progress.fraction = (gdouble) (off + n_read) / gui->file_mem.size;
333         }
334         g_idle_add ((GSourceFunc) stlink_gui_update_filemem_view, gui);
335
336  out_input:
337         g_object_unref (input_stream);
338  out:
339         g_object_unref (file);
340         return NULL;
341 }
342
343 static void mem_jmp (GtkTreeView *view,
344                      GtkEntry    *entry,
345                      guint32      base_addr,
346                      gsize        size,
347                      GError     **err)
348 {
349         GtkTreeModel *model;
350         guint32       jmp_addr;
351         GtkTreeIter   iter;
352
353         jmp_addr = hexstr_to_guint32 (gtk_entry_get_text (entry), err);
354         if (err && *err) {
355                 return;
356         }
357
358         if (jmp_addr < base_addr || jmp_addr > base_addr + size) {
359                 g_set_error (err,
360                              g_quark_from_string ("mem_jmp"),
361                              1,
362                              "Invalid address");
363                 return;
364         }
365
366         model = gtk_tree_view_get_model (view);
367         if (!model) {
368                 return;
369         }
370
371         if (gtk_tree_model_get_iter_first (model, &iter)) {
372                 do {
373                         guint32 addr;
374                         GValue  value = G_VALUE_INIT;
375                         GError *err   = NULL;
376
377                         gtk_tree_model_get_value (model, &iter, 0, &value);
378                         if (G_VALUE_HOLDS_STRING (&value)) {
379                                 addr = hexstr_to_guint32 (g_value_get_string (&value), &err);
380                                 if (!err) {
381                                         if (addr == (jmp_addr & 0xFFFFFFF0)) {
382                                                 GtkTreeSelection *selection;
383                                                 GtkTreePath      *path;
384
385                                                 selection = gtk_tree_view_get_selection (view);
386                                                 path      = gtk_tree_model_get_path (model, &iter);
387
388                                                 gtk_tree_selection_select_iter (selection, &iter);
389                                                 gtk_tree_view_scroll_to_cell (view,
390                                                                               path,
391                                                                               NULL,
392                                                                               TRUE,
393                                                                               0.0,
394                                                                               0.0);
395                                                 gtk_tree_path_free (path);
396                                         }
397                                 }
398                         }
399                         g_value_unset (&value);
400                 } while (gtk_tree_model_iter_next (model, &iter));
401         }
402 }
403
404 static void
405 devmem_jmp_cb (GtkWidget *widget, gpointer data)
406 {
407         STlinkGUI *gui;
408         GError    *err = NULL;
409
410         gui = STLINK_GUI (data);
411
412         mem_jmp (gui->devmem_treeview,
413                  gui->devmem_jmp_entry,
414                  gui->sl->flash_base,
415                  gui->sl->flash_size,
416                  &err);
417
418         if (err) {
419                 stlink_gui_set_info_error_message (gui, err->message);
420                 g_error_free (err);
421         }
422 }
423
424 static void
425 filemem_jmp_cb (GtkWidget *widget, gpointer data)
426 {
427         STlinkGUI *gui;
428         GError    *err = NULL;
429
430         gui = STLINK_GUI (data);
431
432         g_return_if_fail (gui->filename != NULL);
433
434         mem_jmp (gui->filemem_treeview,
435                  gui->filemem_jmp_entry,
436                  0,
437                  gui->file_mem.size,
438                  &err);
439
440         if (err) {
441                 stlink_gui_set_info_error_message (gui, err->message);
442                 g_error_free (err);
443         }
444 }
445
446 static gchar *
447 dev_format_chip_id (guint32 chip_id)
448 {
449         gint i;
450
451         for (i = 0; i < sizeof (devices) / sizeof (devices[0]); i++) {
452                 if (chip_id == devices[i].chip_id) {
453                         return g_strdup (devices[i].description);
454                 }
455         }
456         return g_strdup_printf ("0x%x", chip_id);
457 }
458
459 static gchar *
460 dev_format_mem_size (gsize flash_size)
461 {
462         return g_strdup_printf ("%u kB", flash_size / 1024);
463 }
464
465
466 static void
467 stlink_gui_set_connected (STlinkGUI *gui)
468 {
469         gchar        *tmp_str;
470         GtkListStore *store;
471         GtkTreeIter   iter;
472
473         gtk_statusbar_push (gui->statusbar,
474                             gtk_statusbar_get_context_id (gui->statusbar, "conn"),
475                             "Connected");
476
477         gtk_widget_set_sensitive (GTK_WIDGET (gui->device_frame), TRUE);
478         gtk_widget_set_sensitive (GTK_WIDGET (gui->devmem_box), TRUE);
479         gtk_widget_set_sensitive (GTK_WIDGET (gui->connect_button), FALSE);
480
481         if (gui->filename) {
482                 gtk_widget_set_sensitive (GTK_WIDGET (gui->flash_button), TRUE);
483         }
484
485         tmp_str = dev_format_chip_id (gui->sl->chip_id);
486         gtk_label_set_text (gui->chip_id_label, tmp_str);
487         g_free (tmp_str);
488
489         tmp_str = g_strdup_printf ("0x%x", gui->sl->core_id);
490         gtk_label_set_text (gui->core_id_label, tmp_str);
491         g_free (tmp_str);
492
493         tmp_str = dev_format_mem_size (gui->sl->flash_size);
494         gtk_label_set_text (gui->flash_size_label, tmp_str);
495         g_free (tmp_str);
496
497         tmp_str = dev_format_mem_size (gui->sl->sram_size);
498         gtk_label_set_text (gui->ram_size_label, tmp_str);
499         g_free (tmp_str);
500
501         tmp_str = g_strdup_printf ("0x%08X", gui->sl->flash_base);
502         gtk_entry_set_text (gui->devmem_jmp_entry, tmp_str);
503         gtk_editable_set_editable (GTK_EDITABLE (gui->devmem_jmp_entry), TRUE);
504         g_free (tmp_str);
505
506         store = GTK_LIST_STORE (gtk_tree_view_get_model (gui->devmem_treeview));
507         if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter)) {
508                 gtk_list_store_clear (store);
509         }
510
511         stlink_gui_set_sensitivity (gui, FALSE);
512         gtk_notebook_set_current_page (gui->notebook, PAGE_DEVMEM);
513         gtk_widget_show (GTK_WIDGET (gui->progress.bar));
514         gtk_progress_bar_set_text (gui->progress.bar, "Reading memory");
515
516         g_thread_new ("devmem", (GThreadFunc) stlink_gui_populate_devmem_view, gui);
517 }
518
519 static void
520 connect_button_cb (GtkWidget *widget, gpointer data)
521 {
522         STlinkGUI *gui;
523         gint       i;
524
525         gui = STLINK_GUI (data);
526
527         if (gui->sl != NULL)
528                 return;
529
530         /* try version 1 then version 2 */
531         gui->sl = stlink_v1_open(0);
532         if (gui->sl == NULL) {
533             gui->sl = stlink_open_usb(0);
534         }
535         if (gui->sl == NULL) {
536                 stlink_gui_set_info_error_message (gui, "Failed to connect to STLink.");                return;
537         }
538
539         /* code below taken from flash/main.c, refactoring might be in order */
540         if (stlink_current_mode(gui->sl) == STLINK_DEV_DFU_MODE)
541                 stlink_exit_dfu_mode(gui->sl);
542
543         if (stlink_current_mode(gui->sl) != STLINK_DEV_DEBUG_MODE)
544                 stlink_enter_swd_mode(gui->sl);
545
546         /* Disable DMA - Set All DMA CCR Registers to zero. - AKS 1/7/2013 */
547         if (gui->sl->chip_id == STM32_CHIPID_F4) {
548                 memset(gui->sl->q_buf, 0, 4);
549                 for (i = 0; i < 8; i++) {
550                         stlink_write_mem32(gui->sl, 0x40026000 + 0x10 + 0x18 * i, 4);
551                         stlink_write_mem32(gui->sl, 0x40026400 + 0x10 + 0x18 * i, 4);
552                         stlink_write_mem32(gui->sl, 0x40026000 + 0x24 + 0x18 * i, 4);
553                         stlink_write_mem32(gui->sl, 0x40026400 + 0x24 + 0x18 * i, 4);
554                 }
555         }
556         stlink_gui_set_connected (gui);
557 }
558
559 static void stlink_gui_set_disconnected (STlinkGUI *gui)
560 {
561         gtk_statusbar_push (gui->statusbar,
562                             gtk_statusbar_get_context_id (gui->statusbar, "conn"),
563                             "Disconnected");
564
565         gtk_widget_set_sensitive (GTK_WIDGET (gui->device_frame), FALSE);
566         gtk_widget_set_sensitive (GTK_WIDGET (gui->flash_button), FALSE);
567         gtk_widget_set_sensitive (GTK_WIDGET (gui->disconnect_button), FALSE);
568         gtk_widget_set_sensitive (GTK_WIDGET (gui->connect_button), TRUE);
569 }
570
571 static void
572 disconnect_button_cb (GtkWidget *widget, gpointer data)
573 {
574         STlinkGUI *gui;
575
576         gui = STLINK_GUI (data);
577
578         if (gui->sl != NULL) {
579                 stlink_exit_debug_mode(gui->sl);
580                 stlink_close(gui->sl);
581                 gui->sl = NULL;
582         }
583         stlink_gui_set_disconnected (gui);
584 }
585
586
587 static void
588 stlink_gui_open_file (STlinkGUI *gui)
589 {
590         GtkWidget    *dialog;
591         GtkListStore *store;
592         GtkTreeIter   iter;
593
594         dialog = gtk_file_chooser_dialog_new ("Open file",
595                                               gui->window,
596                                               GTK_FILE_CHOOSER_ACTION_OPEN,
597                                               GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
598                                               GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
599                                               NULL);
600
601         if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
602                 gui->filename =
603                         gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
604
605                 store = GTK_LIST_STORE (gtk_tree_view_get_model (gui->filemem_treeview));
606                 if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter)) {
607                         gtk_list_store_clear (store);
608                 }
609
610                 stlink_gui_set_sensitivity (gui, FALSE);
611                 gtk_notebook_set_current_page (gui->notebook, PAGE_FILEMEM);
612                 gtk_widget_show (GTK_WIDGET (gui->progress.bar));
613                 gtk_progress_bar_set_text (gui->progress.bar, "Reading file");
614                 g_thread_new ("file", (GThreadFunc) stlink_gui_populate_filemem_view, gui);
615         }
616         gtk_widget_destroy (dialog);
617 }
618
619 static void
620 open_button_cb (GtkWidget *widget, gpointer data)
621 {
622         STlinkGUI    *gui;
623
624         gui = STLINK_GUI (data);
625
626         stlink_gui_open_file (gui);
627 }
628
629 static gboolean
630 stlink_gui_write_flash_update (STlinkGUI *gui)
631 {
632         stlink_gui_set_sensitivity (gui, TRUE);
633         gui->progress.activity_mode = FALSE;
634         gtk_widget_hide (GTK_WIDGET (gui->progress.bar));
635
636         return FALSE;
637 }
638
639 static void
640 stlink_gui_write_flash (STlinkGUI *gui)
641 {
642         g_return_if_fail (gui->sl != NULL);
643         g_return_if_fail (gui->filename != NULL);
644
645         if (stlink_fwrite_flash(gui->sl, gui->filename, gui->sl->flash_base) < 0) {
646                 stlink_gui_set_info_error_message (gui, "Failed to write to flash");
647         }
648
649         g_idle_add ((GSourceFunc) stlink_gui_write_flash_update, gui);
650 }
651
652 static void
653 flash_button_cb (GtkWidget *widget, gpointer data)
654 {
655         STlinkGUI *gui;
656         gchar     *tmp_str;
657         guint32    address;
658         gint       result;
659         GError    *err = NULL;
660
661         gui = STLINK_GUI (data);
662         g_return_if_fail (gui->sl != NULL);
663
664         if (!g_strcmp0 (gtk_entry_get_text (gui->flash_dialog_entry), "")) {
665                 tmp_str = g_strdup_printf ("0x%08X", gui->sl->flash_base);
666                 gtk_entry_set_text (gui->flash_dialog_entry, tmp_str);
667                 g_free (tmp_str);
668         }
669
670         result = gtk_dialog_run (gui->flash_dialog);
671         if (result == GTK_RESPONSE_OK) {
672                 address = hexstr_to_guint32 (gtk_entry_get_text (gui->flash_dialog_entry),
673                                              &err);
674                 if (err) {
675                         stlink_gui_set_info_error_message (gui, err->message);
676                 } else {
677                         if (address > gui->sl->flash_base + gui->sl->flash_size ||
678                             address < gui->sl->flash_base) {
679                                 stlink_gui_set_info_error_message (gui, "Invalid address");
680                         }
681                         else if (address + gui->file_mem.size >
682                                  gui->sl->flash_base + gui->sl->flash_size) {
683                                 stlink_gui_set_info_error_message (gui, "Binary overwrites flash");
684                         } else {
685                                 stlink_gui_set_sensitivity (gui, FALSE);
686                                 gtk_progress_bar_set_text (gui->progress.bar,
687                                                            "Writing to flash");
688                                 gui->progress.activity_mode = TRUE;
689                                 gtk_widget_show (GTK_WIDGET (gui->progress.bar));
690                                 g_thread_new ("flash",
691                                               (GThreadFunc) stlink_gui_write_flash, gui);
692                         }
693                 }
694         }
695 }
696
697 static gboolean
698 progress_pulse_timeout (STlinkGUI *gui) {
699         if (gui->progress.activity_mode) {
700                 gtk_progress_bar_pulse (gui->progress.bar);
701         } else {
702                 gtk_progress_bar_set_fraction (gui->progress.bar, gui->progress.fraction);
703         }
704         return TRUE;
705 }
706
707 static void
708 notebook_switch_page_cb (GtkNotebook *notebook,
709                          GtkWidget   *widget,
710                          guint        page_num,
711                          gpointer     data)
712 {
713         STlinkGUI *gui;
714
715         gui = STLINK_GUI (data);
716
717         if (page_num == 1) {
718                 if (gui->filename == NULL) {
719                         stlink_gui_open_file (gui);
720                 }
721         }
722 }
723
724 static void
725 dnd_received_cb (GtkWidget *widget,
726                  GdkDragContext *context,
727                  gint x,
728                  gint y,
729                  GtkSelectionData *selection_data,
730                  guint target_type,
731                  guint time,
732                  gpointer data)
733 {
734         GFile        *file_uri;
735         gchar       **file_list;
736         const guchar *file_data;
737         STlinkGUI    *gui = STLINK_GUI (data);
738         GtkListStore *store;
739         GtkTreeIter   iter;
740
741         if (selection_data != NULL &&
742             gtk_selection_data_get_length (selection_data) > 0) {
743                 switch (target_type) {
744                 case TARGET_FILENAME:
745
746                         if (gui->filename) {
747                                 g_free (gui->filename);
748                         }
749
750                         file_data = gtk_selection_data_get_data (selection_data);
751                         file_list = g_strsplit ((gchar *)file_data, "\r\n", 0);
752
753                         file_uri = g_file_new_for_uri (file_list[0]);
754                         gui->filename = g_file_get_path (file_uri);
755
756                         g_strfreev (file_list);
757                         g_object_unref (file_uri);
758
759
760                         store = GTK_LIST_STORE (gtk_tree_view_get_model (gui->devmem_treeview));
761                         if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter)) {
762                                 gtk_list_store_clear (store);
763                         }
764
765                         stlink_gui_set_sensitivity (gui, FALSE);
766                         gtk_notebook_set_current_page (gui->notebook, PAGE_FILEMEM);
767                         gtk_widget_show (GTK_WIDGET (gui->progress.bar));
768                         gtk_progress_bar_set_text (gui->progress.bar, "Reading file");
769                         g_thread_new ("file", (GThreadFunc) stlink_gui_populate_filemem_view, gui);
770                         break;
771                 }
772         }
773         gtk_drag_finish (context,
774                          TRUE,
775                          gdk_drag_context_get_suggested_action (context) == GDK_ACTION_MOVE,
776                          time);
777 }
778
779 void
780 stlink_gui_init_dnd (STlinkGUI *gui)
781 {
782         GtkTargetEntry target_list[] = {
783                 { "text/uri-list", 0, TARGET_FILENAME },
784         };
785
786         gtk_drag_dest_set (GTK_WIDGET (gui->window),
787                            GTK_DEST_DEFAULT_ALL,
788                            target_list,
789                            G_N_ELEMENTS (target_list),
790                            GDK_ACTION_COPY);
791
792         g_signal_connect (gui->window, "drag-data-received",
793                           G_CALLBACK (dnd_received_cb), gui);
794 }
795
796 static void
797 stlink_gui_build_ui (STlinkGUI *gui) {
798         GtkBuilder   *builder;
799         GtkListStore *devmem_store;
800         GtkListStore *filemem_store;
801         gchar *ui_file = STLINK_UI_DIR "/stlink-gui.ui";
802
803         if (!g_file_test (ui_file, G_FILE_TEST_EXISTS)) {
804                 ui_file = "stlink-gui.ui";
805         }
806         builder = gtk_builder_new ();
807         if (!gtk_builder_add_from_file (builder, ui_file, NULL)) {
808                 g_printerr ("Failed to load UI file: %s\n", ui_file);
809                 exit (1);
810         }
811
812         gui->window = GTK_WINDOW (gtk_builder_get_object (builder, "window"));
813         g_signal_connect (G_OBJECT (gui->window), "destroy",
814                           G_CALLBACK (gtk_main_quit), NULL);
815
816         /* set up toolutton clicked callbacks */
817         gui->open_button =
818                 GTK_TOOL_BUTTON (gtk_builder_get_object (builder, "open_button"));
819         g_signal_connect (G_OBJECT (gui->open_button), "clicked",
820                           G_CALLBACK (open_button_cb), gui);
821
822         gui->connect_button =
823                 GTK_TOOL_BUTTON (gtk_builder_get_object (builder, "connect_button"));
824         g_signal_connect (G_OBJECT (gui->connect_button), "clicked",
825                           G_CALLBACK (connect_button_cb), gui);
826
827         gui->disconnect_button =
828                 GTK_TOOL_BUTTON (gtk_builder_get_object (builder, "disconnect_button"));
829         g_signal_connect (G_OBJECT (gui->disconnect_button), "clicked",
830                           G_CALLBACK (disconnect_button_cb), gui);
831
832         gui->flash_button =
833                 GTK_TOOL_BUTTON (gtk_builder_get_object (builder, "flash_button"));
834         g_signal_connect (G_OBJECT (gui->flash_button), "clicked",
835                           G_CALLBACK (flash_button_cb), gui);
836
837         gui->devmem_treeview =
838                 GTK_TREE_VIEW (gtk_builder_get_object (builder, "devmem_treeview"));
839         gtk_tree_view_set_rules_hint (gui->devmem_treeview, TRUE);
840         mem_view_init_headers (gui->devmem_treeview);
841         devmem_store = gtk_list_store_new (5,
842                                            G_TYPE_STRING,
843                                            G_TYPE_STRING,
844                                            G_TYPE_STRING,
845                                            G_TYPE_STRING,
846                                            G_TYPE_STRING);
847         gtk_tree_view_set_model (gui->devmem_treeview, GTK_TREE_MODEL (devmem_store));
848         g_object_unref (devmem_store);
849
850         gui->filemem_treeview =
851                 GTK_TREE_VIEW (gtk_builder_get_object (builder, "filemem_treeview"));
852         gtk_tree_view_set_rules_hint (gui->filemem_treeview, TRUE);
853         mem_view_init_headers (gui->filemem_treeview);
854         filemem_store = gtk_list_store_new (5,
855                                            G_TYPE_STRING,
856                                            G_TYPE_STRING,
857                                            G_TYPE_STRING,
858                                            G_TYPE_STRING,
859                                            G_TYPE_STRING);
860         gtk_tree_view_set_model (gui->filemem_treeview, GTK_TREE_MODEL (filemem_store));
861         g_object_unref (filemem_store);
862
863         gui->core_id_label =
864                 GTK_LABEL (gtk_builder_get_object (builder, "core_id_value"));
865
866         gui->chip_id_label =
867                 GTK_LABEL (gtk_builder_get_object (builder, "chip_id_value"));
868
869         gui->flash_size_label =
870                 GTK_LABEL (gtk_builder_get_object (builder, "flash_size_value"));
871
872         gui->ram_size_label =
873                 GTK_LABEL (gtk_builder_get_object (builder, "ram_size_value"));
874
875         gui->device_frame =
876                 GTK_FRAME (gtk_builder_get_object (builder, "device_frame"));
877
878         gui->notebook =
879                 GTK_NOTEBOOK (gtk_builder_get_object (builder, "mem_notebook"));
880         g_signal_connect (gui->notebook, "switch-page",
881                           G_CALLBACK (notebook_switch_page_cb), gui);
882
883         gui->devmem_box =
884                 GTK_BOX (gtk_builder_get_object (builder, "devmem_box"));
885
886         gui->filemem_box =
887                 GTK_BOX (gtk_builder_get_object (builder, "filemem_box"));
888
889         gui->devmem_jmp_entry =
890                 GTK_ENTRY (gtk_builder_get_object (builder, "devmem_jmp_entry"));
891         g_signal_connect (gui->devmem_jmp_entry, "activate",
892                           G_CALLBACK (devmem_jmp_cb), gui);
893
894         gui->filemem_jmp_entry =
895                 GTK_ENTRY (gtk_builder_get_object (builder, "filemem_jmp_entry"));
896         g_signal_connect (gui->filemem_jmp_entry, "activate",
897                           G_CALLBACK (filemem_jmp_cb), gui);
898         gtk_editable_set_editable (GTK_EDITABLE (gui->filemem_jmp_entry), TRUE);
899
900         gui->progress.bar =
901                 GTK_PROGRESS_BAR (gtk_builder_get_object (builder, "progressbar"));
902         gtk_progress_bar_set_show_text (gui->progress.bar, TRUE);
903         gui->progress.timer = g_timeout_add (100,
904                                              (GSourceFunc) progress_pulse_timeout,
905                                              gui);
906
907         gui->statusbar =
908                 GTK_STATUSBAR (gtk_builder_get_object (builder, "statusbar"));
909
910         gui->infobar =
911                 GTK_INFO_BAR (gtk_builder_get_object (builder, "infobar"));
912         gtk_info_bar_add_button (gui->infobar, GTK_STOCK_OK, GTK_RESPONSE_OK);
913         gui->infolabel = GTK_LABEL (gtk_label_new (""));
914         gtk_container_add (GTK_CONTAINER (gtk_info_bar_get_content_area (gui->infobar)),
915                            GTK_WIDGET (gui->infolabel));
916         g_signal_connect (gui->infobar, "response", G_CALLBACK (gtk_widget_hide), NULL);
917
918         /* flash dialog */
919         gui->flash_dialog =
920                 GTK_DIALOG (gtk_builder_get_object (builder, "flash_dialog"));
921         g_signal_connect_swapped (gui->flash_dialog, "response",
922                                   G_CALLBACK (gtk_widget_hide), gui->flash_dialog);
923
924         gui->flash_dialog_ok =
925                 GTK_BUTTON (gtk_builder_get_object (builder, "flash_dialog_ok_button"));
926
927         gui->flash_dialog_cancel =
928                 GTK_BUTTON (gtk_builder_get_object (builder, "flash_dialog_cancel_button"));
929
930         gui->flash_dialog_entry =
931                 GTK_ENTRY (gtk_builder_get_object (builder, "flash_dialog_entry"));
932
933         /* make it so */
934         gtk_widget_show_all (GTK_WIDGET (gui->window));
935         gtk_widget_hide (GTK_WIDGET (gui->infobar));
936         gtk_widget_hide (GTK_WIDGET (gui->progress.bar));
937
938         stlink_gui_set_disconnected (gui);
939 }
940
941 int
942 main (int argc, char **argv)
943 {
944         STlinkGUI *gui;
945
946         gtk_init (&argc, &argv);
947
948         gui = g_object_new (STLINK_TYPE_GUI, NULL);
949         stlink_gui_build_ui (gui);
950         stlink_gui_init_dnd (gui);
951
952         gtk_main ();
953
954         return 0;
955 }