617 lines
13 KiB
C
617 lines
13 KiB
C
/*
|
|
* Author: Chandra Mohan C (willvalab@gmail.com)
|
|
* All rights reserved.
|
|
*
|
|
* Use of this source code is governed by a MIT-style license that can be found
|
|
* in the LICENSE file.
|
|
*
|
|
**-----------------------------------------------*/
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <stddef.h>
|
|
#include <stdarg.h>
|
|
|
|
#include "./uartshConfig.h"
|
|
#include "./uartsh.h"
|
|
/*-----------------------------------------------*/
|
|
|
|
#define HISTORY_COUNT (UARTSH_CONFIG_COMMAND_HISTORY_COUNT + 1)
|
|
|
|
#define KEY_BS 0X08
|
|
#define KEY_DEL 0X7F
|
|
#define KEY_ESC_SEQ1 0X1B
|
|
#define KEY_SPECIAL_UP 'A'
|
|
#define KEY_SPECIAL_DOWN 'B'
|
|
#define KEY_SPECIAL_LEFT 'D'
|
|
#define KEY_SPECIAL_RIGHT 'C'
|
|
#define KEY_ESC_SEQ2 '['
|
|
#define KEY_ESC_SEQ3 '3'
|
|
#define KEY_ESC_SEQ4 '~'
|
|
|
|
#define FLAG_ESC_SEQ1 1
|
|
#define FLAG_ESC_SEQ2 2
|
|
#define FLAG_ESC_SEQ3 3
|
|
/*-----------------------------------------------*/
|
|
|
|
struct UartshEditBuffer
|
|
{
|
|
int cCount;
|
|
char buffer[UARTSH_CONFIG_COMMAND_STRING_SIZE];
|
|
};
|
|
|
|
/*-----------------------------------------------*/
|
|
#include "hal_api.h"
|
|
|
|
#define UARTSH_DEFAULT_TIMEOUT 60000
|
|
#define UARTSH_CMD_TIMEOUT 60000*2
|
|
|
|
|
|
void *g_uartsh_mutex = NULL;
|
|
|
|
static int uart_putchar(sh_cust_type_t *cust_sh, int charx)
|
|
{
|
|
return cust_sh->write_func(cust_sh->handler,(unsigned char *)&charx,1,100);
|
|
}
|
|
|
|
static char uart_getchar(sh_cust_type_t *cust_sh)
|
|
{
|
|
char charx=0;
|
|
int ret;
|
|
|
|
do{
|
|
if(cust_sh->run_flag==1){
|
|
break;
|
|
}
|
|
ret=cust_sh->read_func(cust_sh->handler,(unsigned char *)&charx,1,100);
|
|
if(ret==1){
|
|
//cust_sh->time_out_uptime = hal_os_up_time_ms();
|
|
break;
|
|
}
|
|
if(ret<0){
|
|
hal_os_task_sleep_ms(100);
|
|
}else{
|
|
hal_os_task_sleep_ms(10);
|
|
}
|
|
|
|
if((cust_sh->timeout_enable)&&(hal_os_up_time_ms() - cust_sh->time_out_uptime > cust_sh->time_out)){
|
|
cust_sh->run_flag = 1;
|
|
break;
|
|
}
|
|
}while(ret!=1);
|
|
|
|
return charx;
|
|
}
|
|
|
|
void uartsh_puts(sh_cust_type_t *cust_sh, char const* s)
|
|
{
|
|
if(cust_sh->handler==NULL)return;
|
|
#if 0
|
|
char c = 0;
|
|
|
|
while( (c = *s++) )
|
|
{
|
|
uart_putchar(c);
|
|
}
|
|
#else
|
|
int len = strlen(s);
|
|
if(s[len-2]!='\r' && s[len-1]== '\n'){
|
|
cust_sh->write_func(cust_sh->handler,(unsigned char *)s,strlen(s)-1,1000);
|
|
cust_sh->write_func(cust_sh->handler,(unsigned char *)"\r\n",2,1000);
|
|
}else{
|
|
cust_sh->write_func(cust_sh->handler,(unsigned char *)s,strlen(s),1000);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
int uartsh_printf(sh_cust_type_t *cust_sh, const char *fmt, ...)
|
|
{
|
|
char buf[512]={0};
|
|
int len=0;
|
|
|
|
if(cust_sh->handler==NULL)return -1;
|
|
|
|
va_list ap;
|
|
va_start(ap, fmt);
|
|
vsnprintf(buf,sizeof(buf)-1,fmt,ap);
|
|
va_end(ap);
|
|
len = strlen(buf);
|
|
if(buf[len-2]!='\r' && buf[len-1]== '\n'){
|
|
cust_sh->write_func(cust_sh->handler,(unsigned char *)buf,len-1,1000);
|
|
uartsh_puts(cust_sh,"\r\n");
|
|
}else{
|
|
cust_sh->write_func(cust_sh->handler,(unsigned char *)buf,len,1000);
|
|
}
|
|
|
|
return len;
|
|
}
|
|
|
|
/*-----------------------------------------------*/
|
|
|
|
static inline void handleDeleteKey(sh_cust_type_t *cust_sh, struct UartshEditBuffer* pEditBuffer,
|
|
size_t* pCursor)
|
|
{
|
|
unsigned int cursor = *pCursor;
|
|
|
|
if( cursor < pEditBuffer->cCount )
|
|
{
|
|
int b = (pEditBuffer->cCount - cursor);
|
|
memcpy(&pEditBuffer->buffer[cursor],
|
|
&pEditBuffer->buffer[cursor + 1],
|
|
b);
|
|
pEditBuffer->buffer[--pEditBuffer->cCount] = '\0';
|
|
|
|
uart_putchar(cust_sh,' ');
|
|
uart_putchar(cust_sh,'\b');
|
|
uartsh_puts(cust_sh,&pEditBuffer->buffer[cursor]);
|
|
uart_putchar(cust_sh,' ');
|
|
while(b--)
|
|
uart_putchar(cust_sh,'\b');
|
|
}
|
|
}
|
|
/*-----------------------------------------------*/
|
|
|
|
unsigned int uartsh_gets(sh_cust_type_t *cust_sh, char** input)
|
|
{
|
|
static struct UartshEditBuffer editBuffer[HISTORY_COUNT] = { { 0, }, };
|
|
static int bufferIndex = 0;
|
|
static int bufferIndexMax = 0;
|
|
|
|
if( editBuffer[bufferIndex].cCount )
|
|
{
|
|
if( bufferIndexMax < (HISTORY_COUNT - 1) )
|
|
bufferIndexMax++;
|
|
|
|
bufferIndex++;
|
|
if( bufferIndex > bufferIndexMax )
|
|
bufferIndex = 0;
|
|
}
|
|
|
|
struct UartshEditBuffer* pEditBuffer = &editBuffer[bufferIndex];
|
|
pEditBuffer->cCount = 0;
|
|
pEditBuffer->buffer[0] = '\0';
|
|
|
|
int hi = bufferIndex;
|
|
size_t cursor = 0;
|
|
char specialKey = 0;
|
|
|
|
while( 1 )
|
|
{
|
|
char c = (char) uart_getchar(cust_sh);
|
|
if(cust_sh->run_flag==1){
|
|
return -1;
|
|
}
|
|
|
|
#if (UARTSH_CONFIG_END_CHAR & UARTSH_END_CHAR_CR)
|
|
if( c == '\r' )
|
|
{
|
|
#if (UARTSH_CONFIG_END_CHAR == UARTSH_END_CHAR_CRLF)
|
|
c = (char) uart_getchar(cust_sh);
|
|
if( c != '\n')
|
|
continue;
|
|
#endif
|
|
break;
|
|
}
|
|
#elif (UARTSH_CONFIG_END_CHAR & UARTSH_END_CHAR_LF)
|
|
if( c == '\n' )
|
|
{
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
switch( specialKey )
|
|
{
|
|
case 0:
|
|
{
|
|
specialKey = 0;
|
|
|
|
switch(c)
|
|
{
|
|
case KEY_ESC_SEQ1:
|
|
{
|
|
specialKey = FLAG_ESC_SEQ1;
|
|
} break;
|
|
|
|
case UARTSH_CONFIG_KEY_BACKSPACE:
|
|
{
|
|
if( cursor )
|
|
{
|
|
cursor--;
|
|
int b = (pEditBuffer->cCount - cursor);
|
|
memcpy(&pEditBuffer->buffer[cursor],
|
|
&pEditBuffer->buffer[cursor + 1],
|
|
b);
|
|
pEditBuffer->buffer[--pEditBuffer->cCount] = '\0';
|
|
|
|
uart_putchar(cust_sh,'\b');
|
|
uartsh_puts(cust_sh,&pEditBuffer->buffer[cursor]);
|
|
uart_putchar(cust_sh,' ');
|
|
while(b--)
|
|
uart_putchar(cust_sh,'\b');
|
|
}
|
|
} break;
|
|
|
|
#if (UARTSH_CONFIG_KEY_BACKSPACE != UARTSH_DELETE_KEY)
|
|
case KEY_DEL:
|
|
{
|
|
handleDeleteKey(cust_sh, pEditBuffer, &cursor );
|
|
} break;
|
|
#endif
|
|
|
|
default:
|
|
{
|
|
//only alphabets and special characters allowed
|
|
if( (c >= 0x20) && (c <= 0x7e) )
|
|
{
|
|
if( pEditBuffer->cCount < (UARTSH_CONFIG_COMMAND_STRING_SIZE - 1) )
|
|
{
|
|
// insertion
|
|
int i = pEditBuffer->cCount;
|
|
while( i > cursor )
|
|
{
|
|
pEditBuffer->buffer[i] = pEditBuffer->buffer[i - 1];
|
|
i--;
|
|
}
|
|
|
|
pEditBuffer->buffer[cursor] = c;
|
|
pEditBuffer->cCount++;
|
|
pEditBuffer->buffer[pEditBuffer->cCount] = '\0';
|
|
uartsh_puts(cust_sh,&pEditBuffer->buffer[cursor]);
|
|
cursor++;
|
|
|
|
i = (pEditBuffer->cCount - cursor);
|
|
while(i--)
|
|
uart_putchar(cust_sh,'\b');
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} break;
|
|
|
|
case FLAG_ESC_SEQ1:
|
|
{
|
|
specialKey = 0;
|
|
|
|
if( c == KEY_ESC_SEQ2 )
|
|
specialKey = FLAG_ESC_SEQ2;
|
|
}break;
|
|
|
|
case FLAG_ESC_SEQ2:
|
|
{
|
|
specialKey = 0;
|
|
|
|
switch(c)
|
|
{
|
|
case KEY_SPECIAL_UP:
|
|
{
|
|
while( cursor-- )
|
|
uart_putchar(cust_sh,'\b');
|
|
|
|
int oldCount = pEditBuffer->cCount;
|
|
|
|
hi--;
|
|
if( hi < 0 )
|
|
hi = bufferIndexMax;
|
|
|
|
if( hi == bufferIndex )
|
|
{
|
|
pEditBuffer->cCount = 0;
|
|
pEditBuffer->buffer[0] = '\0';
|
|
}
|
|
else
|
|
{
|
|
pEditBuffer->cCount = editBuffer[hi].cCount;
|
|
memcpy(pEditBuffer->buffer, editBuffer[hi].buffer, (pEditBuffer->cCount + 1));
|
|
}
|
|
|
|
uartsh_puts(cust_sh,pEditBuffer->buffer);
|
|
cursor = pEditBuffer->cCount;
|
|
|
|
if( oldCount > pEditBuffer->cCount )
|
|
{
|
|
int move = (oldCount - pEditBuffer->cCount);
|
|
while( move-- )
|
|
uart_putchar(cust_sh,' ');
|
|
move = (oldCount - pEditBuffer->cCount);
|
|
while( move-- )
|
|
uart_putchar(cust_sh,'\b');
|
|
}
|
|
} break;
|
|
|
|
case KEY_SPECIAL_DOWN:
|
|
{
|
|
while( cursor-- )
|
|
uart_putchar(cust_sh,'\b');
|
|
|
|
int oldCount = pEditBuffer->cCount;
|
|
|
|
hi++;
|
|
if( hi > bufferIndexMax )
|
|
hi = 0;
|
|
|
|
if( hi == bufferIndex )
|
|
{
|
|
pEditBuffer->cCount = 0;
|
|
pEditBuffer->buffer[0] = '\0';
|
|
}
|
|
else
|
|
{
|
|
pEditBuffer->cCount = editBuffer[hi].cCount;
|
|
memcpy(pEditBuffer->buffer, editBuffer[hi].buffer, (pEditBuffer->cCount + 1));
|
|
}
|
|
|
|
uartsh_puts(cust_sh,pEditBuffer->buffer);
|
|
cursor = pEditBuffer->cCount;
|
|
|
|
if( oldCount > pEditBuffer->cCount )
|
|
{
|
|
int move = (oldCount - pEditBuffer->cCount);
|
|
while( move-- )
|
|
uart_putchar(cust_sh,' ');
|
|
move = (oldCount - pEditBuffer->cCount);
|
|
while( move-- )
|
|
uart_putchar(cust_sh,'\b');
|
|
}
|
|
} break;
|
|
|
|
case KEY_SPECIAL_LEFT:
|
|
{
|
|
if( cursor )
|
|
{
|
|
uart_putchar(cust_sh,'\b');
|
|
cursor--;
|
|
}
|
|
} break;
|
|
|
|
case KEY_SPECIAL_RIGHT:
|
|
{
|
|
if( cursor < pEditBuffer->cCount )
|
|
{
|
|
uart_putchar(cust_sh,pEditBuffer->buffer[cursor++]);
|
|
}
|
|
} break;
|
|
|
|
case KEY_ESC_SEQ3:
|
|
{
|
|
specialKey = FLAG_ESC_SEQ3;
|
|
} break;
|
|
}
|
|
}break;
|
|
|
|
case FLAG_ESC_SEQ3:
|
|
{
|
|
specialKey = 0;
|
|
|
|
// deletion
|
|
if( c == KEY_ESC_SEQ4 )
|
|
{
|
|
handleDeleteKey(cust_sh, pEditBuffer, &cursor );
|
|
}
|
|
}break;
|
|
}
|
|
|
|
//fflush(stdout);
|
|
}
|
|
|
|
uartsh_puts(cust_sh,"\r\n");
|
|
|
|
// copy current buffer to next buffer only if current buffer has content
|
|
if( pEditBuffer->cCount )
|
|
{
|
|
// as caller uses strtok passed buffer will be spoiled
|
|
// copies current edit buffer's content to next buffer and passes to caller
|
|
// next call makes use of passed buffer for editing
|
|
int bi = (bufferIndex + 1);
|
|
if( bi > (HISTORY_COUNT - 1) )
|
|
bi = 0;
|
|
|
|
#if (HISTORY_COUNT >= 2) // as total buffer is 1, no point in copying to itself
|
|
memcpy(editBuffer[bi].buffer, pEditBuffer->buffer, (pEditBuffer->cCount + 1));
|
|
#endif
|
|
|
|
*input = editBuffer[bi].buffer;
|
|
}
|
|
|
|
return pEditBuffer->cCount;
|
|
}
|
|
/*-----------------------------------------------*/
|
|
|
|
int uartshTokenize(char commandString[], char const tokens[], int argcMax, char* argv[])
|
|
{
|
|
int argc = 0;
|
|
char* token = strtok(commandString, tokens);
|
|
while(token != NULL)
|
|
{
|
|
argv[argc++] = token;
|
|
if( argc >= argcMax )
|
|
break;
|
|
|
|
token = strtok(NULL, tokens);
|
|
}
|
|
|
|
return argc;
|
|
}
|
|
/*-----------------------------------------------*/
|
|
|
|
UartshCommandHandler uartshGetHandler(UartshCommand cmdlist[], char command[])
|
|
{
|
|
int commandLength = strlen(command);
|
|
|
|
int index = 0;
|
|
while( cmdlist[index].name != NULL )
|
|
{
|
|
int appNameSize = strlen(cmdlist[index].name);
|
|
|
|
// extra check to ensure command length is exactly matching app length
|
|
if( commandLength == appNameSize )
|
|
{
|
|
if( 0 == strncmp(command, cmdlist[index].name, appNameSize) )
|
|
{
|
|
return cmdlist[index].handler;
|
|
}
|
|
}
|
|
|
|
index++;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
/*-----------------------------------------------*/
|
|
|
|
void uartsh_thread_cb(void *args)
|
|
{
|
|
char* argv[UARTSH_CONFIG_ARGC_MAX] = { 0, };
|
|
int argc = 0;
|
|
int first_flag = 0;
|
|
sh_cust_type_t *cust_sh = args;
|
|
|
|
UartshCommand *cmdlist = cust_sh->cmd_list;
|
|
|
|
cust_sh->time_out = UARTSH_DEFAULT_TIMEOUT;
|
|
cust_sh->time_out_uptime = hal_os_up_time_ms();
|
|
|
|
cust_sh->handler = cust_sh->open_func(cust_sh->port,cust_sh->configbuf);
|
|
if(!cust_sh->handler){
|
|
RLOGD("sh %s open error",cust_sh->name);
|
|
goto exit;
|
|
}
|
|
|
|
RLOGD("shell %s runing",cust_sh->name);
|
|
cust_sh->run_flag = 0;
|
|
while(cust_sh->run_flag==0)
|
|
{
|
|
if(first_flag==1){
|
|
//uartsh_puts(cust_sh,"\r\n");
|
|
uartsh_printf(cust_sh,"cmd# ");
|
|
}
|
|
|
|
first_flag=1;
|
|
|
|
char* commandString = NULL;
|
|
int commandStringLength = 0;
|
|
if( 0 == (commandStringLength = uartsh_gets(cust_sh,&commandString)) )
|
|
continue;
|
|
|
|
if(cust_sh->run_flag==1){
|
|
break;
|
|
}
|
|
|
|
//uartsh_puts(cust_sh,commandString);
|
|
argc = uartshTokenize(commandString, " \n", UARTSH_CONFIG_ARGC_MAX, argv);
|
|
uartsh_puts(cust_sh,"\r\n");
|
|
|
|
size_t commandLength = strlen(argv[0]);
|
|
if( 1 == argc )
|
|
{
|
|
if( commandLength == 4 )
|
|
{
|
|
if( 0 == strncmp("help", argv[0], 5) )
|
|
{
|
|
if( NULL == cmdlist )
|
|
{
|
|
uartsh_puts(cust_sh,"No commands found\r\n");
|
|
continue;
|
|
}
|
|
|
|
uartsh_puts(cust_sh,"Supported commands are below:\r\n\n");
|
|
int index = 0;
|
|
while( cmdlist[index].name != NULL )
|
|
{
|
|
uartsh_puts(cust_sh," ");
|
|
uartsh_puts(cust_sh,cmdlist[index++].name);
|
|
uartsh_puts(cust_sh,"\r\n");
|
|
}
|
|
|
|
continue;
|
|
}
|
|
else if( 0 == strncmp("exit", argv[0], 4) ){
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( NULL == cmdlist )
|
|
continue;
|
|
|
|
UartshCommandHandler handler = uartshGetHandler(cmdlist, argv[0]);
|
|
if( NULL == handler ){
|
|
RLOGD("\r\nUNKNOWN CMD\r\n");
|
|
uartsh_puts(cust_sh,"\r\nUNKNOWN\r\n");
|
|
//break;
|
|
}else{
|
|
RLOGD("\r\nEXEC CMD:%s\r\n", argv[0]);
|
|
|
|
if(g_uartsh_mutex==NULL){
|
|
g_uartsh_mutex = hal_os_mutex_create();
|
|
}
|
|
hal_os_mutex_lock(g_uartsh_mutex);
|
|
int myret = handler(cust_sh,argc, argv);
|
|
if( myret != 0 ){
|
|
uartsh_printf(cust_sh,"\r\nERROR %d\r\n",myret);
|
|
}else{
|
|
uartsh_printf(cust_sh,"\r\nOK\r\n");
|
|
}
|
|
|
|
cust_sh->time_out_uptime = hal_os_up_time_ms();
|
|
|
|
cust_sh->time_out = UARTSH_CMD_TIMEOUT;
|
|
|
|
hal_os_mutex_unlock(g_uartsh_mutex);
|
|
}
|
|
|
|
hal_os_task_sleep_ms(1);
|
|
}
|
|
|
|
exit:
|
|
if(cust_sh->handler){
|
|
cust_sh->close_func(cust_sh->handler);
|
|
}
|
|
cust_sh->handler=NULL;
|
|
cust_sh->run_flag =2;
|
|
RLOGD("shell %s exit!", cust_sh->name);
|
|
hal_os_task_destroy(&cust_sh->thread);
|
|
}
|
|
|
|
int uartshInit(sh_cust_type_t *cust_sh)
|
|
{
|
|
|
|
cust_sh->thread = hal_os_task_create(cust_sh->name,HAL_OS_TASK_PRIORITY_NORMAL,10*1024,uartsh_thread_cb,cust_sh);
|
|
if(!cust_sh->thread){
|
|
RLOGE("shthread thread error");
|
|
cust_sh->run_flag = 1;
|
|
return -1;
|
|
}
|
|
|
|
|
|
return 0;
|
|
}
|
|
|
|
int uartshExit(sh_cust_type_t *cust_sh)
|
|
{
|
|
uint64_t start_ms = hal_os_up_time_ms();
|
|
if(cust_sh->run_flag!=0)return -1;
|
|
|
|
cust_sh->run_flag=1;
|
|
while (cust_sh->run_flag!=2)
|
|
{
|
|
if(hal_os_up_time_ms()-start_ms>10000)
|
|
{
|
|
cust_sh->run_flag = 1;
|
|
return -1;
|
|
}
|
|
hal_os_task_sleep_ms(10);
|
|
}
|
|
cust_sh->run_flag=1;
|
|
return 0;
|
|
}
|
|
|
|
int uartshRunning(sh_cust_type_t *cust_sh)
|
|
{
|
|
if(cust_sh->run_flag==0 || cust_sh->run_flag==-1){
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|