dcc.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. // NodeMCU Lua port by @voborsky
  2. // Module for handling NMRA DCC protocol
  3. // #define NODE_DEBUG
  4. #include "module.h"
  5. #include "lauxlib.h"
  6. #include "platform.h"
  7. #include "driver/NmraDcc.h"
  8. #ifdef LUA_USE_MODULES_DCC
  9. #if !defined(GPIO_INTERRUPT_ENABLE) || !defined(GPIO_INTERRUPT_HOOK_ENABLE)
  10. #error Must have GPIO_INTERRUPT and GPIO_INTERRUPT_HOOK if using DCC module
  11. #endif
  12. #endif
  13. #define TYPE "Type"
  14. #define OPERATION "Operation"
  15. static inline void register_lua_cb(lua_State* L,int* cb_ref){
  16. int ref=luaL_ref(L, LUA_REGISTRYINDEX);
  17. if( *cb_ref != LUA_NOREF){
  18. luaL_unref(L, LUA_REGISTRYINDEX, *cb_ref);
  19. }
  20. *cb_ref = ref;
  21. }
  22. static inline void unregister_lua_cb(lua_State* L, int* cb_ref){
  23. if(*cb_ref != LUA_NOREF){
  24. luaL_unref(L, LUA_REGISTRYINDEX, *cb_ref);
  25. *cb_ref = LUA_NOREF;
  26. }
  27. }
  28. static int notify_cb = LUA_NOREF;
  29. static int CV_cb = LUA_NOREF;
  30. // DCC commands
  31. void cbInit(lua_State* L, uint16_t command) {
  32. if(notify_cb == LUA_NOREF)
  33. return;
  34. lua_rawgeti(L, LUA_REGISTRYINDEX, notify_cb);
  35. lua_pushinteger(L, command);
  36. lua_newtable(L);
  37. }
  38. void cbAddFieldInteger(lua_State* L, uint16_t Value, char *Field) {
  39. lua_pushinteger(L, Value);
  40. lua_setfield(L, -2, Field);
  41. }
  42. void notifyDccReset(uint8_t hardReset ) {
  43. lua_State* L = lua_getstate();
  44. cbInit(L, DCC_RESET);
  45. cbAddFieldInteger(L, hardReset, "hardReset");
  46. luaL_pcallx(L, 2, 0);
  47. }
  48. void notifyDccIdle(void) {
  49. lua_State* L = lua_getstate();
  50. cbInit(L, DCC_IDLE);
  51. luaL_pcallx(L, 2, 0);
  52. }
  53. void notifyDccSpeed( uint16_t Addr, DCC_ADDR_TYPE AddrType, uint8_t Speed, DCC_DIRECTION Dir, DCC_SPEED_STEPS SpeedSteps ) {
  54. lua_State* L = lua_getstate();
  55. cbInit(L, DCC_SPEED);
  56. cbAddFieldInteger(L, Addr, "Addr");
  57. cbAddFieldInteger(L, AddrType, "AddrType");
  58. cbAddFieldInteger(L, Speed, "Speed");
  59. cbAddFieldInteger(L, Dir, "Dir");
  60. cbAddFieldInteger(L, SpeedSteps, "SpeedSteps");
  61. luaL_pcallx(L, 2, 0);
  62. }
  63. void notifyDccSpeedRaw( uint16_t Addr, DCC_ADDR_TYPE AddrType, uint8_t Raw) {
  64. lua_State* L = lua_getstate();
  65. cbInit(L, DCC_SPEED_RAW);
  66. cbAddFieldInteger(L, Addr, "Addr");
  67. cbAddFieldInteger(L, AddrType, "AddrType");
  68. cbAddFieldInteger(L, Raw, "Raw");
  69. luaL_pcallx(L, 2, 0);
  70. }
  71. void notifyDccFunc( uint16_t Addr, DCC_ADDR_TYPE AddrType, FN_GROUP FuncGrp, uint8_t FuncState) {
  72. lua_State* L = lua_getstate();
  73. cbInit(L, DCC_FUNC);
  74. cbAddFieldInteger(L, Addr, "Addr");
  75. cbAddFieldInteger(L, AddrType, "AddrType");
  76. cbAddFieldInteger(L, FuncGrp, "FuncGrp");
  77. cbAddFieldInteger(L, FuncState, "FuncState");
  78. luaL_pcallx(L, 2, 0);
  79. }
  80. void notifyDccAccTurnoutBoard( uint16_t BoardAddr, uint8_t OutputPair, uint8_t Direction, uint8_t OutputPower ) {
  81. lua_State* L = lua_getstate();
  82. cbInit(L, DCC_TURNOUT);
  83. cbAddFieldInteger(L, BoardAddr, "BoardAddr");
  84. cbAddFieldInteger(L, OutputPair, "OutputPair");
  85. cbAddFieldInteger(L, Direction, "Direction");
  86. cbAddFieldInteger(L, OutputPower, "OutputPower");
  87. luaL_pcallx(L, 2, 0);
  88. }
  89. void notifyDccAccTurnoutOutput( uint16_t Addr, uint8_t Direction, uint8_t OutputPower ) {
  90. lua_State* L = lua_getstate();
  91. cbInit(L, DCC_TURNOUT);
  92. cbAddFieldInteger(L, Addr, "Addr");
  93. cbAddFieldInteger(L, Direction, "Direction");
  94. cbAddFieldInteger(L, OutputPower, "OutputPower");
  95. luaL_pcallx(L, 2, 0);
  96. }
  97. void notifyDccAccBoardAddrSet( uint16_t BoardAddr) {
  98. lua_State* L = lua_getstate();
  99. cbInit(L, DCC_ACCESSORY);
  100. cbAddFieldInteger(L, BoardAddr, "BoardAddr");
  101. luaL_pcallx(L, 2, 0);
  102. }
  103. void notifyDccAccOutputAddrSet( uint16_t Addr) {
  104. lua_State* L = lua_getstate();
  105. cbInit(L, DCC_ACCESSORY);
  106. cbAddFieldInteger(L, Addr, "Addr");
  107. luaL_pcallx(L, 2, 0);
  108. }
  109. void notifyDccSigOutputState( uint16_t Addr, uint8_t State) {
  110. lua_State* L = lua_getstate();
  111. cbInit(L, DCC_ACCESSORY);
  112. cbAddFieldInteger(L, State, "State");
  113. luaL_pcallx(L, 2, 0);
  114. }
  115. void notifyDccMsg( DCC_MSG * Msg ) {
  116. lua_State* L = lua_getstate();
  117. cbInit(L, DCC_RAW);
  118. cbAddFieldInteger(L, Msg->Size, "Size");
  119. cbAddFieldInteger(L, Msg->PreambleBits, "PreambleBits");
  120. char field[8];
  121. for(uint8_t i = 0; i< MAX_DCC_MESSAGE_LEN; i++ ) {
  122. ets_sprintf(field, "Data%d", i);
  123. cbAddFieldInteger(L, Msg->Data[i], field);
  124. }
  125. luaL_pcallx(L, 2, 0);
  126. }
  127. void notifyServiceMode(bool InServiceMode){
  128. lua_State* L = lua_getstate();
  129. cbInit(L, DCC_SERVICEMODE);
  130. cbAddFieldInteger(L, InServiceMode, "InServiceMode");
  131. luaL_pcallx(L, 2, 0);
  132. }
  133. // CV handling
  134. uint8_t notifyCVValid( uint16_t CV, uint8_t Writable ) {
  135. lua_State* L = lua_getstate();
  136. if(notify_cb == LUA_NOREF)
  137. return 0;
  138. lua_rawgeti(L, LUA_REGISTRYINDEX, CV_cb);
  139. lua_pushinteger(L, CV_VALID);
  140. lua_newtable(L);
  141. cbAddFieldInteger(L, CV, "CV");
  142. cbAddFieldInteger(L, Writable, "Writable");
  143. if (luaL_pcallx(L, 2, 1) != LUA_OK)
  144. return 0;
  145. uint8 result = lua_tointeger(L, -1);
  146. lua_pop(L, 1);
  147. return result;
  148. }
  149. uint8_t notifyCVRead( uint16_t CV) {
  150. lua_State* L = lua_getstate();
  151. if(notify_cb == LUA_NOREF)
  152. return 0;
  153. lua_rawgeti(L, LUA_REGISTRYINDEX, CV_cb);
  154. lua_pushinteger(L, CV_READ);
  155. lua_newtable(L);
  156. cbAddFieldInteger(L, CV, "CV");
  157. if (luaL_pcallx(L, 2, 1) != LUA_OK)
  158. return 0;;
  159. uint8 result = lua_tointeger(L, -1);
  160. lua_pop(L, 1);
  161. return result;
  162. }
  163. uint8_t notifyCVWrite( uint16_t CV, uint8_t Value) {
  164. lua_State* L = lua_getstate();
  165. if(notify_cb == LUA_NOREF)
  166. return 0;
  167. lua_rawgeti(L, LUA_REGISTRYINDEX, CV_cb);
  168. lua_pushinteger(L, CV_WRITE);
  169. lua_newtable(L);
  170. cbAddFieldInteger(L, CV, "CV");
  171. cbAddFieldInteger(L, Value, "Value");
  172. luaL_pcallx(L, 2, 0);
  173. return Value;
  174. }
  175. void notifyCVResetFactoryDefault(void) {
  176. lua_State* L = lua_getstate();
  177. if(notify_cb == LUA_NOREF)
  178. return;
  179. lua_rawgeti(L, LUA_REGISTRYINDEX, CV_cb);
  180. lua_pushinteger(L, CV_RESET);
  181. luaL_pcallx(L, 1, 0);
  182. }
  183. static int dcc_lua_setup(lua_State* L) {
  184. NODE_DBG("[dcc_lua_setup]\n");
  185. if (!lua_isnumber(L, 6) && !lua_isnumber(L, 7)) {
  186. return luaL_error(L, "wrong arg range");
  187. }
  188. uint8_t pin = luaL_checkinteger(L, 1);
  189. luaL_argcheck(L, platform_gpio_exists(pin) && pin>0, 1, "Invalid interrupt pin");
  190. if (lua_type(L, 2) == LUA_TFUNCTION)
  191. {
  192. lua_pushvalue(L, 2);
  193. register_lua_cb(L, &notify_cb);
  194. }
  195. else
  196. {
  197. unregister_lua_cb(L, &notify_cb);
  198. }
  199. uint8_t ManufacturerId = luaL_checkinteger(L, 3);
  200. uint8_t VersionId = luaL_checkinteger(L, 4);
  201. uint8_t Flags = luaL_checkinteger(L, 5);
  202. uint8_t OpsModeAddressBaseCV = luaL_checkinteger(L, 6);
  203. if (lua_type(L, 7) == LUA_TFUNCTION)
  204. {
  205. lua_pushvalue(L, 7);
  206. register_lua_cb(L, &CV_cb);
  207. }
  208. else
  209. {
  210. unregister_lua_cb(L, &CV_cb);
  211. }
  212. NODE_DBG("[dcc_lua_setup] Enabling interrupt on PIN %d\n", pin);
  213. dcc_setup(pin, ManufacturerId, VersionId, Flags, OpsModeAddressBaseCV );
  214. return 0;
  215. }
  216. static int dcc_lua_close(lua_State* L) {
  217. dcc_close();
  218. unregister_lua_cb(L, &notify_cb);
  219. return 0;
  220. }
  221. int luaopen_dcc( lua_State *L ) {
  222. NODE_DBG("[dcc_luaopen]\n");
  223. dcc_init();
  224. //DccRx.lua_cb_ref = LUA_NOREF;
  225. return 0;
  226. }
  227. // Module function map
  228. LROT_BEGIN(dcc, NULL, 0)
  229. LROT_FUNCENTRY( setup, dcc_lua_setup )
  230. LROT_FUNCENTRY( close, dcc_lua_close )
  231. LROT_NUMENTRY( DCC_RESET, DCC_RESET )
  232. LROT_NUMENTRY( DCC_IDLE, DCC_IDLE )
  233. LROT_NUMENTRY( DCC_SPEED, DCC_SPEED )
  234. LROT_NUMENTRY( DCC_SPEED_RAW, DCC_SPEED_RAW )
  235. LROT_NUMENTRY( DCC_FUNC, DCC_FUNC )
  236. LROT_NUMENTRY( DCC_TURNOUT, DCC_TURNOUT )
  237. LROT_NUMENTRY( DCC_ACCESSORY, DCC_ACCESSORY )
  238. LROT_NUMENTRY( DCC_RAW, DCC_RAW )
  239. LROT_NUMENTRY( DCC_SERVICEMODE, DCC_SERVICEMODE )
  240. LROT_NUMENTRY( CV_VALID, CV_VALID )
  241. LROT_NUMENTRY( CV_READ, CV_READ )
  242. LROT_NUMENTRY( CV_WRITE, CV_WRITE )
  243. LROT_NUMENTRY( CV_RESET, CV_RESET )
  244. LROT_NUMENTRY( MAN_ID_JMRI, MAN_ID_JMRI)
  245. LROT_NUMENTRY( MAN_ID_DIY, MAN_ID_DIY)
  246. LROT_NUMENTRY( MAN_ID_SILICON_RAILWAY, MAN_ID_SILICON_RAILWAY)
  247. LROT_NUMENTRY( FLAGS_MY_ADDRESS_ONLY, FLAGS_MY_ADDRESS_ONLY )
  248. LROT_NUMENTRY( FLAGS_AUTO_FACTORY_DEFAULT, FLAGS_AUTO_FACTORY_DEFAULT )
  249. LROT_NUMENTRY( FLAGS_OUTPUT_ADDRESS_MODE, FLAGS_OUTPUT_ADDRESS_MODE )
  250. LROT_NUMENTRY( FLAGS_DCC_ACCESSORY_DECODER, FLAGS_DCC_ACCESSORY_DECODER )
  251. LROT_END(dcc, NULL, 0)
  252. NODEMCU_MODULE(DCC, "dcc", dcc, luaopen_dcc);