|
@@ -2,9 +2,9 @@
|
|
|
|
|
|
#include "module.h"
|
|
|
#include "lauxlib.h"
|
|
|
+#include "lmem.h"
|
|
|
#include "platform.h"
|
|
|
-#include "rom.h"
|
|
|
-
|
|
|
+#include "user_interface.h"
|
|
|
#include "c_types.h"
|
|
|
#include "c_string.h"
|
|
|
|
|
@@ -16,139 +16,115 @@
|
|
|
#define HIGH PLATFORM_GPIO_HIGH
|
|
|
#define LOW PLATFORM_GPIO_LOW
|
|
|
|
|
|
-
|
|
|
#ifdef GPIO_INTERRUPT_ENABLE
|
|
|
static int gpio_cb_ref[GPIO_PIN_NUM];
|
|
|
-static lua_State* gL = NULL;
|
|
|
-
|
|
|
-void lua_gpio_unref(unsigned pin){
|
|
|
- if(gpio_cb_ref[pin] != LUA_NOREF){
|
|
|
- if(gL!=NULL)
|
|
|
- luaL_unref(gL, LUA_REGISTRYINDEX, gpio_cb_ref[pin]);
|
|
|
- }
|
|
|
- gpio_cb_ref[pin] = LUA_NOREF;
|
|
|
-}
|
|
|
|
|
|
-void gpio_intr_callback( unsigned pin, unsigned level )
|
|
|
+// This task is scheduled by the ISP if pin_trigger[pin] is true and is used
|
|
|
+// to intitied the Lua-land gpio.trig() callback function
|
|
|
+static void gpio_intr_callback_task (task_param_t param, uint8 priority)
|
|
|
{
|
|
|
+ unsigned pin = param >> 1;
|
|
|
+ unsigned level = param & 1;
|
|
|
+ UNUSED(priority);
|
|
|
+
|
|
|
NODE_DBG("pin:%d, level:%d \n", pin, level);
|
|
|
- if(gpio_cb_ref[pin] == LUA_NOREF)
|
|
|
- return;
|
|
|
- if(!gL)
|
|
|
- return;
|
|
|
- lua_rawgeti(gL, LUA_REGISTRYINDEX, gpio_cb_ref[pin]);
|
|
|
- lua_pushinteger(gL, level);
|
|
|
- lua_call(gL, 1, 0);
|
|
|
+ if(gpio_cb_ref[pin] != LUA_NOREF) {
|
|
|
+ // GPIO callbacks are run in L0 and inlcude the level as a parameter
|
|
|
+ lua_State *L = lua_getstate();
|
|
|
+ NODE_DBG("Calling: %08x\n", gpio_cb_ref[pin]);
|
|
|
+ // The trigger is reset before the callback, as the callback itself might reset the trigger
|
|
|
+ pin_trigger[pin] = true;
|
|
|
+ lua_rawgeti(L, LUA_REGISTRYINDEX, gpio_cb_ref[pin]);
|
|
|
+ lua_pushinteger(L, level);
|
|
|
+ lua_call(L, 1, 0);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
// Lua: trig( pin, type, function )
|
|
|
static int lgpio_trig( lua_State* L )
|
|
|
{
|
|
|
- unsigned type;
|
|
|
- unsigned pin;
|
|
|
- size_t sl;
|
|
|
-
|
|
|
- pin = luaL_checkinteger( L, 1 );
|
|
|
- MOD_CHECK_ID( gpio, pin );
|
|
|
- if(pin==0)
|
|
|
- return luaL_error( L, "no interrupt for D0" );
|
|
|
-
|
|
|
- const char *str = luaL_checklstring( L, 2, &sl );
|
|
|
- if (str == NULL)
|
|
|
- return luaL_error( L, "wrong arg type" );
|
|
|
-
|
|
|
- if(sl == 2 && c_strcmp(str, "up") == 0){
|
|
|
- type = GPIO_PIN_INTR_POSEDGE;
|
|
|
- }else if(sl == 4 && c_strcmp(str, "down") == 0){
|
|
|
- type = GPIO_PIN_INTR_NEGEDGE;
|
|
|
- }else if(sl == 4 && c_strcmp(str, "both") == 0){
|
|
|
- type = GPIO_PIN_INTR_ANYEDGE;
|
|
|
- }else if(sl == 3 && c_strcmp(str, "low") == 0){
|
|
|
- type = GPIO_PIN_INTR_LOLEVEL;
|
|
|
- }else if(sl == 4 && c_strcmp(str, "high") == 0){
|
|
|
- type = GPIO_PIN_INTR_HILEVEL;
|
|
|
- }else{
|
|
|
- type = GPIO_PIN_INTR_DISABLE;
|
|
|
- }
|
|
|
-
|
|
|
- // luaL_checkanyfunction(L, 3);
|
|
|
- if (lua_type(L, 3) == LUA_TFUNCTION || lua_type(L, 3) == LUA_TLIGHTFUNCTION){
|
|
|
+ unsigned pin = luaL_checkinteger( L, 1 );
|
|
|
+ static const char * const opts[] = {"", "up", "down", "both", "low", "high"};
|
|
|
+ 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
|
|
|
- if(gpio_cb_ref[pin] != LUA_NOREF)
|
|
|
- luaL_unref(L, LUA_REGISTRYINDEX, gpio_cb_ref[pin]);
|
|
|
gpio_cb_ref[pin] = luaL_ref(L, LUA_REGISTRYINDEX);
|
|
|
}
|
|
|
-
|
|
|
+ NODE_DBG("Pin data: %d %d %08x, %d %d %d %d, %08x\n",
|
|
|
+ pin, type, pin_mux[pin], pin_num[pin], pin_func[pin], pin_int_type[pin], pin_trigger[pin], gpio_cb_ref[pin]);
|
|
|
platform_gpio_intr_init(pin, type);
|
|
|
- return 0;
|
|
|
+ return 0;
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
// Lua: mode( pin, mode, pullup )
|
|
|
static int lgpio_mode( lua_State* L )
|
|
|
{
|
|
|
- unsigned mode, pullup = FLOAT;
|
|
|
- unsigned pin;
|
|
|
+ unsigned pin = luaL_checkinteger( L, 1 );
|
|
|
+ unsigned mode = luaL_checkinteger( L, 2 );
|
|
|
+ unsigned pullup = luaL_optinteger( L, 3, FLOAT );
|
|
|
+
|
|
|
+ luaL_argcheck(L, platform_gpio_exists(pin) && (mode!=INTERRUPT || pin>0), 1, "Invalid pin");
|
|
|
+ luaL_argcheck(L, mode==OUTPUT || mode==INPUT
|
|
|
+ #ifdef GPIO_INTERRUPT_ENABLE
|
|
|
+ || mode==INTERRUPT
|
|
|
+ #endif
|
|
|
+ , 2, "wrong arg type" );
|
|
|
+ if(pullup!=FLOAT) pullup = PULLUP;
|
|
|
+
|
|
|
+NODE_DBG("pin,mode,pullup= %d %d %d\n",pin,mode,pullup);
|
|
|
+NODE_DBG("Pin data at mode: %d %08x, %d %d %d %d, %08x\n",
|
|
|
+ pin, pin_mux[pin], pin_num[pin], pin_func[pin], pin_int_type[pin], pin_trigger[pin], gpio_cb_ref[pin]);
|
|
|
|
|
|
- pin = luaL_checkinteger( L, 1 );
|
|
|
- MOD_CHECK_ID( gpio, pin );
|
|
|
- mode = luaL_checkinteger( L, 2 );
|
|
|
- if ( mode!=OUTPUT && mode!=INPUT && mode!=INTERRUPT)
|
|
|
- return luaL_error( L, "wrong arg type" );
|
|
|
- if(pin==0 && mode==INTERRUPT)
|
|
|
- return luaL_error( L, "no interrupt for D0" );
|
|
|
- if(lua_isnumber(L, 3))
|
|
|
- pullup = lua_tointeger( L, 3 );
|
|
|
- if(pullup!=FLOAT)
|
|
|
- pullup = PULLUP;
|
|
|
#ifdef GPIO_INTERRUPT_ENABLE
|
|
|
- gL = L; // save to local gL, for callback function
|
|
|
- if (mode!=INTERRUPT){ // disable interrupt
|
|
|
+ if (mode != INTERRUPT){ // disable interrupt
|
|
|
if(gpio_cb_ref[pin] != LUA_NOREF){
|
|
|
luaL_unref(L, LUA_REGISTRYINDEX, gpio_cb_ref[pin]);
|
|
|
+ gpio_cb_ref[pin] = LUA_NOREF;
|
|
|
}
|
|
|
- gpio_cb_ref[pin] = LUA_NOREF;
|
|
|
}
|
|
|
#endif
|
|
|
- int r = platform_gpio_mode( pin, mode, pullup );
|
|
|
- if( r<0 )
|
|
|
+
|
|
|
+ if( platform_gpio_mode( pin, mode, pullup ) < 0 )
|
|
|
return luaL_error( L, "wrong pin num." );
|
|
|
- return 0;
|
|
|
+
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
// Lua: read( pin )
|
|
|
static int lgpio_read( lua_State* L )
|
|
|
{
|
|
|
- unsigned pin;
|
|
|
-
|
|
|
- pin = luaL_checkinteger( L, 1 );
|
|
|
+ unsigned pin = luaL_checkinteger( L, 1 );
|
|
|
MOD_CHECK_ID( gpio, pin );
|
|
|
-
|
|
|
- unsigned level = platform_gpio_read( pin );
|
|
|
- lua_pushinteger( L, level );
|
|
|
- return 1;
|
|
|
+ lua_pushinteger( L, platform_gpio_read( pin ) );
|
|
|
+ return 1;
|
|
|
}
|
|
|
|
|
|
// Lua: write( pin, level )
|
|
|
static int lgpio_write( lua_State* L )
|
|
|
{
|
|
|
- unsigned level;
|
|
|
- unsigned pin;
|
|
|
-
|
|
|
- pin = luaL_checkinteger( L, 1 );
|
|
|
+ unsigned pin = luaL_checkinteger( L, 1 );
|
|
|
+ unsigned level = luaL_checkinteger( L, 2 );
|
|
|
+
|
|
|
MOD_CHECK_ID( gpio, pin );
|
|
|
- level = luaL_checkinteger( L, 2 );
|
|
|
- if ( level!=HIGH && level!=LOW )
|
|
|
- return luaL_error( L, "wrong arg type" );
|
|
|
+ luaL_argcheck(L, level==HIGH || level==LOW, 2, "wrong level type" );
|
|
|
+
|
|
|
platform_gpio_write(pin, level);
|
|
|
- return 0;
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
#define DELAY_TABLE_MAX_LEN 256
|
|
|
-#define noInterrupts ets_intr_lock
|
|
|
-#define interrupts ets_intr_unlock
|
|
|
#define delayMicroseconds os_delay_us
|
|
|
-#define DIRECT_WRITE(pin, level) (GPIO_OUTPUT_SET(GPIO_ID_PIN(pin_num[pin]), level))
|
|
|
// Lua: serout( pin, firstLevel, delay_table, [repeatNum] )
|
|
|
// -- serout( pin, firstLevel, delay_table, [repeatNum] )
|
|
|
// gpio.mode(1,gpio.OUTPUT,gpio.PULLUP)
|
|
@@ -161,62 +137,41 @@ static int lgpio_write( lua_State* L )
|
|
|
// gpio.serout(1,1,{8,18},8) -- serial 30% pwm 38k, lasts 8 cycles
|
|
|
static int lgpio_serout( lua_State* L )
|
|
|
{
|
|
|
- unsigned level;
|
|
|
- unsigned pin;
|
|
|
- unsigned table_len = 0;
|
|
|
- unsigned repeat = 0;
|
|
|
- int delay_table[DELAY_TABLE_MAX_LEN];
|
|
|
-
|
|
|
- pin = luaL_checkinteger( L, 1 );
|
|
|
- MOD_CHECK_ID( gpio, pin );
|
|
|
- level = luaL_checkinteger( L, 2 );
|
|
|
- if ( level!=HIGH && level!=LOW )
|
|
|
- return luaL_error( L, "wrong arg type" );
|
|
|
- if( lua_istable( L, 3 ) )
|
|
|
- {
|
|
|
- table_len = lua_objlen( L, 3 );
|
|
|
- if (table_len <= 0 || table_len>DELAY_TABLE_MAX_LEN)
|
|
|
- return luaL_error( L, "wrong arg range" );
|
|
|
- int i;
|
|
|
- for( i = 0; i < table_len; i ++ )
|
|
|
- {
|
|
|
- lua_rawgeti( L, 3, i + 1 );
|
|
|
- delay_table[i] = ( int )luaL_checkinteger( L, -1 );
|
|
|
- lua_pop( L, 1 );
|
|
|
- if( delay_table[i] < 0 || delay_table[i] > 1000000 ) // can not delay more than 1000000 us
|
|
|
- return luaL_error( L, "delay must < 1000000 us" );
|
|
|
- }
|
|
|
- } else {
|
|
|
- return luaL_error( L, "wrong arg range" );
|
|
|
- }
|
|
|
-
|
|
|
- if(lua_isnumber(L, 4))
|
|
|
- repeat = lua_tointeger( L, 4 );
|
|
|
- if( repeat < 0 || repeat > DELAY_TABLE_MAX_LEN )
|
|
|
- return luaL_error( L, "delay must < 256" );
|
|
|
-
|
|
|
- if(repeat==0)
|
|
|
- repeat = 1;
|
|
|
- int j;
|
|
|
- bool skip_loop = true;
|
|
|
- do
|
|
|
- {
|
|
|
- if(skip_loop){ // skip the first loop.
|
|
|
- skip_loop = false;
|
|
|
+ unsigned clocks_per_us = system_get_cpu_freq();
|
|
|
+ unsigned pin = luaL_checkinteger( L, 1 );
|
|
|
+ unsigned level = luaL_checkinteger( L, 2 );
|
|
|
+ unsigned repeats = luaL_optint( L, 4, 1 );
|
|
|
+ unsigned table_len, i, j;
|
|
|
+
|
|
|
+ luaL_argcheck(L, platform_gpio_exists(pin), 1, "Invalid pin");
|
|
|
+ luaL_argcheck(L, level==HIGH || level==LOW, 2, "Wrong arg type" );
|
|
|
+ luaL_argcheck(L, lua_istable( L, 3 ) &&
|
|
|
+ ((table_len = lua_objlen( L, 3 )<DELAY_TABLE_MAX_LEN)), 3, "Invalid table" );
|
|
|
+ luaL_argcheck(L, repeats<256, 4, "repeats >= 256" );
|
|
|
+
|
|
|
+ uint32 *delay_table = luaM_newvector(L, table_len*repeats, uint32);
|
|
|
+ for( i = 1; i <= table_len; i++ ) {
|
|
|
+ lua_rawgeti( L, 3, i + 1 );
|
|
|
+ unsigned delay = (unsigned) luaL_checkinteger( L, -1 );
|
|
|
+ if (delay > 1000000) return luaL_error( L, "delay %u must be < 1,000,000 us", i );
|
|
|
+ delay_table[i-1] = delay;
|
|
|
+ lua_pop( L, 1 );
|
|
|
+ }
|
|
|
+
|
|
|
+ for( i = 0; i <= repeats; i++ ) {
|
|
|
+ if (!i) // skip the first loop (presumably this is some form of icache priming??).
|
|
|
continue;
|
|
|
- }
|
|
|
- for(j=0;j<table_len;j++){
|
|
|
- noInterrupts();
|
|
|
- // platform_gpio_write(pin, level);
|
|
|
- DIRECT_WRITE(pin, level);
|
|
|
- interrupts();
|
|
|
+
|
|
|
+ for( j = 0;j < table_len; j++ ){
|
|
|
+ /* Direct Write is a ROM function which already disables interrupts for the atomic bit */
|
|
|
+ GPIO_OUTPUT_SET(GPIO_ID_PIN(pin_num[pin]), level);
|
|
|
delayMicroseconds(delay_table[j]);
|
|
|
- level=!level;
|
|
|
+ level = level==LOW ? HIGH : LOW;
|
|
|
}
|
|
|
- repeat--;
|
|
|
- } while (repeat>0);
|
|
|
+ }
|
|
|
|
|
|
- return 0;
|
|
|
+ luaM_freearray(L, delay_table, table_len, uint32);
|
|
|
+ return 0;
|
|
|
}
|
|
|
#undef DELAY_TABLE_MAX_LEN
|
|
|
|
|
@@ -245,7 +200,7 @@ int luaopen_gpio( lua_State *L ) {
|
|
|
for(i=0;i<GPIO_PIN_NUM;i++){
|
|
|
gpio_cb_ref[i] = LUA_NOREF;
|
|
|
}
|
|
|
- platform_gpio_init(gpio_intr_callback);
|
|
|
+ platform_gpio_init(task_get_id(gpio_intr_callback_task));
|
|
|
#endif
|
|
|
return 0;
|
|
|
}
|