using g_timeout_add and updating GUI

Viewed 128

I am just getting back into programming and need some help. I am totally new to GTK3 and dusting off the coding cobwebs.

The program I am writing basically reads the serial port for GPS GPGGA data strings that come in every sec, parses the data and calculates the distance between strings and triggers an output when a user enter distance is reached and repeats. I am writing in C on a raspberry PI, used Glade to make interface and Code::Block IDE.

Right now, I have the time g_timeout_add working, Kinda. If I remove the gtk_label_set_text from the calc_display function it works and runs that function every 500mS (had a LED on the GPIO to confirm that - code removed to make reading simple). But the GUI is unresponsive and doesn't update.

If I have the gtk_label_set_text and the gtk_main_iteration() in the function, it runs once and freezes up (updates display with GPS but not blinking LED). What am I screwing up here, I have read through the GTK reference but nothing jumps out, I suspect it's a newbie dumb error. Any thoughts?

Here is the code:

#include <gtk/gtk.h>
#include <stdio.h>
#include <stdlib.h>
#include <wiringPi.h>
#include "serial_gps.h"
#include "pin_names.h"
#include "gps_distance.h"

typedef struct
{
    GtkWidget *w_shot_spacing_ent;      // generic pointer for entered text
    GtkWidget *w_num_shots_val;
    GtkWidget *w_gps_q_val;
    GtkWidget *w_total_dist_val;
    GtkWidget *w_avg_space_val;
    GtkWidget *w_lat_val;
    GtkWidget *w_long_val;
    GtkWidget *w_pause_but;
    GtkWidget *w_start_but;
    GtkWidget *w_serial_in;
} app_widgets;

int start =0;           // used in the "Start button clicked" function
int port_fd = 0;    // file descriptor for the serial port
float spacing = 0;      // global for the shor spacing value
gint input_type = 1;    // for picking USB or DB9 serial
guint event_id =  0;
char port_data[100];   // big buffer for the port data
int toggle = FALSE;

void flash_leds(void);
void ini_data(void);
void calc_display(app_widgets *app_wdgts);
void calc_display_f(void);

int main (int argc, char *argv[])
{

    GtkBuilder *builder;
    GtkWidget *window;

    // instantiate structure, allocating memory for it
    app_widgets *widgets = g_slice_new(app_widgets);

    wiringPiSetup();  // initialise the wiring Pi library
    flash_leds();
    ini_data();     // ini the data structure
    gtk_init(&argc, &argv);

    builder = gtk_builder_new_from_file ("glade/ShotMaster.glade");

    window = GTK_WIDGET(gtk_builder_get_object (builder, "window_main"));
     // get pointers to label widgets
    widgets->w_shot_spacing_ent= GTK_WIDGET(gtk_builder_get_object(builder, "shot_spacing_ent"));
    widgets->w_num_shots_val= GTK_WIDGET(gtk_builder_get_object(builder, "shot_num_val"));
    widgets->w_total_dist_val= GTK_WIDGET(gtk_builder_get_object(builder, "total_dist_val"));
    widgets->w_avg_space_val= GTK_WIDGET(gtk_builder_get_object(builder, "avg_space_val"));
    widgets->w_gps_q_val= GTK_WIDGET(gtk_builder_get_object(builder, "gps_q_val"));
    widgets->w_lat_val= GTK_WIDGET(gtk_builder_get_object(builder, "lat_val"));
    widgets->w_long_val= GTK_WIDGET(gtk_builder_get_object(builder, "long_val"));
    widgets->w_pause_but= GTK_WIDGET(gtk_builder_get_object(builder, "pause_but"));
    widgets->w_start_but= GTK_WIDGET(gtk_builder_get_object(builder, "start_but"));
    widgets->w_serial_in= GTK_WIDGET(gtk_builder_get_object(builder, "serial_in"));

    gtk_builder_connect_signals(builder,widgets);
    g_object_unref(builder);
    gtk_widget_show(window);
    gtk_main();
    g_slice_free(app_widgets, widgets);  // free up memory, usually done by OS, but good pratice
    return 0;
}


void on_reset_but_clicked (GtkButton *button, app_widgets *app_wdgts)
{
    // just some test code
    gtk_label_set_text(GTK_LABEL (app_wdgts->w_num_shots_val), "3");
    gtk_label_set_text(GTK_LABEL (app_wdgts->w_total_dist_val), "2");
    gtk_label_set_text(GTK_LABEL (app_wdgts->w_avg_space_val), "1");

}

void calc_display(app_widgets *app_wdgts)
{
    char    buffer[20];
    int     num_buf;
    double   F_buff;

    shot_trigger();   // this code works, has no GTK functions in it  works with the "data" struct for collecting data
    GString *temp = g_string_new("0000");
    num_buf = data.num_shots;
    F_buff = data.latitude;
    F_buff = data.longitude;


    sprintf(buffer, "%i", data.num_shots);
    gtk_label_set_text(GTK_LABEL (app_wdgts->w_num_shots_val),buffer);

    sprintf(buffer, "%i", data.gps_q);
    gtk_label_set_text(GTK_LABEL (app_wdgts->w_gps_q_val),buffer );

    sprintf(buffer, "%f", data.total_dist);
    gtk_label_set_text(GTK_LABEL (app_wdgts->w_total_dist_val),buffer );

    sprintf(buffer, "%f", data.avg_space);
    gtk_label_set_text(GTK_LABEL (app_wdgts->w_avg_space_val),buffer );

    sprintf(buffer, "%f", data.latitude);
    gtk_label_set_text(GTK_LABEL (app_wdgts->w_lat_val),buffer );

    sprintf(buffer, "%f", data.longitude);
    gtk_label_set_text(GTK_LABEL (app_wdgts->w_long_val),buffer );



    }

    gtk_main_iteration();   // update the display
}

void on_start_but_clicked(GtkButton *button, app_widgets *app_wdgts)  // Main function that starts serial data grabbing/ calculations
{
    int     port_err = 0;

    data.spacing = gtk_spin_button_get_value(GTK_SPIN_BUTTON(app_wdgts->w_shot_spacing_ent));

    input_type = gtk_combo_box_get_active(GTK_COMBO_BOX(app_wdgts->w_serial_in)); // returns a 0 for USB and 1 for DBc
    port_fd = start_serial(input_type, 9600);   //open the port
    flush_port(port_fd);  // start with a clean buffer

    port_err= get_serial_string(port_data,port_fd);  // get a line of GPS data
    data.run=TRUE;
    if (port_err != 0)
        {
        // error found,  -1 = buffer overflow
        }

    if(start == 0)     // initial condition
    {
        event_id = g_timeout_add(500,(GSourceFunc) calc_display,app_wdgts);
        start = 1;
        gtk_button_set_label(button, "Change");  //once started you can only change things..
    }
    else   // after program has Started,  button in "Change" mode
    {
        spacing = gtk_spin_button_get_value(GTK_SPIN_BUTTON(app_wdgts->w_shot_spacing_ent));  // get new value

    }
}

void on_pause_but_clicked (GtkButton *button, app_widgets *app_wdgts)
{
        if(data.run == TRUE)
        {
            gtk_button_set_label(button, "RUN");// change button label
            data.run = FALSE;
        }
        else
        {
            data.run = TRUE;
            gtk_button_set_label(button, "PAUSE");// change button label
        }
}
void on_quit_but_clicked(void)
{
    stop_serial( port_fd);    // close the serial port
    gtk_main_quit();
}
void on_window_main_destroy(void)
{
    stop_serial( port_fd);  // close the serial port
    gtk_main_quit();
}


void flash_leds(void)
{
    pinMode(test_LED,OUTPUT);  // set pin(s) to outputs
    pinMode(trig_LED,OUTPUT);  // set pin(s) to outputs
    pinMode(gps_LED,OUTPUT);  // set pin(s) to outputs
    pinMode(error_LED,OUTPUT);  // set pin(s) to outputs
    digitalWrite(test_LED, HIGH); // high is LED off
    digitalWrite(trig_LED, HIGH); // high is LED off
    digitalWrite(gps_LED, HIGH); // high is LED off
    digitalWrite(error_LED, HIGH); // high is LED off

    digitalWrite(test_LED, LOW);
    digitalWrite(trig_LED, LOW);
    digitalWrite(gps_LED, LOW);
    digitalWrite(error_LED, LOW);
    delay(1000);
    digitalWrite(test_LED, HIGH); // high is LED off
    digitalWrite(trig_LED, HIGH); // high is LED off
    digitalWrite(gps_LED, HIGH); // high is LED off
    digitalWrite(error_LED, HIGH); // high is LED off


}

void ini_data(void)
{
data.spacing = 0;
data.num_shots =0;
data.gps_q = 0;
data.total_dist = 0;
data.avg_space = 0;
data.latitude = 0;
data.longitude = 0;
data.run = FALSE;
}
1 Answers

OK, my implementation was correct (or correct enough it works). My mistake was in some timing conflicts between the timeout and reading from the serial port. It just took some public embarrassment to see that.... I originally wrote it in Python, but switched to C for faster calculations and held on to some assumptions....wedged head firmly up ass and there you go!

Related