switec.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. /*
  2. * Module for interfacing with Switec instrument steppers (and
  3. * similar devices). These are the steppers that are used in automotive
  4. * instrument panels and the like. Run off 5 volts at low current.
  5. *
  6. * Code inspired by:
  7. *
  8. * SwitecX25 Arduino Library
  9. * Guy Carpenter, Clearwater Software - 2012
  10. *
  11. * Licensed under the BSD2 license, see license.txt for details.
  12. *
  13. * NodeMcu integration by Philip Gladstone, N1DQ
  14. */
  15. #include "module.h"
  16. #include "lauxlib.h"
  17. #include "platform.h"
  18. #include <stdint.h>
  19. #include "task/task.h"
  20. #include "driver/switec.h"
  21. // This is the reference to the callbacks for when the pointer
  22. // stops moving.
  23. static int stopped_callback[SWITEC_CHANNEL_COUNT] = { LUA_NOREF, LUA_NOREF, LUA_NOREF };
  24. static task_handle_t tasknumber;
  25. static void callback_free(lua_State* L, unsigned int id)
  26. {
  27. luaL_unref(L, LUA_REGISTRYINDEX, stopped_callback[id]);
  28. stopped_callback[id] = LUA_NOREF;
  29. }
  30. static void callback_set(lua_State* L, unsigned int id, int argNumber)
  31. {
  32. if (lua_isfunction(L, argNumber)) {
  33. lua_pushvalue(L, argNumber); // copy argument (func) to the top of stack
  34. callback_free(L, id);
  35. stopped_callback[id] = luaL_ref(L, LUA_REGISTRYINDEX);
  36. }
  37. }
  38. static void callback_execute(lua_State* L, unsigned int id)
  39. {
  40. if (stopped_callback[id] != LUA_NOREF) {
  41. int callback = stopped_callback[id];
  42. lua_rawgeti(L, LUA_REGISTRYINDEX, callback);
  43. callback_free(L, id);
  44. luaL_pcallx(L, 0, 0);
  45. }
  46. }
  47. int platform_switec_exists( unsigned int id )
  48. {
  49. return (id < SWITEC_CHANNEL_COUNT);
  50. }
  51. // Lua: setup(id, P1, P2, P3, P4, maxSpeed)
  52. static int lswitec_setup( lua_State* L )
  53. {
  54. unsigned int id;
  55. id = luaL_checkinteger( L, 1 );
  56. MOD_CHECK_ID( switec, id );
  57. int pin[4];
  58. if (switec_close(id)) {
  59. return luaL_error( L, "Unable to setup stepper." );
  60. }
  61. int i;
  62. for (i = 0; i < 4; i++) {
  63. uint32_t gpio = luaL_checkinteger(L, 2 + i);
  64. luaL_argcheck(L, platform_gpio_exists(gpio), 2 + i, "Invalid pin");
  65. pin[i] = pin_num[gpio];
  66. platform_gpio_mode(gpio, PLATFORM_GPIO_OUTPUT, PLATFORM_GPIO_PULLUP);
  67. }
  68. int deg_per_sec = 0;
  69. if (lua_gettop(L) >= 6) {
  70. deg_per_sec = luaL_checkinteger(L, 6);
  71. }
  72. if (switec_setup(id, pin, deg_per_sec, tasknumber)) {
  73. return luaL_error(L, "Unable to setup stepper.");
  74. }
  75. return 0;
  76. }
  77. // Lua: close( id )
  78. static int lswitec_close( lua_State* L )
  79. {
  80. unsigned int id;
  81. id = luaL_checkinteger( L, 1 );
  82. MOD_CHECK_ID( switec, id );
  83. callback_free(L, id);
  84. if (switec_close( id )) {
  85. return luaL_error( L, "Unable to close stepper." );
  86. }
  87. return 0;
  88. }
  89. // Lua: reset( id )
  90. static int lswitec_reset( lua_State* L )
  91. {
  92. unsigned int id;
  93. id = luaL_checkinteger( L, 1 );
  94. MOD_CHECK_ID( switec, id );
  95. if (switec_reset( id )) {
  96. return luaL_error( L, "Unable to reset stepper." );
  97. }
  98. return 0;
  99. }
  100. // Lua: moveto( id, pos [, cb] )
  101. static int lswitec_moveto( lua_State* L )
  102. {
  103. unsigned int id;
  104. id = luaL_checkinteger( L, 1 );
  105. MOD_CHECK_ID( switec, id );
  106. int pos;
  107. pos = luaL_checkinteger( L, 2 );
  108. if (lua_gettop(L) >= 3) {
  109. callback_set(L, id, 3);
  110. } else {
  111. callback_free(L, id);
  112. }
  113. if (switec_moveto( id, pos )) {
  114. return luaL_error( L, "Unable to move stepper." );
  115. }
  116. return 0;
  117. }
  118. // Lua: getpos( id ) -> position, moving
  119. static int lswitec_getpos( lua_State* L )
  120. {
  121. unsigned int id;
  122. id = luaL_checkinteger( L, 1 );
  123. MOD_CHECK_ID( switec, id );
  124. int32_t pos;
  125. int32_t dir;
  126. int32_t target;
  127. if (switec_getpos( id, &pos, &dir, &target )) {
  128. return luaL_error( L, "Unable to get position." );
  129. }
  130. lua_pushnumber(L, pos);
  131. lua_pushnumber(L, dir);
  132. return 2;
  133. }
  134. static int lswitec_dequeue(lua_State* L)
  135. {
  136. int id;
  137. for (id = 0; id < SWITEC_CHANNEL_COUNT; id++) {
  138. if (stopped_callback[id] != LUA_NOREF) {
  139. int32_t pos;
  140. int32_t dir;
  141. int32_t target;
  142. if (!switec_getpos( id, &pos, &dir, &target )) {
  143. if (dir == 0 && pos == target) {
  144. callback_execute(L, id);
  145. }
  146. }
  147. }
  148. }
  149. return 0;
  150. }
  151. static void lswitec_task(os_param_t param, uint8_t prio)
  152. {
  153. (void) param;
  154. (void) prio;
  155. lswitec_dequeue(lua_getstate());
  156. }
  157. static int switec_open(lua_State *L)
  158. {
  159. (void) L;
  160. tasknumber = task_get_id(lswitec_task);
  161. return 0;
  162. }
  163. // Module function map
  164. LROT_BEGIN(switec, NULL, 0)
  165. LROT_FUNCENTRY( setup, lswitec_setup )
  166. LROT_FUNCENTRY( close, lswitec_close )
  167. LROT_FUNCENTRY( reset, lswitec_reset )
  168. LROT_FUNCENTRY( moveto, lswitec_moveto )
  169. LROT_FUNCENTRY( getpos, lswitec_getpos )
  170. #ifdef SQITEC_DEBUG
  171. LROT_FUNCENTRY( dequeue, lswitec_dequeue )
  172. #endif
  173. LROT_END(switec, NULL, 0)
  174. NODEMCU_MODULE(SWITEC, "switec", switec, switec_open);