From: Brendan Le Foll Date: Wed, 7 May 2014 13:48:21 +0000 (+0100) Subject: gpio: initial implementation of interupt handling on gpio X-Git-Tag: v0.2.3~22 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=37b5d9f0cc15892043a6f1feec905e8fefa2b8b2;p=contrib%2Fmraa.git gpio: initial implementation of interupt handling on gpio Signed-off-by: Brendan Le Foll --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 23b6394..16256e4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,8 @@ cmake_minimum_required (VERSION 2.8) project (maa) +FIND_PACKAGE (Threads) + set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wall") set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Wall") diff --git a/api/gpio.h b/api/gpio.h index 6a141b6..6bc6ff8 100644 --- a/api/gpio.h +++ b/api/gpio.h @@ -35,15 +35,20 @@ extern "C" { #endif #include +#include #include "maa.h" /** * A strucutre representing a gpio pin. */ + typedef struct { /*@{*/ int pin; /**< the pin number, as known to the os. */ FILE *value_fp; /**< the file pointer to the value of the gpio */ + void (* isr)(); /**< the interupt service request */ + pthread_t thread_id; /**< the isr handler thread id */ + int isr_value_fp; /**< the isr file pointer on the value */ /*@}*/ } maa_gpio_context; @@ -65,6 +70,13 @@ typedef enum { MAA_GPIO_IN = 1 /**< Input. */ } gpio_dir_t; +typedef enum { + MAA_GPIO_EDGE_NONE = 0, /**< No interrupt on GPIO */ + MAA_GPIO_EDGE_BOTH = 1, /**< Interupt on rising & falling */ + MAA_GPIO_EDGE_RISING = 2, /**< Interupt on rising only */ + MAA_GPIO_EDGE_FALLING = 3 /**< Interupt on falling only */ +} gpio_edge_t; + /** Initialise gpio_context, based on board number * * @param pin pin number read from the board, i.e IO3 is 3. @@ -82,6 +94,37 @@ maa_gpio_context* maa_gpio_init(int pin); */ maa_gpio_context* maa_gpio_init_raw(int gpiopin); +/** Set the edge mode on the gpio + * + * @param dev The GPIO context + * @param mode The edge mode to set the gpio into + * + * @return maa result type. + */ +maa_result_t maa_gpio_edge_mode(maa_gpio_context *dev, gpio_edge_t mode); + +/** Set an interupt on pin + * + * @param dev The GPIO context + * @param mode The edge mode to set the gpio into + * @param fptr Function pointer to function to be called when interupt is + * triggered + * + * @return maa result type. + */ +maa_result_t +maa_gpio_isr(maa_gpio_context *dev, gpio_edge_t edge, void (*fptr)(void)); + +/** Stop the current interupt watcher on this GPIO, and set the GPIO edge mode + * to MAA_GPIO_EDGE_NONE. + * + * @param dev The GPIO context. + * + * @return maa result type. + */ +maa_result_t +maa_gpio_isr_exit(maa_gpio_context *dev); + /** Set GPIO Output Mode, * * @param dev The GPIO context diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 49de0b3..cfd5718 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -3,11 +3,13 @@ add_executable (hellomaa hellomaa.c) add_executable (cycle-pwm3 cycle-pwm3.c) add_executable (blink-io8 blink-io8.c) add_executable (analogin_a0 analogin_a0.c) +add_executable (isr_pin6 isr_pin6.c) include_directories(${PROJECT_SOURCE_DIR}/api ${PROJECT_SOURCE_DIR}/include) -target_link_libraries (hellomaa maa) -target_link_libraries (i2c_HMC5883L maa m) -target_link_libraries (cycle-pwm3 maa) -target_link_libraries (blink-io8 maa) -target_link_libraries (analogin_a0 maa) +target_link_libraries (hellomaa maa ${CMAKE_THREAD_LIBS_INIT}) +target_link_libraries (i2c_HMC5883L maa m ${CMAKE_THREAD_LIBS_INIT}) +target_link_libraries (cycle-pwm3 maa ${CMAKE_THREAD_LIBS_INIT}) +target_link_libraries (blink-io8 maa ${CMAKE_THREAD_LIBS_INIT}) +target_link_libraries (analogin_a0 maa ${CMAKE_THREAD_LIBS_INIT}) +target_link_libraries (isr_pin6 maa ${CMAKE_THREAD_LIBS_INIT}) diff --git a/examples/isr_pin6.c b/examples/isr_pin6.c new file mode 100644 index 0000000..916bc20 --- /dev/null +++ b/examples/isr_pin6.c @@ -0,0 +1,64 @@ +/* + * Author: Brendan Le Foll + * Copyright (c) 2014 Intel Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include + +#include "gpio.h" + +static volatile int counter = 0; +static volatile int oldcounter = 0; + +void interrupt (void) { + ++counter; +} + +int main () +{ + maa_init(); + maa_gpio_context* x; + + x = maa_gpio_init(6); + if (x == NULL) { + return 1; + } + + maa_gpio_dir(x, MAA_GPIO_IN); + + gpio_edge_t edge = MAA_GPIO_EDGE_BOTH; + + maa_gpio_isr(x, edge, &interrupt); + + for(;;) { + if(counter != oldcounter) { + fprintf(stdout, "timeout counter == %d\n", counter); + oldcounter = counter; + } + // got to relieve our poor CPU! + sleep(1); + } + + maa_gpio_close(x); + + return MAA_SUCCESS; +} diff --git a/src/gpio/gpio.c b/src/gpio/gpio.c index e49213a..ba5d590 100644 --- a/src/gpio/gpio.c +++ b/src/gpio/gpio.c @@ -22,28 +22,29 @@ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include "gpio.h" #include #include -#include +#include #include - -#include "gpio.h" +#include #define SYSFS_CLASS_GPIO "/sys/class/gpio" #define MAX_SIZE 64 +#define POLL_TIMEOUT -static int +static maa_result_t maa_gpio_get_valfp(maa_gpio_context *dev) { char bu[MAX_SIZE]; sprintf(bu, SYSFS_CLASS_GPIO "/gpio%d/value", dev->pin); if ((dev->value_fp = fopen(bu, "r+b")) == NULL) { - return 1; + return MAA_ERROR_INVALID_RESOURCE; } - return 0; + return MAA_SUCCESS; } maa_gpio_context* @@ -67,6 +68,7 @@ maa_gpio_init_raw(int pin) int length; maa_gpio_context* dev = (maa_gpio_context*) malloc(sizeof(maa_gpio_context)); + memset(dev, 0, sizeof(maa_gpio_context)); dev->pin = pin; if ((export_f = fopen(SYSFS_CLASS_GPIO "/export", "w")) == NULL) { @@ -80,6 +82,123 @@ maa_gpio_init_raw(int pin) return dev; } +static maa_result_t +maa_gpio_wait_interrupt(int fd) +{ + unsigned char c; + struct pollfd pfd; + + // setup poll on POLLPRI + pfd.fd = fd; + pfd.events = POLLPRI; + + // do an initial read to clear interupt + read (fd, &c, 1); + + if (fd <= 0) { + return MAA_ERROR_INVALID_RESOURCE; + } + + // Wait for it forever + int x = poll (&pfd, 1, -1); + + // do a final read to clear interupt + read (fd, &c, 1); + + return MAA_SUCCESS; +} + +static void* +maa_gpio_interrupt_handler(void* arg) +{ + maa_gpio_context* dev = (maa_gpio_context*) arg; + maa_result_t ret; + + // open gpio value with open(3) + char bu[MAX_SIZE]; + sprintf(bu, SYSFS_CLASS_GPIO "/gpio%d/value", dev->pin); + dev->isr_value_fp = open(bu, O_RDONLY); + + for (;;) { + ret = maa_gpio_wait_interrupt(dev->isr_value_fp); + if (ret == MAA_SUCCESS) { + dev->isr(); + } else { + // we must have got an error code so die nicely + close(dev->isr_value_fp); + return; + } + } +} + +maa_result_t +maa_gpio_edge_mode(maa_gpio_context *dev, gpio_edge_t mode) +{ + if (dev->value_fp != NULL) { + dev->value_fp = NULL; + } + + char filepath[MAX_SIZE]; + snprintf(filepath, MAX_SIZE, SYSFS_CLASS_GPIO "/gpio%d/edge", dev->pin); + + FILE *edge; + if ((edge= fopen(filepath, "w")) == NULL) { + fprintf(stderr, "Failed to open edge for writing!\n"); + return MAA_ERROR_INVALID_RESOURCE; + } + + char bu[MAX_SIZE]; + int length; + switch(mode) { + case MAA_GPIO_EDGE_NONE: + length = snprintf(bu, sizeof(bu), "none"); + break; + case MAA_GPIO_EDGE_BOTH: + length = snprintf(bu, sizeof(bu), "both"); + break; + case MAA_GPIO_EDGE_RISING: + length = snprintf(bu, sizeof(bu), "rising"); + break; + case MAA_GPIO_EDGE_FALLING: + length = snprintf(bu, sizeof(bu), "falling"); + break; + default: + fclose(edge); + return MAA_ERROR_FEATURE_NOT_IMPLEMENTED; + } + fwrite(bu, sizeof(char), length, edge); + + fclose(edge); + dev->value_fp = NULL; + return MAA_SUCCESS; +} + +maa_result_t +maa_gpio_isr(maa_gpio_context *dev, gpio_edge_t mode, void (*fptr)(void)) +{ + maa_gpio_edge_mode(dev, mode); + dev->isr = fptr; + pthread_create (&dev->thread_id, NULL, maa_gpio_interrupt_handler, (void *) dev); + + return MAA_SUCCESS; +} + +maa_result_t +maa_gpio_isr_exit(maa_gpio_context *dev) +{ + maa_result_t ret = MAA_SUCCESS; + maa_gpio_edge_mode(dev, MAA_GPIO_EDGE_NONE); + + if (pthread_kill(dev->thread_id) != 0) { + ret = MAA_ERROR_INVALID_HANDLE; + } + if (close(dev->isr_value_fp) != 0) { + ret = MAA_ERROR_INVALID_PARAMETER; + } + + return ret; +} + maa_result_t maa_gpio_mode(maa_gpio_context *dev, gpio_mode_t mode) { @@ -211,6 +330,8 @@ maa_gpio_unexport(maa_gpio_context *dev) fwrite(bu, sizeof(char), length, unexport_f); fclose(unexport_f); + maa_gpio_isr_exit(dev); + return MAA_SUCCESS; }