Updated 2018-09-20 13:04:36 by jdc

the GPIO subsystem on the Raspberry allows to set pins for "interrupt" the created subsystem file becomes readable on any level change.

Raspberry GPIO utility

Unfortunately I could not coerce tcl to ignore the eof condition. So I expanded the sample c programm to handle multiple pins set up for interrupt notice to be watched over and handed in to a tcl file input.

the helper will first iterate over all configured inputs and report their current state. then one line will be output for every event seen. <pin>:<state> which fits in nicely with the tcl event model.

Useage example ( here the gpio 23, 24 and 25 ) :
# config input:
proc Uevent fd {
        set line [gets $fd]
        puts stderr line:>>$line<<
        switch -- $line \
                  23:0 {
                        hands right
                } 23:1 {
                        hands right 0
                } 24:0 {
                        hands left
                } 24:1 {
                        hands left 0
                } 25:0 {
                        puts stderr Release
                } 25:1 {
                        set ::stop [ clock milliseconds ]
                        incr ::cont
                } default {
                }
}
set fd [ open "| ./gpioirq 23 24 25" RDONLY ]
fconfigure $fd -buffering none
fileevent $fd readable [list Uevent $fd]

Then create a fileevent readable for $fd.
fileevent $fd readable [list Uevent $fd]

./gpioirq.c slightly expanded from an example give on the gpio project page.
// adapted from an example.
// i2016 Uwe Klein Habertwedt

#include <stdio.h>
#include <poll.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>

#define GPIO_FN_MAXLEN  32
#define POLL_TIMEOUT    1000
#define RDBUF_LEN       5

int main(int argc, char **argv) {
        char fn[GPIO_FN_MAXLEN];
        int fd[argc],ret, arg;
        struct pollfd pfd[argc];
        char rdbuf[RDBUF_LEN];

        memset(rdbuf, 0x00, RDBUF_LEN);
        memset(fn, 0x00, GPIO_FN_MAXLEN);

        if(argc<2) {
                printf("Usage: %s <GPIO>\nGPIO must be exported to sysfs and have enabled edge detection\n", argv[0]);
                return 1;
        }
        for (arg=1;(arg<argc);arg++) {
                snprintf(fn, GPIO_FN_MAXLEN-1, \
                        "/sys/class/gpio/gpio%s/value", argv[arg]);
                fd[arg]=open(fn, O_RDONLY);
                if(fd[arg]<0) {
                        perror(fn);
                        return 2;
                }
                pfd[arg].fd=fd[arg];
                pfd[arg].events=POLLPRI;

                ret=read(fd[arg], rdbuf, RDBUF_LEN-1);
                        if(ret<0) {
                        perror("read()");
                        return 4;
                        return 4;
                        }
                printf("%s:%s", argv[arg],rdbuf);
        }
        fflush(stdout);
        while(1) {
                memset(rdbuf, 0x00, RDBUF_LEN);
                for (arg=1; arg<argc;arg++) {
                        lseek(fd[arg], 0, SEEK_SET);
                }
                ret=poll(&pfd[1], argc-1, POLL_TIMEOUT);
                if(ret<0) {
                        perror("poll()");
                        close(fd);
                        return 3;
                }
                if(ret==0) {
                        // printf("timeout\n");
                        continue;
                }
                for (arg=1; arg<argc;arg++) {
                        if (pfd[arg].revents) {
                                ret=read(fd[arg], rdbuf, RDBUF_LEN-1);
                                printf("%s:%s", argv[arg], rdbuf);
                                fflush(stdout);
                        }
                }
                if(ret<0) {
                        perror("read()");
                        return 4;
                }
        }
        close(fd);
        return 0;
}