diff --git a/gui_graph_tab.c b/gui_graph_tab.c index 43a2dc8..ab19a52 100644 --- a/gui_graph_tab.c +++ b/gui_graph_tab.c @@ -19,10 +19,9 @@ #include #include -#include - #include #include +#include #include #include "tdc_variable.h" @@ -57,7 +56,7 @@ struct xygraph { gfloat yarr[HISTORY]; GdkColor *color; - struct timeval base; + int last_index; }; static GdkColor * get_color(void) @@ -99,6 +98,7 @@ static void update_legend(void) tmp = g_string_new(""); g_list_foreach(graphlist, &update_legend_cb, tmp); + /* strip last \n */ tmp->str[tmp->len -1] = 0x00; gtk_label_set_markup(GTK_LABEL(legend), tmp->str); @@ -136,6 +136,10 @@ gint gui_graphtab_init(GtkNotebook *notebook) GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0); gtk_databox_set_vruler(GTK_DATABOX(box), GTK_RULER(ruler)); + GdkColor color = { .red = 0xC000, .green = 0xC000, .blue = 0xC000, }; + GtkDataboxGraph *grid = gtk_databox_grid_new(10, 10, &color, 1); + gtk_databox_graph_add(GTK_DATABOX(box), grid); + legend = gtk_label_new(NULL); gtk_table_attach(GTK_TABLE(table), legend, 1, 2, 3, 4, 0, 0, 10, 10); @@ -145,16 +149,6 @@ gint gui_graphtab_init(GtkNotebook *notebook) GtkWidget *button3 = gtk_button_new_with_label("Stopp"); gtk_table_attach(GTK_TABLE(table), button3, 3, 4, 3, 4, 0, 0, 10, 10); - struct tdc_var *var = tdcvar_create(1, 0, "test", 4); - gui_graphtab_add_var(var); - gui_graphtab_add_var(var); - gui_graphtab_add_var(var); - gui_graphtab_add_var(var); - gui_graphtab_add_var(var); - gui_graphtab_add_var(var); - gui_graphtab_add_var(var); - gui_graphtab_add_var(var); - GtkWidget *label = gtk_label_new(" Graph "); return gtk_notebook_append_page(GTK_NOTEBOOK(notebook), table, label); } @@ -170,18 +164,16 @@ int gui_graphtab_add_var(struct tdc_var *var) graph->var = var; graph->color = color; - var->privdata_graphtab = graph; - int i; for (i = 0; i < HISTORY; i++) { - graph->xarr[i] = i - HISTORY; - graph->yarr[i] = sin(((int)graph % 127) + i * 4 * M_PI / 1024); + graph->xarr[i] = i; + graph->yarr[i] = 0; } + var->privdata_graphtab = graph; graphlist = g_list_append(graphlist, graph); gtk_databox_graph_add(GTK_DATABOX(box), graph->graph); - gtk_databox_auto_rescale(GTK_DATABOX(box), 0.05); update_legend(); return 0; @@ -190,18 +182,91 @@ int gui_graphtab_add_var(struct tdc_var *var) void gui_graphtab_remove_var(struct tdc_var *var) { struct xygraph *graph = (struct xygraph *)var->privdata_graphtab; + var->privdata_graphtab = NULL; gtk_databox_graph_remove(GTK_DATABOX(box), graph->graph); - g_free(graph->graph); + free_color(graph->color); graphlist = g_list_remove(graphlist, graph); - graph->var->privdata_graphtab = NULL; + update_legend(); + g_free(graph); } +static int calc_index(struct timeval *base, struct timeval *now, int step) +{ + struct timeval diff; + diff.tv_sec = now->tv_sec - base->tv_sec; + diff.tv_usec = now->tv_usec - base->tv_usec; + + diff.tv_usec += diff.tv_sec * 1000000; + diff.tv_usec /= 1000; + + return diff.tv_usec / step; +} + +static void rescale_graphs(gboolean reset) +{ + static GtkDataboxValue min; + static GtkDataboxValue max; + + GtkDataboxValue tmp_min, tmp_max; + + if (gtk_databox_calculate_extrema(GTK_DATABOX(box), &tmp_min, &tmp_max) < 0) + return; + + float swap = tmp_min.y; + tmp_min.y = tmp_max.y; + tmp_max.y = swap; + + if (!reset) { + min.x = MIN(min.x, tmp_min.x); + min.y = MAX(min.y, tmp_min.y); + max.x = MAX(max.x, tmp_max.x); + max.y = MIN(max.y, tmp_max.y); + + } else { + min.x = tmp_min.x; + min.y = tmp_min.y; + max.x = tmp_max.x; + max.y = tmp_max.y; + } + + gtk_databox_set_canvas(GTK_DATABOX(box), min, max); +} + void gui_graphtab_update_var(struct tdc_var *var) { + static struct timeval base, update; + struct xygraph *graph = (struct xygraph *)var->privdata_graphtab; - // do some updates, i think + + struct timeval now; + gettimeofday(&now, NULL); + + int i = calc_index(&base, &now, 10); + if (i < 0 || i >= HISTORY) { + base.tv_sec = now.tv_sec; + base.tv_usec = now.tv_usec; + i = 0; + } + + float last_value = graph->yarr[graph->last_index]; + while (graph->last_index != i) { + graph->last_index++; + if (graph->last_index == HISTORY) + graph->last_index = 0; + + graph->yarr[graph->last_index] = last_value; + } + + graph->yarr[i] = tdcvar_get_double(var); + + if (calc_index(&update, &now, 100) != 0) { + update.tv_sec = now.tv_sec; + update.tv_usec = now.tv_usec; + + rescale_graphs(FALSE); + } } diff --git a/gui_variable_tab.c b/gui_variable_tab.c index 27c0db7..81d5a0f 100644 --- a/gui_variable_tab.c +++ b/gui_variable_tab.c @@ -22,6 +22,8 @@ #include "tdc_parser.h" #include "tdc_proto.h" +#include "gui_graph_tab.h" + enum { COL_ID = 0, /* UINT */ COL_GRAPH, /* BOOLEAN */ @@ -52,14 +54,23 @@ static void cell_graph_toggle(GtkCellRendererToggle *cell, COL_VALUE, &var, -1); - if (var->flags & TDC_GUI_GRAPH) + if (var->flags & TDC_GUI_GRAPH) { var->flags &= ~TDC_GUI_GRAPH; - else + + if (var->privdata_graphtab != NULL) + gui_graphtab_remove_var(var); + + } else { + if (var->privdata_graphtab == NULL) + /* bailout if no new graph allowed */ + if (gui_graphtab_add_var(var) < 0) + return; + var->flags |= TDC_GUI_GRAPH; + } // FIXME: assuming board 1 tdcstore_graph_refresh(1, -1); - printf("cell_graph_toggle(%d)\n", var->id); gtk_list_store_set(GTK_LIST_STORE(user_data), &it, COL_GRAPH, !toggle, diff --git a/tdc_parser.c b/tdc_parser.c index 8df1e5f..d444bd0 100644 --- a/tdc_parser.c +++ b/tdc_parser.c @@ -156,7 +156,7 @@ static int tdcparser_parse(void) tdcstore_create_board(address, pkt->name); tdcstore_refresh_values(address, 250); - tdcstore_graph_refresh(address, 50); + tdcstore_graph_refresh(address, 20); tdcparser_send_getvars(address); } break; diff --git a/tdc_variable.c b/tdc_variable.c index 4b42901..912ece6 100644 --- a/tdc_variable.c +++ b/tdc_variable.c @@ -232,6 +232,41 @@ int tdcvar_parse_value(struct tdc_var *var, char *data) return 0; } +double tdcvar_get_double(struct tdc_var *var) +{ + switch (var->flags & TDC_TYPEMASK) { + case TDC_UNSIGNED: + switch (var->flags & TDC_SIZEMASK) { + case 1: return var->data_uint8; + case 2: return var->data_uint16; + case 4: return var->data_uint32; + case 8: return var->data_uint64; + } + break; + + case TDC_SIGNED: + switch (var->flags & TDC_SIZEMASK) { + case 1: return (int8_t)var->data_uint8; + case 2: return (int16_t)var->data_uint16; + case 4: return (int32_t)var->data_uint32; + case 8: return (int64_t)var->data_uint64; + } + break; + case TDC_FP: + case TDC_FP | 0x100: + switch (var->flags & TDC_SIZEMASK) { + case sizeof(float): + return var->data_float; + + case sizeof(double): + return var->data_double; + } + break; + } + + return 0.0; +} + struct tdc_var * tdcvar_create(int id, uint32_t flags, char *name, int len) { struct tdc_var *var = g_malloc0(sizeof(struct tdc_var) + len + 1); diff --git a/tdc_variable.h b/tdc_variable.h index e739b5d..7087494 100644 --- a/tdc_variable.h +++ b/tdc_variable.h @@ -24,6 +24,7 @@ struct tdc_var { void tdcvar_get_value(struct tdc_var *var, char *buf, int size, int viewmode); void tdcvar_get_type(struct tdc_var *var, char *buf, int size); int tdcvar_parse_value(struct tdc_var *var, char *data); +double tdcvar_get_double(struct tdc_var *var); struct tdc_var * tdcvar_create(int id, uint32_t flags, char *name, int len); void tdcvar_update(struct tdc_var *var, uint8_t *data, int len);