int add_edge_detect(unsigned int gpio, unsigned int edge, int bouncetime) // return values: // 0 - Success // 1 - Edge detection already added // 2 - Other error { pthread_t threads; struct epoll_event ev; long t = 0; struct gpios *g; int i = -1; i = gpio_event_added(gpio); if (i == 0) { // event not already added if ((g = new_gpio(gpio)) == NULL) return 2; gpio_set_edge(gpio, edge); g->edge = edge; g->bouncetime = bouncetime; } else if (i == edge) { // get existing event g = get_gpio(gpio); if ((bouncetime != -666 && g->bouncetime != bouncetime) || // different event bouncetime used (g->thread_added)) // event already added return 1; } else { return 1; } // create epfd_thread if not already open if ((epfd_thread == -1) && ((epfd_thread = epoll_create(1)) == -1)) return 2; // add to epoll fd ev.events = EPOLLIN | EPOLLET | EPOLLPRI; ev.data.fd = g->value_fd; if (epoll_ctl(epfd_thread, EPOLL_CTL_ADD, g->value_fd, &ev) == -1) { remove_edge_detect(gpio); return 2; } g->thread_added = 1; // start poll thread if it is not already running if (!thread_running) { if (pthread_create(&threads, NULL, poll_thread, (void *)t) != 0) { remove_edge_detect(gpio); return 2; } } return 0; }
int add_edge_detect(unsigned int gpio, unsigned int edge) // return values: // 0 - Success // 1 - Edge detection already added // 2 - Other error { int fd; pthread_t threads; struct epoll_event ev; long t = 0; // check to see if this gpio has been added already if (gpio_event_added(gpio) != 0) return 1; // export /sys/class/gpio interface gpio_export(gpio); gpio_set_direction(gpio, 1); // 1=input gpio_set_edge(gpio, edge); if ((fd = open_value_file(gpio)) == -1) return 2; add_fd_list(gpio,fd); // create epfd if not already open if ((epfd == -1) && ((epfd = epoll_create(1)) == -1)) return 2; // add to epoll fd ev.events = EPOLLIN | EPOLLET | EPOLLPRI; ev.data.fd = fd; if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) == -1) return 2; // start poll thread if it is not already running if (!thread_running) { if (pthread_create(&threads, NULL, poll_thread, (void *)t) != 0) return 2; } return 0; }
int add_edge_detect(unsigned int gpio, unsigned int edge, unsigned int bouncetime) // return values: // 0 - Success // 1 - Edge detection already added // 2 - Other error { pthread_t threads; struct epoll_event ev; long t = 0; struct gpios *g; // check to see if this gpio has been added already if (gpio_event_added(gpio) != 0) return 1; // create epfd if not already open if ((epfd == -1) && ((epfd = epoll_create(1)) == -1)) return 2; if ((g = new_gpio(gpio)) == NULL) return 2; gpio_set_edge(gpio, edge); g->bouncetime = bouncetime; // add to epoll fd ev.events = EPOLLIN | EPOLLET | EPOLLPRI; ev.data.fd = g->value_fd; if (epoll_ctl(epfd, EPOLL_CTL_ADD, g->value_fd, &ev) == -1) { remove_edge_detect(gpio); return 2; } // start poll thread if it is not already running if (!thread_running) { if (pthread_create(&threads, NULL, poll_thread, (void *)t) != 0) { remove_edge_detect(gpio); return 2; } } return 0; }
// python function add_event_callback(gpio, callback, bouncetime=0) static PyObject *py_add_event_callback(PyObject *self, PyObject *args, PyObject *kwargs) { unsigned int gpio; int channel; unsigned int bouncetime = 0; PyObject *cb_func; char *kwlist[] = {"gpio", "callback", "bouncetime", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "iO|i", kwlist, &channel, &cb_func, &bouncetime)) return NULL; if (!PyCallable_Check(cb_func)) { PyErr_SetString(PyExc_TypeError, "Parameter must be callable"); return NULL; } if (get_gpio_number(channel, &gpio)) return NULL; // check channel is set up as an input if (gpio_direction[gpio] != INPUT) { PyErr_SetString(WrongDirectionException, "You must setup() the GPIO channel as an input first"); return NULL; } if (!gpio_event_added(gpio)) { PyErr_SetString(AddEventException, "Add event detection using add_event_detect first before adding a callback"); return NULL; } if (add_py_callback(gpio, bouncetime, cb_func) != 0) return NULL; Py_INCREF(Py_None); return Py_None; }
// python function add_event_callback(gpio, callback) static PyObject *py_add_event_callback(PyObject *self, PyObject *args, PyObject *kwargs) { unsigned int gpio; unsigned int sys_gpio; int channel; PyObject *cb_func; char *kwlist[] = {"gpio", "callback", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "iO|i", kwlist, &channel, &cb_func)) return NULL; if (!PyCallable_Check(cb_func)) { PyErr_SetString(PyExc_TypeError, "Parameter must be callable"); return NULL; } if (get_gpio_number(channel, &gpio, &sys_gpio)) return NULL; // check channel is set up as an input if (gpio_direction[sys_gpio] != INPUT) { PyErr_SetString(PyExc_RuntimeError, "You must setup() the GPIO channel as an input first"); return NULL; } if (!gpio_event_added(sys_gpio)) { PyErr_SetString(PyExc_RuntimeError, "Add event detection using add_event_detect first before adding a callback"); return NULL; } if (add_py_callback(sys_gpio, cb_func) != 0) return NULL; Py_RETURN_NONE; }
int blocking_wait_for_edge(unsigned int gpio, unsigned int edge, int bouncetime, int timeout) // return values: // 1 - Success (edge detected) // 0 - Timeout // -1 - Edge detection already added // -2 - Other error { int n, ed; struct epoll_event events, ev; char buf; struct gpios *g = NULL; struct timeval tv_timenow; unsigned long long timenow; int finished = 0; int initial_edge = 1; if (callback_exists(gpio)) return -1; // add gpio if it has not been added already ed = gpio_event_added(gpio); if (ed == edge) { // get existing record g = get_gpio(gpio); if (g->bouncetime != -666 && g->bouncetime != bouncetime) { return -1; } } else if (ed == NO_EDGE) { // not found so add event if ((g = new_gpio(gpio)) == NULL) { return -2; } gpio_set_edge(gpio, edge); g->edge = edge; g->bouncetime = bouncetime; } else { // ed != edge - event for a different edge g = get_gpio(gpio); gpio_set_edge(gpio, edge); g->edge = edge; g->bouncetime = bouncetime; g->initial_wait = 1; } // create epfd_blocking if not already open if ((epfd_blocking == -1) && ((epfd_blocking = epoll_create(1)) == -1)) { return -2; } // add to epoll fd ev.events = EPOLLIN | EPOLLET | EPOLLPRI; ev.data.fd = g->value_fd; if (epoll_ctl(epfd_blocking, EPOLL_CTL_ADD, g->value_fd, &ev) == -1) { return -2; } // wait for edge while (!finished) { if ((n = epoll_wait(epfd_blocking, &events, 1, timeout)) == -1) { epoll_ctl(epfd_blocking, EPOLL_CTL_DEL, g->value_fd, &ev); return -2; } if (initial_edge) { // first time triggers with current state, so ignore initial_edge = 0; } else { gettimeofday(&tv_timenow, NULL); timenow = tv_timenow.tv_sec*1E6 + tv_timenow.tv_usec; if (g->bouncetime == -666 || timenow - g->lastcall > g->bouncetime*1000 || g->lastcall == 0 || g->lastcall > timenow) { g->lastcall = timenow; finished = 1; } } } // check event was valid if (n > 0) { lseek(events.data.fd, 0, SEEK_SET); if ((read(events.data.fd, &buf, 1) != 1) || (events.data.fd != g->value_fd)) { epoll_ctl(epfd_blocking, EPOLL_CTL_DEL, g->value_fd, &ev); return -2; } } epoll_ctl(epfd_blocking, EPOLL_CTL_DEL, g->value_fd, &ev); if (n == 0) { return 0; // timeout } else { return 1; // edge found } }
int blocking_wait_for_edge(unsigned int gpio, unsigned int edge) // standalone from all the event functions above { int epfd, fd, n, i; struct epoll_event events, ev; char buf; if ((epfd = epoll_create(1)) == -1) return 1; // check to see if this gpio has been added already if (gpio_event_added(gpio) != 0) return 2; // export /sys/class/gpio interface gpio_export(gpio); gpio_set_direction(gpio, 1); // 1=input gpio_set_edge(gpio, edge); if ((fd = open_value_file(gpio)) == -1) return 3; // add to epoll fd ev.events = EPOLLIN | EPOLLET | EPOLLPRI; ev.data.fd = fd; if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) == -1) { gpio_unexport(gpio); close(fd); return 4; } // epoll for event for (i = 0; i<2; i++) // first time triggers with current state, so ignore if ((n = epoll_wait(epfd, &events, 1, -1)) == -1) { gpio_unexport(gpio); close(fd); return 5; } if (n > 0) { lseek(events.data.fd, 0, SEEK_SET); if (read(events.data.fd, &buf, 1) != 1) { gpio_unexport(gpio); close(fd); return 6; } if (events.data.fd != fd) { gpio_unexport(gpio); close(fd); return 7; } } // clean up gpio_unexport(gpio); close(fd); close(epfd); return 0; }