Sfoglia il codice sorgente

Merge pull request #1136 from TerryE/dev-quick-gpio-bugfix

one line bugfix to GPIO.c -- Oops!  (Finally!)
Philip Gladstone 8 anni fa
parent
commit
6822116d64
2 ha cambiato i file con 45 aggiunte e 27 eliminazioni
  1. 24 8
      app/modules/gpio.c
  2. 21 19
      docs/en/modules/gpio.md

+ 24 - 8
app/modules/gpio.c

@@ -63,22 +63,38 @@ static void gpio_intr_callback_task (task_param_t param, uint8 priority)
 static int lgpio_trig( lua_State* L )
 {
   unsigned pin = luaL_checkinteger( L, 1 );
-  static const char * const opts[] = {"", "up", "down", "both", "low", "high"};
+  static const char * const opts[] = {"none", "up", "down", "both", "low", "high", NULL};
   static const int opts_type[] = {
     GPIO_PIN_INTR_DISABLE, GPIO_PIN_INTR_POSEDGE, GPIO_PIN_INTR_NEGEDGE,
     GPIO_PIN_INTR_ANYEDGE, GPIO_PIN_INTR_LOLEVEL, GPIO_PIN_INTR_HILEVEL
     };
-  int type = opts_type[luaL_checkoption(L, 2, "", opts)];
-
   luaL_argcheck(L, platform_gpio_exists(pin) && pin>0, 1, "Invalid interrupt pin");
 
-  if (type != GPIO_PIN_INTR_DISABLE) {
-    int cbtype = lua_type(L, 3);
-    luaL_argcheck(L, cbtype == LUA_TFUNCTION || cbtype == LUA_TLIGHTFUNCTION, 3,
-      "invalid callback type");
-    lua_pushvalue(L, 3);  // copy argument (func) to the top of stack
+  int old_pin_ref = gpio_cb_ref[pin];
+  int type = opts_type[luaL_checkoption(L, 2, "none", opts)];
+
+  if (type == GPIO_PIN_INTR_DISABLE) {
+    // "none" clears the callback
+    gpio_cb_ref[pin] = LUA_NOREF;
+
+  } else if (lua_gettop(L)==2 && old_pin_ref != LUA_NOREF) {
+    // keep the old one if no callback 
+    old_pin_ref = LUA_NOREF;
+
+  } else if (lua_type(L, 3) == LUA_TFUNCTION || lua_type(L, 3) == LUA_TLIGHTFUNCTION) {
+    // set up the new callback if present
+    lua_pushvalue(L, 3);
     gpio_cb_ref[pin] = luaL_ref(L, LUA_REGISTRYINDEX);
+
+  } else {
+     // invalid combination, so clear down any old callback and throw an error
+    if(old_pin_ref != LUA_NOREF) luaL_unref(L, LUA_REGISTRYINDEX, old_pin_ref);
+    luaL_argcheck(L,  0, 3, "invalid callback type");
   }
+
+  // unreference any overwritten callback
+  if(old_pin_ref != LUA_NOREF) luaL_unref(L, LUA_REGISTRYINDEX, old_pin_ref);
+
   NODE_DBG("Pin data: %d %d %08x, %d %d %d, %08x\n",
           pin, type, pin_mux[pin], pin_num[pin], pin_func[pin], pin_int_type[pin], gpio_cb_ref[pin]);
   platform_gpio_intr_init(pin, type);

+ 21 - 19
docs/en/modules/gpio.md

@@ -98,19 +98,21 @@ gpio.serout(1,1,{8,18},8) -- serial 30% pwm 38k, lasts 8 cycles
 
 ## gpio.trig()
 
-Establish a callback function to run on interrupt for a pin.
-
-There is currently no support for unregistering the callback.
+Establish or clear a callback function to run on interrupt for a pin.
 
 This function is not available if GPIO_INTERRUPT_ENABLE was undefined at compile time.
 
 #### Syntax
-`gpio.trig(pin, type [, function(level)])`
+`gpio.trig(pin, [type [, callback_function]])`
 
 #### Parameters
-- `pin` **1~12**, IO index, pin D0 does not support interrupt.
-- `type` "up", "down", "both", "low", "high", which represent rising edge, falling edge, both edge, low level, high level trig mode correspondingly.
-- `function(level)` callback function when triggered. The gpio level is the param. Use previous callback function if undefined here.
+- `pin` **1-12**, pin to trigger on, IO index. Note that pin 0 does not support interrupts.
+- `type` "up", "down", "both", "low", "high", which represent *rising edge*, *falling edge*, *both 
+edges*, *low level*, and *high level* trigger modes respectivey. If the type is "none" or omitted 
+then the callback function is removed and the interrupt is disabled.
+- `callback_function(level)` callback function when trigger occurs. The level of the specified pin 
+at the interrupt passed as the parameter to the callback. The previous callback function will be 
+used if the function is omitted.
 
 #### Returns
 `nil`
@@ -118,20 +120,20 @@ This function is not available if GPIO_INTERRUPT_ENABLE was undefined at compile
 #### Example
 
 ```lua
--- use pin 1 as the input pulse width counter
-pin = 1
-pulse1 = 0
-du = 0
-gpio.mode(pin,gpio.INT)
-function pin1cb(level)
-  du = tmr.now() - pulse1
-  print(du)
-  pulse1 = tmr.now()
-  if level == gpio.HIGH then gpio.trig(pin, "down") else gpio.trig(pin, "up") end
+do
+  -- use pin 1 as the input pulse width counter
+  local pin, pulse1, du, now, trig = 1, 0, 0, tmr.now, gpio.trig
+  gpio.mode(pin,gpio.INT)
+  local function pin1cb(level)
+    local pulse2 = now()
+    print( level, pulse2 - pulse1 )
+    pulse1 = pulse2
+    trig(pin, level == gpio.HIGH  and "down" or "up")
+  end
+  trig(pin, "down", pin1cb)
 end
-gpio.trig(pin, "down", pin1cb)
-
 ```
+
 #### See also
 [`gpio.mode()`](#gpiomode)