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, 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; }
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 } }