input.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. #include "platform.h"
  2. #include "driver/uart.h"
  3. #include "driver/input.h"
  4. #include <stdint.h>
  5. #include "mem.h"
  6. static void input_handler(platform_task_param_t flag, uint8 priority);
  7. static struct input_state {
  8. char *data;
  9. int line_pos;
  10. size_t len;
  11. const char *prompt;
  12. uart_cb_t uart_cb;
  13. platform_task_handle_t input_sig;
  14. int data_len;
  15. bool run_input;
  16. bool uart_echo;
  17. char last_char;
  18. char end_char;
  19. uint8 input_sig_flag;
  20. } ins = {0};
  21. #define NUL '\0'
  22. #define BS '\010'
  23. #define CR '\r'
  24. #define LF '\n'
  25. #define DEL 0x7f
  26. #define BS_OVER "\010 \010"
  27. #define sendStr(s) uart0_sendStr(s)
  28. #define putc(c) uart0_putc(c)
  29. // UartDev is defined and initialized in rom code.
  30. extern UartDevice UartDev;
  31. static bool uart_getc(char *c){
  32. RcvMsgBuff *pRxBuff = &(UartDev.rcv_buff);
  33. if(pRxBuff->pWritePos == pRxBuff->pReadPos){ // empty
  34. return false;
  35. }
  36. // ETS_UART_INTR_DISABLE();
  37. ETS_INTR_LOCK();
  38. *c = (char)*(pRxBuff->pReadPos);
  39. if (pRxBuff->pReadPos == (pRxBuff->pRcvMsgBuff + RX_BUFF_SIZE)) {
  40. pRxBuff->pReadPos = pRxBuff->pRcvMsgBuff ;
  41. } else {
  42. pRxBuff->pReadPos++;
  43. }
  44. // ETS_UART_INTR_ENABLE();
  45. ETS_INTR_UNLOCK();
  46. return true;
  47. }
  48. /*
  49. ** input_handler at high-priority is a system post task used to process pending Rx
  50. ** data on UART0. The flag is used as a latch to stop the interrupt handler posting
  51. ** multiple pending requests. At low priority it is used the trigger interactive
  52. ** compile.
  53. **
  54. ** The ins.data check detects up the first task call which used to initialise
  55. ** everything.
  56. */
  57. extern int lua_main (void);
  58. static bool input_readline(void);
  59. static void input_handler(platform_task_param_t flag, uint8 priority) {
  60. (void) priority;
  61. if (!ins.data) {
  62. lua_main();
  63. return;
  64. }
  65. ins.input_sig_flag = flag & 0x1;
  66. while (input_readline()) {}
  67. }
  68. /*
  69. ** The input state (ins) is private, so input_setup() exposes the necessary
  70. ** access to public properties and is called in user_init() before the Lua
  71. ** enviroment is initialised. The second routine input_setup_receive() is
  72. ** called in lua.c after the Lua environment is available to bind the Lua
  73. ** input handler. Any UART input before this receive setup is ignored.
  74. */
  75. void input_setup(int bufsize, const char *prompt) {
  76. // Initialise non-zero elements
  77. ins.run_input = true;
  78. ins.uart_echo = true;
  79. ins.data = os_malloc(bufsize);
  80. ins.len = bufsize;
  81. ins.prompt = prompt;
  82. ins.input_sig = platform_task_get_id(input_handler);
  83. // pass the task CB parameters to the uart driver
  84. uart_init_task(ins.input_sig, &ins.input_sig_flag);
  85. ETS_UART_INTR_ENABLE();
  86. }
  87. void input_setup_receive(uart_cb_t uart_on_data_cb, int data_len, char end_char, bool run_input) {
  88. ins.uart_cb = uart_on_data_cb;
  89. ins.data_len = data_len;
  90. ins.end_char = end_char;
  91. ins.run_input = run_input;
  92. }
  93. void input_setecho (bool flag) {
  94. ins.uart_echo = flag;
  95. }
  96. void input_setprompt (const char *prompt) {
  97. ins.prompt = prompt;
  98. }
  99. /*
  100. ** input_readline() is called from the input_handler() event routine which is
  101. ** posted by the UART Rx ISR posts. This works in one of two modes depending on
  102. ** the bool ins.run_input.
  103. ** - TRUE: it clears the UART FIFO up to EOL, doing any callback and sending
  104. ** the line to Lua.
  105. ** - FALSE: it clears the UART FIFO doing callbacks according to the data_len
  106. ** or end_char break.
  107. */
  108. extern void lua_input_string (const char *line, int len);
  109. static bool input_readline(void) {
  110. char ch = NUL;
  111. if (ins.run_input) {
  112. while (uart_getc(&ch)) {
  113. /* handle CR & LF characters and aggregate \n\r and \r\n pairs */
  114. if ((ch == CR && ins.last_char == LF) ||
  115. (ch == LF && ins.last_char == CR)) {
  116. ins.last_char = NUL;
  117. continue;
  118. }
  119. /* backspace key */
  120. if (ch == DEL || ch == BS) {
  121. if (ins.line_pos > 0) {
  122. if(ins.uart_echo) sendStr(BS_OVER);
  123. ins.line_pos--;
  124. }
  125. ins.data[ins.line_pos] = 0;
  126. ins.last_char = NUL;
  127. continue;
  128. }
  129. ins.last_char = ch;
  130. /* end of data */
  131. if (ch == CR || ch == LF) {
  132. if (ins.uart_echo) putc(LF);
  133. if (ins.uart_cb) ins.uart_cb(ins.data, ins.line_pos);
  134. if (ins.line_pos == 0) {
  135. /* Get a empty data, then go to get a new data */
  136. sendStr(ins.prompt);
  137. continue;
  138. } else {
  139. ins.data[ins.line_pos++] = LF;
  140. lua_input_string(ins.data, ins.line_pos);
  141. ins.line_pos = 0;
  142. return true;
  143. }
  144. }
  145. if(ins.uart_echo) putc(ch);
  146. /* it's a large data, discard it */
  147. if ( ins.line_pos + 1 >= ins.len ){
  148. ins.line_pos = 0;
  149. }
  150. ins.data[ins.line_pos++] = ch;
  151. }
  152. } else {
  153. if (!ins.uart_cb) {
  154. while (uart_getc(&ch)) {}
  155. } else if (ins.data_len == 0) {
  156. while (uart_getc(&ch)) {
  157. ins.uart_cb(&ch, 1);
  158. }
  159. } else {
  160. while (uart_getc(&ch)) {
  161. ins.data[ins.line_pos++] = ch;
  162. if( ins.line_pos >= ins.len ||
  163. (ins.data_len >= 0 && ins.line_pos >= ins.data_len) ||
  164. (ins.data_len < 0 && ch == ins.end_char )) {
  165. ins.uart_cb(ins.data, ins.line_pos);
  166. ins.line_pos = 0;
  167. }
  168. }
  169. }
  170. }
  171. return false;
  172. }