kopia lustrzana https://github.com/stlink-org/stlink
956 wiersze
28 KiB
C
956 wiersze
28 KiB
C
#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, 1);
|
|
if (gui->sl == NULL) {
|
|
gui->sl = stlink_open_usb(0, 1);
|
|
}
|
|
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;
|
|
}
|