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