softuart.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440
  1. #include "ets_sys.h"
  2. #include "osapi.h"
  3. #include "gpio.h"
  4. #include "os_type.h"
  5. #include "user_interface.h"
  6. #include "module.h"
  7. #include "lauxlib.h"
  8. #include "task/task.h"
  9. #include "platform.h"
  10. #include <stdlib.h>
  11. #include <string.h>
  12. #define SOFTUART_MAX_RX_BUFF 128
  13. #define SOFTUART_GPIO_COUNT 13
  14. //TODO: Overflow flag as callback function + docs
  15. typedef struct {
  16. char receive_buffer[SOFTUART_MAX_RX_BUFF];
  17. uint8_t buffer_first;
  18. uint8_t buffer_last;
  19. uint8_t bytes_count;
  20. uint8_t buffer_overflow;
  21. } softuart_buffer_t;
  22. typedef struct {
  23. uint8_t pin_rx;
  24. uint8_t pin_tx;
  25. volatile softuart_buffer_t buffer;
  26. uint16_t bit_time;
  27. uint16_t need_len; // Buffer length needed to run callback function
  28. char end_char; // Used to run callback if last char in buffer will be the same
  29. uint8_t armed;
  30. } softuart_t;
  31. typedef struct {
  32. softuart_t *softuart;
  33. } softuart_userdata;
  34. // Array of pointers to SoftUART instances
  35. softuart_t * softuart_gpio_instances[SOFTUART_GPIO_COUNT] = {NULL};
  36. // Array of callback reference to be able to find which callback is used to which rx pin
  37. static int softuart_rx_cb_ref[SOFTUART_GPIO_COUNT];
  38. // Task for receiving data
  39. static task_handle_t uart_recieve_task = 0;
  40. // Receiving buffer for callback usage
  41. static char softuart_rx_buffer[SOFTUART_MAX_RX_BUFF];
  42. static inline int32_t asm_ccount(void) {
  43. int32_t r;
  44. asm volatile ("rsr %0, ccount" : "=r"(r));
  45. return r;
  46. }
  47. static inline uint8_t checkbit(uint8_t data, uint8_t bit)
  48. {
  49. if ((data & bit) != 0) {
  50. return 1;
  51. } else {
  52. return 0;
  53. }
  54. }
  55. uint32_t ICACHE_RAM_ATTR softuart_intr_handler(uint32_t ret_gpio_status)
  56. {
  57. // Disable all interrupts
  58. ets_intr_lock();
  59. int32_t start_time = asm_ccount();
  60. uint32_t gpio_status = GPIO_REG_READ(GPIO_STATUS_ADDRESS);
  61. uint32_t gpio_bits = gpio_status;
  62. for (uint8_t gpio_bit = 0; gpio_bits != 0; gpio_bit++, gpio_bits >>= 1) {
  63. // Check all pins for interrupts
  64. if (! (gpio_bits & 0x01)) continue;
  65. // We got pin that was interrupted
  66. // Load instance which has rx pin on interrupt pin attached
  67. softuart_t *s = softuart_gpio_instances[pin_num_inv[gpio_bit]];
  68. if (s == NULL) continue;
  69. if (softuart_rx_cb_ref[pin_num_inv[gpio_bit]] == LUA_NOREF) continue;
  70. if (!s->armed) continue;
  71. // There is SoftUART rx instance on that pin
  72. // Clear interrupt status on that pin
  73. GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, gpio_status & (1 << pin_num[s->pin_rx]));
  74. ret_gpio_status &= ~(1 << pin_num[s->pin_rx]);
  75. // Start listening to transmission
  76. // TODO: inverted
  77. if (! (GPIO_INPUT_GET(GPIO_ID_PIN(pin_num[s->pin_rx])))) {
  78. //pin is low - therefore we have a start bit
  79. unsigned byte = 0;
  80. // Casting and using signed types to always be able to compute elapsed time even if there is a overflow
  81. uint32_t elapsed_time = (uint32_t)(asm_ccount() - start_time);
  82. // Wait till start bit is half over so we can sample the next one in the center
  83. if (elapsed_time < s->bit_time / 2) {
  84. uint16_t wait_time = s->bit_time / 2 - elapsed_time;
  85. while ((uint32_t)(asm_ccount() - start_time) < wait_time);
  86. start_time += wait_time;
  87. }
  88. // Sample bits
  89. // TODO: How many bits? Add other configs to softuart
  90. for (uint8_t i = 0; i < 8; i ++ ) {
  91. while ((uint32_t)(asm_ccount() - start_time) < s->bit_time);
  92. //shift d to the right
  93. byte >>= 1;
  94. // Read bit
  95. if(GPIO_INPUT_GET(GPIO_ID_PIN(pin_num[s->pin_rx]))) {
  96. // If high, set msb of 8bit to 1
  97. byte |= 0x80;
  98. }
  99. // Recalculate start time for next bit
  100. start_time += s->bit_time;
  101. }
  102. // Store byte in buffer
  103. // If buffer full, set the overflow flag and return
  104. if (s->buffer.bytes_count == SOFTUART_MAX_RX_BUFF) {
  105. s->buffer.buffer_overflow = 1;
  106. } else if (s->buffer.bytes_count < SOFTUART_MAX_RX_BUFF) {
  107. s->buffer.receive_buffer[s->buffer.buffer_last] = byte;
  108. s->buffer.buffer_last++;
  109. s->buffer.bytes_count++;
  110. // Check for callback conditions
  111. if (((s->need_len != 0) && (s->buffer.bytes_count >= s->need_len)) || \
  112. ((s->need_len == 0) && ((char)byte == s->end_char))) {
  113. // Send the pointer to task handler
  114. s->armed = 0;
  115. task_post_low(uart_recieve_task, (task_param_t)s);
  116. }
  117. }
  118. // Check for overflow after appending new byte
  119. if (s->buffer.bytes_count == SOFTUART_MAX_RX_BUFF) {
  120. s->buffer.buffer_overflow = 1;
  121. }
  122. // Roll over buffer index if necessary
  123. if (s->buffer.buffer_last == SOFTUART_MAX_RX_BUFF) {
  124. s->buffer.buffer_last = 0;
  125. }
  126. // Wait for stop bit
  127. // TODO: Add config for stop bits and parity bits
  128. while ((uint32_t)(asm_ccount() - start_time) < s->bit_time);
  129. }
  130. }
  131. // re-enable all interrupts
  132. ets_intr_unlock();
  133. return ret_gpio_status;
  134. }
  135. static void softuart_putchar(softuart_t *s, char data)
  136. {
  137. // Disable all interrupts
  138. ets_intr_lock();
  139. int32_t start_time = asm_ccount();
  140. // Set start bit
  141. GPIO_OUTPUT_SET(GPIO_ID_PIN(pin_num[s->pin_tx]), 0);
  142. for (uint32_t i = 0; i < 8; i++) {
  143. while ((uint32_t)(asm_ccount() - start_time) < s->bit_time);
  144. GPIO_OUTPUT_SET(GPIO_ID_PIN(pin_num[s->pin_tx]), checkbit(data, 1 << i));
  145. // Recalculate start time for next bit
  146. start_time += s->bit_time;
  147. }
  148. // Stop bit
  149. while ((uint32_t)(asm_ccount() - start_time) < s->bit_time);
  150. GPIO_OUTPUT_SET(GPIO_ID_PIN(pin_num[s->pin_tx]), 1);
  151. // Delay after byte, for new sync
  152. os_delay_us(s->bit_time*6 / system_get_cpu_freq());
  153. // Re-enable all interrupts
  154. ets_intr_unlock();
  155. }
  156. static void softuart_init(softuart_t *s)
  157. {
  158. NODE_DBG("SoftUART initialize gpio\n");
  159. // Init tx pin
  160. if (s->pin_tx != 0xFF){
  161. platform_gpio_mode(s->pin_tx, PLATFORM_GPIO_OUTPUT, PLATFORM_GPIO_PULLUP);
  162. platform_gpio_write(s->pin_tx, PLATFORM_GPIO_HIGH);
  163. }
  164. // Init rx pin
  165. if (s->pin_rx != 0xFF){
  166. platform_gpio_mode(s->pin_rx, PLATFORM_GPIO_INT, PLATFORM_GPIO_PULLUP);
  167. uint32_t mask = 1 << pin_num[s->pin_rx];
  168. platform_gpio_register_intr_hook(mask, softuart_intr_handler);
  169. softuart_gpio_instances[s->pin_rx] = s;
  170. // Enable interrupt for pin on falling edge
  171. platform_gpio_intr_init(s->pin_rx, GPIO_PIN_INTR_NEGEDGE);
  172. }
  173. }
  174. static int softuart_setup(lua_State *L)
  175. {
  176. uint32_t baudrate;
  177. uint8_t tx_gpio_id, rx_gpio_id;
  178. uint8_t stack = 1;
  179. softuart_userdata *suart = NULL;
  180. NODE_DBG("SoftUART setup called\n");
  181. if(lua_isnumber(L, stack)) {
  182. baudrate = (uint32_t)luaL_checkinteger( L, stack);
  183. //230400 Is the max baudrate the author of Arduino-Esp8266-Software-UART tested
  184. if (baudrate <= 0 || baudrate > 230400) {
  185. return luaL_error(L, "Invalid baud rate" );
  186. }
  187. stack++;
  188. } else {
  189. return luaL_error(L, "Invalid argument type");
  190. }
  191. if(lua_isnumber(L, stack)) {
  192. tx_gpio_id = (uint8_t)luaL_checkinteger( L, stack);
  193. if (!platform_gpio_exists(tx_gpio_id) || tx_gpio_id == 0) {
  194. return luaL_error(L, "SoftUART tx GPIO not valid");
  195. }
  196. stack++;
  197. } else {
  198. tx_gpio_id = 0xFF;
  199. stack++;
  200. }
  201. if (lua_isnumber(L, stack)) {
  202. rx_gpio_id = (uint8_t)luaL_checkinteger( L, stack);
  203. if (!platform_gpio_exists(rx_gpio_id) || rx_gpio_id == 0) {
  204. return luaL_error(L, "SoftUART rx GPIO not valid");
  205. }
  206. if (softuart_gpio_instances[rx_gpio_id] != NULL) {
  207. return luaL_error( L, "SoftUART rx already configured on the pin.");
  208. }
  209. } else {
  210. rx_gpio_id = 0xFF;
  211. }
  212. suart = (softuart_userdata*)lua_newuserdata(L, sizeof(softuart_userdata));
  213. suart->softuart = malloc(sizeof(softuart_t));
  214. if (!suart->softuart) {
  215. free(suart->softuart);
  216. suart->softuart = NULL;
  217. return luaL_error(L, "Not enough memory");
  218. }
  219. suart->softuart->pin_rx = rx_gpio_id;
  220. suart->softuart->pin_tx = tx_gpio_id;
  221. suart->softuart->need_len = RX_BUFF_SIZE;
  222. suart->softuart->armed = 0;
  223. // Set buffer
  224. suart->softuart->buffer.buffer_first = 0;
  225. suart->softuart->buffer.buffer_last = 0;
  226. suart->softuart->buffer.bytes_count = 0;
  227. suart->softuart->buffer.buffer_overflow = 0;
  228. // Set bit time
  229. suart->softuart->bit_time = system_get_cpu_freq() * 1000000 / baudrate;
  230. // Set metatable
  231. luaL_getmetatable(L, "softuart.port");
  232. lua_setmetatable(L, -2);
  233. // Init SoftUART
  234. softuart_init(suart->softuart);
  235. return 1;
  236. }
  237. static void softuart_rx_callback(task_param_t arg)
  238. {
  239. softuart_t *softuart = (softuart_t*)arg; //Receive pointer from ISR
  240. lua_State *L = lua_getstate();
  241. lua_rawgeti(L, LUA_REGISTRYINDEX, softuart_rx_cb_ref[softuart->pin_rx]);
  242. // Clear overflow flag if needed
  243. if(softuart->buffer.bytes_count == SOFTUART_MAX_RX_BUFF) {
  244. softuart->buffer.buffer_overflow = 0;
  245. }
  246. // Copy volatile data to static buffer
  247. uint8_t buffer_lenght = softuart->buffer.bytes_count;
  248. for (int i = 0; i < buffer_lenght; i++) {
  249. softuart_rx_buffer[i] = softuart->buffer.receive_buffer[softuart->buffer.buffer_first];
  250. softuart->buffer.buffer_first++;
  251. softuart->buffer.bytes_count--;
  252. if (softuart->buffer.buffer_first == SOFTUART_MAX_RX_BUFF) {
  253. softuart->buffer.buffer_first = 0;
  254. }
  255. }
  256. lua_pushlstring(L, softuart_rx_buffer, buffer_lenght);
  257. softuart->armed = 1;
  258. luaL_pcallx(L, 1, 0);
  259. }
  260. // Arguments: event name, minimum buffer filled to run callback, callback function
  261. static int softuart_on(lua_State *L)
  262. {
  263. NODE_DBG("SoftUART on called\n");
  264. softuart_userdata *suart = NULL;
  265. size_t name_len, arg_len;
  266. uint8_t stack = 1;
  267. suart = (softuart_userdata *)luaL_checkudata(L, 1, "softuart.port");
  268. luaL_argcheck(L, suart, stack, "softuart.port expected");
  269. if (suart == NULL) {
  270. NODE_DBG("Userdata is nil\n");
  271. return 0;
  272. }
  273. stack++;
  274. const char *method = luaL_checklstring(L, stack, &name_len);
  275. if (method == NULL)
  276. return luaL_error(L, "Wrong argument type");
  277. stack++;
  278. if (lua_type(L, stack) == LUA_TNUMBER) {
  279. suart->softuart->need_len = (uint16_t)luaL_checkinteger( L, stack );
  280. stack++;
  281. suart->softuart->end_char = 0;
  282. if (suart->softuart->need_len > SOFTUART_MAX_RX_BUFF) {
  283. suart->softuart->need_len = 0;
  284. return luaL_error(L, "Argument bigger than SoftUART buffer");
  285. }
  286. suart->softuart->armed = 1;
  287. } else if (lua_isstring(L, stack)) {
  288. const char *end = luaL_checklstring(L , stack, &arg_len);
  289. stack++;
  290. if ( arg_len != 1) {
  291. return luaL_error(L, "Wrong end char length");
  292. }
  293. suart->softuart->end_char = end[0];
  294. suart->softuart->need_len = 0;
  295. suart->softuart->armed = 1;
  296. } else {
  297. return luaL_error(L, "Wrong argument type");
  298. }
  299. if (lua_type(L, stack) == LUA_TFUNCTION) {
  300. lua_pushvalue(L, stack); // Copy to top of the stack
  301. } else {
  302. lua_pushnil(L);
  303. }
  304. if (name_len == 4 && strcmp(method, "data") == 0) {
  305. if(suart->softuart->pin_rx == 0xFF) {
  306. return luaL_error(L, "Rx pin was not declared");
  307. }
  308. if (softuart_rx_cb_ref[suart->softuart->pin_rx] != LUA_NOREF) {
  309. luaL_unref(L, LUA_REGISTRYINDEX, softuart_rx_cb_ref[suart->softuart->pin_rx]);
  310. softuart_rx_cb_ref[suart->softuart->pin_rx] = LUA_NOREF;
  311. }
  312. if (! lua_isnil(L, -1)) {
  313. softuart_rx_cb_ref[suart->softuart->pin_rx] = luaL_ref(L, LUA_REGISTRYINDEX);
  314. } else {
  315. lua_pop(L, 1);
  316. }
  317. } else {
  318. lua_pop(L, 1);
  319. return luaL_error(L, "Method not supported");
  320. }
  321. return 0;
  322. }
  323. static int softuart_write(lua_State *L)
  324. {
  325. NODE_DBG("SoftUART write called\n");
  326. softuart_userdata *suart = NULL;
  327. uint8_t stack = 1;
  328. size_t str_len;
  329. suart = (softuart_userdata *)luaL_checkudata(L, 1, "softuart.port");
  330. luaL_argcheck(L, suart, stack, "softuart.port expected");
  331. if (suart == NULL) {
  332. NODE_DBG("Userdata is nil\n");
  333. return 0;
  334. }
  335. stack++;
  336. if(suart->softuart->pin_tx == 0xFF) {
  337. return luaL_error(L, "Tx pin was not declared");
  338. }
  339. if (lua_type(L, stack) == LUA_TNUMBER) {
  340. // Send byte
  341. uint32_t byte = (uint32_t)luaL_checkinteger( L, stack );
  342. if (byte > 255) {
  343. return luaL_error(L, "Integer too large for a byte");
  344. }
  345. softuart_putchar(suart->softuart, (char)byte);
  346. } else if (lua_isstring(L, stack)) {
  347. // Send string
  348. const char *string = luaL_checklstring(L , stack, &str_len);
  349. for (size_t i = 0; i < str_len; i++) {
  350. softuart_putchar(suart->softuart, string[i]);
  351. }
  352. } else {
  353. return luaL_error(L, "Wrong argument type");
  354. }
  355. return 0;
  356. }
  357. static int softuart_gcdelete(lua_State *L)
  358. {
  359. NODE_DBG("SoftUART GC called\n");
  360. softuart_userdata *suart = NULL;
  361. suart = (softuart_userdata *)luaL_checkudata(L, 1, "softuart.port");
  362. luaL_argcheck(L, suart, 1, "softuart.port expected");
  363. if (suart == NULL) {
  364. NODE_DBG("Userdata is nil\n");
  365. return 0;
  366. }
  367. softuart_gpio_instances[suart->softuart->pin_rx] = NULL;
  368. luaL_unref(L, LUA_REGISTRYINDEX, softuart_rx_cb_ref[suart->softuart->pin_rx]);
  369. softuart_rx_cb_ref[suart->softuart->pin_rx] = LUA_NOREF;
  370. free(suart->softuart);
  371. return 0;
  372. }
  373. // Port function map
  374. LROT_BEGIN(softuart_port, NULL, LROT_MASK_GC_INDEX)
  375. LROT_FUNCENTRY( __gc, softuart_gcdelete)
  376. LROT_TABENTRY( __index, softuart_port)
  377. LROT_FUNCENTRY( on, softuart_on)
  378. LROT_FUNCENTRY( write, softuart_write)
  379. LROT_END(softuart_port, NULL, LROT_MASK_GC_INDEX)
  380. // Module function map
  381. LROT_BEGIN(softuart, LROT_TABLEREF(softuart_port), 0)
  382. LROT_FUNCENTRY( setup, softuart_setup)
  383. LROT_END(softuart, LROT_TABLEREF(softuart_port), 0)
  384. static int luaopen_softuart(lua_State *L)
  385. {
  386. for(int i = 0; i < SOFTUART_GPIO_COUNT; i++) {
  387. softuart_rx_cb_ref[i] = LUA_NOREF;
  388. }
  389. uart_recieve_task = task_get_id((task_callback_t) softuart_rx_callback);
  390. luaL_rometatable(L, "softuart.port", LROT_TABLEREF(softuart_port));
  391. return 0;
  392. }
  393. NODEMCU_MODULE(SOFTUART, "softuart", softuart, luaopen_softuart);