the GPIO subsystem on the Raspberry allows to set pins for "interrupt" the created subsystem file becomes readable on any level change.
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; }