195 lines
5.3 KiB
C
195 lines
5.3 KiB
C
|
#include "platform.h"
|
||
|
#include "driver/uart.h"
|
||
|
#include "driver/input.h"
|
||
|
#include <stdint.h>
|
||
|
#include "mem.h"
|
||
|
|
||
|
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.
|
||
|
*/
|
||
|
extern 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
|
||
|
** or end_char break.
|
||
|
*/
|
||
|
extern 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) ||
|
||
|
(ins.data_len < 0 && ch == ins.end_char )) {
|
||
|
ins.uart_cb(ins.data, ins.line_pos);
|
||
|
ins.line_pos = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|