From a61af52d96fa0b511c097d1fa62fd60c1b2fd9a8 Mon Sep 17 00:00:00 2001
From: UncleRus <unclerus@gmail.com>
Date: Wed, 30 Nov 2016 00:58:24 +0500
Subject: [PATCH] More convenient GPIO interrupt handlers

---
 core/esp_gpio.c            | 31 +++++++++++++++
 core/esp_gpio_interrupts.c | 80 --------------------------------------
 core/include/esp/gpio.h    | 11 +-----
 examples/button/button.c   |  7 ++--
 4 files changed, 37 insertions(+), 92 deletions(-)
 delete mode 100644 core/esp_gpio_interrupts.c

diff --git a/core/esp_gpio.c b/core/esp_gpio.c
index f6db1ef..bb8987f 100644
--- a/core/esp_gpio.c
+++ b/core/esp_gpio.c
@@ -56,3 +56,34 @@ void gpio_set_pullup(uint8_t gpio_num, bool enabled, bool enabled_during_sleep)
     iomux_set_pullup_flags(gpio_to_iomux(gpio_num), flags);
 }
 
+static gpio_interrupt_handler_t gpio_interrupt_handlers[16] = { 0 };
+
+static void IRAM _gpio_intr_internal_handler(void)
+{
+    uint32_t status_reg = GPIO.STATUS;
+    GPIO.STATUS_CLEAR = status_reg;
+
+    uint8_t gpio_idx;
+    while((gpio_idx = __builtin_ffs(status_reg)))
+    {
+        gpio_idx--;
+        status_reg &= ~BIT(gpio_idx);
+        if(FIELD2VAL(GPIO_CONF_INTTYPE, GPIO.CONF[gpio_idx])) {
+            gpio_interrupt_handler_t handler = gpio_interrupt_handlers[gpio_idx];
+            if (handler) {
+                handler(gpio_idx);
+            }
+        }
+    }
+}
+
+void gpio_set_interrupt(const uint8_t gpio_num, const gpio_inttype_t int_type, gpio_interrupt_handler_t handler)
+{
+    gpio_interrupt_handlers[gpio_num] = handler;
+
+    GPIO.CONF[gpio_num] = SET_FIELD(GPIO.CONF[gpio_num], GPIO_CONF_INTTYPE, int_type);
+    if(int_type != GPIO_INTTYPE_NONE && handler) {
+        _xt_isr_attach(INUM_GPIO, _gpio_intr_internal_handler);
+        _xt_isr_unmask(1<<INUM_GPIO);
+    }
+}
diff --git a/core/esp_gpio_interrupts.c b/core/esp_gpio_interrupts.c
deleted file mode 100644
index ef0a47d..0000000
--- a/core/esp_gpio_interrupts.c
+++ /dev/null
@@ -1,80 +0,0 @@
-/* ESP GPIO interrupts.
-
-   Use with gpio_set_interrupt(), defined in esp/gpio.h
-
-   These interrupt vectors are default implementations with weak
-   linkage. If you write your own GPIO interrupt vectors in your program
-   then they will replace these at link time.
-
-   Look in examples/button/ for a simple GPIO interrupt example.
-
-   You can implement GPIO interrupt handlers in either of two ways:
-
-   - Implement gpXX_interrupt_handler() for each GPIO pin number that
-     you want to use interrupt with. This is simple but it may not
-     be enough in all cases.
-
-   void gpio01_interrupt_handler(void) {
-       // Do something when GPIO 01 changes
-   }
-
-   void gpio12_interrupt_handler(void) {
-       // Do something when GPIO 12 changes
-   }
-
-   OR
-
-   - Implement a single function named gpio_interrupt_handler(). This
-     will need to manually check GPIO.STATUS and clear any status
-     bits after handling interrupts. This gives you full control, but
-     you can't combine it with the first approach.
-
-
-  Part of esp-open-rtos
-  Copyright (C) 2015 Superhouse Automation Pty Ltd
-  BSD Licensed as described in the file LICENSE
- */
-#include "esp8266.h"
-
-void gpio_interrupt_handler(void);
-void gpio_noop_interrupt_handler(void) { }
-void gpio00_interrupt_handler(void) __attribute__((weak, alias("gpio_noop_interrupt_handler")));
-void gpio01_interrupt_handler(void) __attribute__((weak, alias("gpio_noop_interrupt_handler")));
-void gpio02_interrupt_handler(void) __attribute__((weak, alias("gpio_noop_interrupt_handler")));
-void gpio03_interrupt_handler(void) __attribute__((weak, alias("gpio_noop_interrupt_handler")));
-void gpio04_interrupt_handler(void) __attribute__((weak, alias("gpio_noop_interrupt_handler")));
-void gpio05_interrupt_handler(void) __attribute__((weak, alias("gpio_noop_interrupt_handler")));
-void gpio06_interrupt_handler(void) __attribute__((weak, alias("gpio_noop_interrupt_handler")));
-void gpio07_interrupt_handler(void) __attribute__((weak, alias("gpio_noop_interrupt_handler")));
-void gpio08_interrupt_handler(void) __attribute__((weak, alias("gpio_noop_interrupt_handler")));
-void gpio09_interrupt_handler(void) __attribute__((weak, alias("gpio_noop_interrupt_handler")));
-void gpio10_interrupt_handler(void) __attribute__((weak, alias("gpio_noop_interrupt_handler")));
-void gpio11_interrupt_handler(void) __attribute__((weak, alias("gpio_noop_interrupt_handler")));
-void gpio12_interrupt_handler(void) __attribute__((weak, alias("gpio_noop_interrupt_handler")));
-void gpio13_interrupt_handler(void) __attribute__((weak, alias("gpio_noop_interrupt_handler")));
-void gpio14_interrupt_handler(void) __attribute__((weak, alias("gpio_noop_interrupt_handler")));
-void gpio15_interrupt_handler(void) __attribute__((weak, alias("gpio_noop_interrupt_handler")));
-
-typedef void (* gpio_interrupt_handler_t)(void);
-
-const gpio_interrupt_handler_t gpio_interrupt_handlers[16] = {
-    gpio00_interrupt_handler, gpio01_interrupt_handler, gpio02_interrupt_handler,
-    gpio03_interrupt_handler, gpio04_interrupt_handler, gpio05_interrupt_handler,
-    gpio06_interrupt_handler, gpio07_interrupt_handler, gpio08_interrupt_handler,
-    gpio09_interrupt_handler, gpio10_interrupt_handler, gpio11_interrupt_handler,
-    gpio12_interrupt_handler, gpio13_interrupt_handler, gpio14_interrupt_handler,
-    gpio15_interrupt_handler };
-
-void __attribute__((weak)) IRAM gpio_interrupt_handler(void)
-{
-    uint32_t status_reg = GPIO.STATUS;
-    GPIO.STATUS_CLEAR = status_reg;
-    uint8_t gpio_idx;
-    while((gpio_idx = __builtin_ffs(status_reg)))
-    {
-        gpio_idx--;
-        status_reg &= ~BIT(gpio_idx);
-        if(FIELD2VAL(GPIO_CONF_INTTYPE, GPIO.CONF[gpio_idx]))
-            gpio_interrupt_handlers[gpio_idx]();
-    }
-}
diff --git a/core/include/esp/gpio.h b/core/include/esp/gpio.h
index f3f6308..32875d9 100644
--- a/core/include/esp/gpio.h
+++ b/core/include/esp/gpio.h
@@ -127,21 +127,14 @@ static inline bool gpio_read(const uint8_t gpio_num)
         return GPIO.IN & BIT(gpio_num);
 }
 
-extern void gpio_interrupt_handler(void);
+typedef void (* gpio_interrupt_handler_t)(uint8_t gpio_num);
 
 /* Set the interrupt type for a given pin
  *
  * If int_type is not GPIO_INTTYPE_NONE, the gpio_interrupt_handler will be
  * attached and unmasked.
  */
-static inline void gpio_set_interrupt(const uint8_t gpio_num, const gpio_inttype_t int_type)
-{
-    GPIO.CONF[gpio_num] = SET_FIELD(GPIO.CONF[gpio_num], GPIO_CONF_INTTYPE, int_type);
-    if(int_type != GPIO_INTTYPE_NONE) {
-        _xt_isr_attach(INUM_GPIO, gpio_interrupt_handler);
-        _xt_isr_unmask(1<<INUM_GPIO);
-    }
-}
+void gpio_set_interrupt(const uint8_t gpio_num, const gpio_inttype_t int_type, gpio_interrupt_handler_t handler);
 
 /* Return the interrupt type set for a pin */
 static inline gpio_inttype_t gpio_get_interrupt(const uint8_t gpio_num)
diff --git a/examples/button/button.c b/examples/button/button.c
index a371f0d..c12d78b 100644
--- a/examples/button/button.c
+++ b/examples/button/button.c
@@ -16,7 +16,6 @@
 const int gpio = 0;   /* gpio 0 usually has "PROGRAM" button attached */
 const int active = 0; /* active == 0 for active low */
 const gpio_inttype_t int_type = GPIO_INTTYPE_EDGE_NEG;
-#define GPIO_HANDLER gpio00_interrupt_handler
 
 
 /* This task polls for the button and prints the tick
@@ -39,6 +38,8 @@ void buttonPollTask(void *pvParameters)
     }
 }
 
+void gpio_intr_handler(uint8_t gpio_num);
+
 /* This task configures the GPIO interrupt and uses it to tell
    when the button is pressed.
 
@@ -51,7 +52,7 @@ void buttonIntTask(void *pvParameters)
 {
     printf("Waiting for button press interrupt on gpio %d...\r\n", gpio);
     QueueHandle_t *tsqueue = (QueueHandle_t *)pvParameters;
-    gpio_set_interrupt(gpio, int_type);
+    gpio_set_interrupt(gpio, int_type, gpio_intr_handler);
 
     uint32_t last = 0;
     while(1) {
@@ -67,7 +68,7 @@ void buttonIntTask(void *pvParameters)
 
 static QueueHandle_t tsqueue;
 
-void GPIO_HANDLER(void)
+void gpio_intr_handler(uint8_t gpio_num)
 {
     uint32_t now = xTaskGetTickCountFromISR();
     xQueueSendToBackFromISR(tsqueue, &now, NULL);