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;
}
Ejemplo n.º 2
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
    }
}