/* * Module for interfacing with Switec instrument steppers (and * similar devices). These are the steppers that are used in automotive * instrument panels and the like. Run off 5 volts at low current. * * Code inspired by: * * SwitecX25 Arduino Library * Guy Carpenter, Clearwater Software - 2012 * * Licensed under the BSD2 license, see license.txt for details. * * NodeMcu integration by Philip Gladstone, N1DQ */ #include "module.h" #include "lauxlib.h" #include "platform.h" #include #include "task/task.h" #include "driver/switec.h" // This is the reference to the callbacks for when the pointer // stops moving. static int stopped_callback[SWITEC_CHANNEL_COUNT] = { LUA_NOREF, LUA_NOREF, LUA_NOREF }; static task_handle_t tasknumber; static void callback_free(lua_State* L, unsigned int id) { luaL_unref(L, LUA_REGISTRYINDEX, stopped_callback[id]); stopped_callback[id] = LUA_NOREF; } static void callback_set(lua_State* L, unsigned int id, int argNumber) { if (lua_isfunction(L, argNumber)) { lua_pushvalue(L, argNumber); // copy argument (func) to the top of stack callback_free(L, id); stopped_callback[id] = luaL_ref(L, LUA_REGISTRYINDEX); } } static void callback_execute(lua_State* L, unsigned int id) { if (stopped_callback[id] != LUA_NOREF) { int callback = stopped_callback[id]; lua_rawgeti(L, LUA_REGISTRYINDEX, callback); callback_free(L, id); luaL_pcallx(L, 0, 0); } } int platform_switec_exists( unsigned int id ) { return (id < SWITEC_CHANNEL_COUNT); } // Lua: setup(id, P1, P2, P3, P4, maxSpeed) static int lswitec_setup( lua_State* L ) { unsigned int id; id = luaL_checkinteger( L, 1 ); MOD_CHECK_ID( switec, id ); int pin[4]; if (switec_close(id)) { return luaL_error( L, "Unable to setup stepper." ); } int i; for (i = 0; i < 4; i++) { uint32_t gpio = luaL_checkinteger(L, 2 + i); luaL_argcheck(L, platform_gpio_exists(gpio), 2 + i, "Invalid pin"); pin[i] = pin_num[gpio]; platform_gpio_mode(gpio, PLATFORM_GPIO_OUTPUT, PLATFORM_GPIO_PULLUP); } int deg_per_sec = 0; if (lua_gettop(L) >= 6) { deg_per_sec = luaL_checkinteger(L, 6); } if (switec_setup(id, pin, deg_per_sec, tasknumber)) { return luaL_error(L, "Unable to setup stepper."); } return 0; } // Lua: close( id ) static int lswitec_close( lua_State* L ) { unsigned int id; id = luaL_checkinteger( L, 1 ); MOD_CHECK_ID( switec, id ); callback_free(L, id); if (switec_close( id )) { return luaL_error( L, "Unable to close stepper." ); } return 0; } // Lua: reset( id ) static int lswitec_reset( lua_State* L ) { unsigned int id; id = luaL_checkinteger( L, 1 ); MOD_CHECK_ID( switec, id ); if (switec_reset( id )) { return luaL_error( L, "Unable to reset stepper." ); } return 0; } // Lua: moveto( id, pos [, cb] ) static int lswitec_moveto( lua_State* L ) { unsigned int id; id = luaL_checkinteger( L, 1 ); MOD_CHECK_ID( switec, id ); int pos; pos = luaL_checkinteger( L, 2 ); if (lua_gettop(L) >= 3) { callback_set(L, id, 3); } else { callback_free(L, id); } if (switec_moveto( id, pos )) { return luaL_error( L, "Unable to move stepper." ); } return 0; } // Lua: getpos( id ) -> position, moving static int lswitec_getpos( lua_State* L ) { unsigned int id; id = luaL_checkinteger( L, 1 ); MOD_CHECK_ID( switec, id ); int32_t pos; int32_t dir; int32_t target; if (switec_getpos( id, &pos, &dir, &target )) { return luaL_error( L, "Unable to get position." ); } lua_pushinteger(L, pos); lua_pushinteger(L, dir); return 2; } static int lswitec_dequeue(lua_State* L) { int id; for (id = 0; id < SWITEC_CHANNEL_COUNT; id++) { if (stopped_callback[id] != LUA_NOREF) { int32_t pos; int32_t dir; int32_t target; if (!switec_getpos( id, &pos, &dir, &target )) { if (dir == 0 && pos == target) { callback_execute(L, id); } } } } return 0; } static void lswitec_task(os_param_t param, uint8_t prio) { (void) param; (void) prio; lswitec_dequeue(lua_getstate()); } static int switec_open(lua_State *L) { (void) L; tasknumber = task_get_id(lswitec_task); return 0; } // Module function map LROT_BEGIN(switec, NULL, 0) LROT_FUNCENTRY( setup, lswitec_setup ) LROT_FUNCENTRY( close, lswitec_close ) LROT_FUNCENTRY( reset, lswitec_reset ) LROT_FUNCENTRY( moveto, lswitec_moveto ) LROT_FUNCENTRY( getpos, lswitec_getpos ) #ifdef SQITEC_DEBUG LROT_FUNCENTRY( dequeue, lswitec_dequeue ) #endif LROT_END(switec, NULL, 0) NODEMCU_MODULE(SWITEC, "switec", switec, switec_open);