Mike
Mike

Reputation: 55

gtk_main() alongside while(1) Raspberry Pi 3

I've just started my first project in C language on raspberry pi 3 and I want to create my first GUI app for touch panel. My goal is to run the while(1) loop which controls the raspberry I/O and the gtk_main function to open a simple window.

After calling gtk_main(), the rest of the code doesn't work. I know it's caused by the fact that gtk_main creates it's own loop. Is there any way to run these two loops simultaneously?

#include <stdio.h>    // Used for printf() statements
#include <wiringPi.h> // Include WiringPi library!
#include <gtk/gtk.h>

// Pin number declarations. We're using the Broadcom chip pin numbers.
const int pwmPin = 18; // PWM LED - Broadcom pin 18, P1 pin 12
const int ledPin = 23; // Regular LED - Broadcom pin 23, P1 pin 16
const int butPin = 21; // Active-low button - Broadcom pin 17, P1 pin 11    

const int pwmValue = 0; // Use this to set an LED brightness

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

    int add = 0;
    int sign = 1;
    // Setup stuff:
    wiringPiSetupGpio(); // Initialize wiringPi -- using Broadcom pin numbers

    pinMode(pwmPin, PWM_OUTPUT); // Set PWM LED as PWM output
    pinMode(ledPin, OUTPUT);     // Set regular LED as output
    pinMode(butPin, INPUT);      // Set button as INPUT
    pullUpDnControl(butPin, PUD_UP); // Enable pull-up resistor on button

    GtkWidget *window;

    gtk_init (&argc, &argv);

    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    gtk_widget_show (window);

    gtk_main ();

    // Loop (while(1)):
    while(1)
    {
        if (digitalRead(butPin)) // Button is released if this returns 1
        {
            pwmWrite(pwmPin, pwmValue+add); // PWM LED at bright setting
            digitalWrite(ledPin, LOW);     // Regular LED off
            add=add+(sign*50);
            if (add==1000) sign=-1;
            if (add==0) sign=1;
            delay(50);
        }
        else // If digitalRead returns 0, button is pressed
        {
            pwmWrite(pwmPin, 1024 - pwmValue); // PWM LED at dim setting
            // Do some blinking on the ledPin:
            digitalWrite(ledPin, HIGH); // Turn LED ON
            delay(75); // Wait 75ms
            digitalWrite(ledPin, LOW); // Turn LED OFF
            delay(75); // Wait 75ms again
        }
    }    

}

Upvotes: 1

Views: 379

Answers (3)

liberforce
liberforce

Reputation: 11454

Remove your while loop and use g_idle_add and/or g_timeout to trigger your callbacks. This defines when your code is called. Then in your callback, do your pin I/O control stuff. Just remember that using delay or any blocking function similar to sleep will freeze your UI for the same amount of time. You may avoid this by using g_idle_add or g_timeout to trigger for changing the state again.

Upvotes: 0

gtk_main is documented as:

Runs the main loop until gtk_main_quit() is called.

You can nest calls to gtk_main(). In that case gtk_main_quit() will make the innermost invocation of the main loop return.

So you need to have some callback explicitly invoking gtk_main_quit (and I guess you don't).

So the behavior is expected. You may want to handle the "delete-event" GTK signal on your window (by having your GTK signal handler for that event calling explicitly gtk_main_quit). You need to read much more, notably about the GTK event loop, and GObject's signals.

If you want to poll(2) and read(2) some device, you'll better do that inside the GTK event loop (e.g. by calling g_source_add_unix_fd or g_io_channel_unix_new, etc etc...).

You should spend several days reading more about Gtk, notably its Getting Started chapter.

Upvotes: 1

Mathieu
Mathieu

Reputation: 9659

I have two solution in mind to solve your problem:

  • You could create a timer which will call a function to deal with butPin value each 100ms,
  • You could use threads:

    void *start_gtk_thread(void *arg)
    {
        gtk_main();
        return NULL;
    }
    void *start_pin_thread(void *arg)
    {
        while(1)
        {
            if (digitalRead(butPin)) // Button is released if this returns 1
            {
                 ....
            }
            return NULL;
        }
    }
    

    And in your main function

    gtk_widget_show (window);
    
    /* threads id*/
    pthread_t tid[2];
    
    /* create threads */        
    pthread_create(&tid[0], NULL, start_gtk_thread, NULL);
    pthread_create(&tid[1], NULL, start_pin_thread, NULL);
    
    /* wait for threads (warning, they should never terminate) */ 
    pthread_join(id[0], NULL);
    pthread_join(id[1], NULL);
    

Upvotes: 0

Related Questions