1

I am just starting programming for Linux and right now I have a wish to trigger some event when the external button connected to Beaglebone is pressed. Here I have found a nice solution based on Glib and tried to implement it. But unfortunately the event is triggered only once at the beginning and then no matter how many times I press the button it doesn't react.

Here is the code taken exactly from the tutorial:

#include<iostream>
#include<unistd.h>
#include<fstream>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<glib-2.0/glib.h>

using namespace std;

static gboolean onButtonEvent( GIOChannel *channel, GIOCondition condition, gpointer user_data )
{
    GError *error = 0;
    gsize bytes_read = 0;
    const int buf_sz = 1024;
    gchar buf[buf_sz] = {};
    g_io_channel_seek_position( channel, 0, G_SEEK_SET, 0 );
    GIOStatus rc = g_io_channel_read_chars( channel,
                                            buf,buf_sz - 1,
                                            &bytes_read,
                                            &error );
    cerr << "rc:" << rc << "  data:" << buf << endl;
    return 1;
}

int main( int argc, char** argv )
{
    GMainLoop* loop = g_main_loop_new( 0, 0 );

    int fd = open( "/sys/class/gpio/gpio49/value", O_RDONLY | O_NONBLOCK );
    GIOChannel* channel = g_io_channel_unix_new(fd);
    GIOCondition cond = GIOCondition(G_IO_PRI);
    guint id = g_io_add_watch(channel, cond, onButtonEvent, 0);

    g_main_loop_run( loop );
}

When I have changed the GIOCondition to G_IO_IN the onButtonEvent runs all the time giving me the correct value of gpio, but infinitely, without a stop, because (as written here) g_io_add_watch in this case reads the file always when there is data to read. But I want to read the data only when the file was changed.

Is it really possible to make that with G_IO_PRI which invoke the event when "there is urgent data to read"? And when exactly this condition is satisfied? What can be my mistake?

Ulyana
  • 11
  • 2

2 Answers2

0

When you poll the GPIO state from a sysfs device, you'll end up with a solution consuming a lot of CPU time and operating slow.

A faster and more easy solution is using libpruio:

http://beagleboard.org/project/libpruio/

Check out the example "button":

http://users.freebasic-portal.de/tjf/Projekte/libpruio/doc/html/_cha_examples.html#SubSecExaButton

BR

TJF
  • 91
  • 1
  • 4
0

If you add a watch on a GIOChannel with the condition G_IO_PRI it will basically result in a poll() call with POLLPRI flag. In the documentation for the Linux GPIO Sysfs interface it says that:

If the pin can be configured as interrupt-generating interrupt and if it has been configured to generate interrupts (see the description of "edge"), you can poll(2) on that file and poll(2) will return whenever the interrupt was triggered. If you use poll(2), set the events POLLPRI and POLLERR. If you use select(2), set the file descriptor in exceptfds. After poll(2) returns, either lseek(2) to the beginning of the sysfs file and read the new value or close the file and re-open it to read the value.

That means that G_IO_PRI will listen to interrupts on the GPIO and that in turn means that you have to configure the pin to generate interrupts on "none", "rising", "falling", or "both" edges in 'sys/class/gpio/gpio/edge'. If that file doesn't exist it means that the GPIO does not support interrupt generation.

So in short; your code should work given that the GPIO support interrupt generation and that the correct edges are enabled.

evading
  • 3,032
  • 6
  • 37
  • 57