嵌入式开发包罗万象,但是一些基本组件的设计可以让你的代码更具灵活性和可操作性,比如可以在你的系统中集成一个shell,让你可以向linux一样操作命令控制。
shell的本质就是通过对命令行的解析实现对应功能函数的调用,一般嵌入式的输入终端大多数采用串口进行交互,下面就是一个简单的接收串口的键盘输入然后解析内置的命令,实现内置功能函数的调用,程序可以采用可配置的方式,实现命令字和功能函数指针映射,实现强大而简洁的shell功能,这种解析技巧也可以用在文本协议功能解析上,逻辑简单易于扩展,功能强大,欢迎大家交流。
核心代码如下
void shelltask(char recChar)
{
//u8 i=0,num,err; /*i is the pointer of commandbuf */
int ii=0;
char ch;
ii=ii;
ch=recChar;
switch(ch)
{
case 0xd: //enter
#ifdef ShellDebug
Shell_Printf("Run command\r\n");
#endif
if (g_Counter==0)
{ //commandbuf is null,begin a new line
_log(DIRNAME);
_log(CurDir);
_log(">");
}
else{
if(CommandBuf[g_Counter-1]==' ')
g_Counter--; //get rid of the end space
//CommandBuf[i++] = '\r';
//CommandBuf[i++] = '\n';
CommandBuf[g_Counter] = '\0';
#ifdef ShellDebug
for(ii=0;ii<g_Counter;ii++)
UART_Send_Byte(CommandBuf[ii]);
Shell_Printf("\r\nexcute command i=%d\r\n",g_Counter);
//UART_Send_Str(CommandBuf);
Shell_Printf("\r\n%s\r\n",CommandBuf);
#endif
_log("\r\n");
//OSSemPost(WaitSem);
ShellCommand(CommandBuf);
//OSSemPost(WaitSem);
g_Counter = 0;
CommandBuf[g_Counter] = '\0';
_log("\r\n");
_log(DIRNAME);
_log(CurDir);
_log(">");
}
break;
case '\b': //backspace
if ( g_Counter==0 ){ //has backed to first one
//do nothing
}
else{
g_Counter--; //pointer back once
putchar('\b'); //cursor back once
putchar(' '); //earse last char in screen
putchar('\b'); //cursor back again
}
break;
case ' ': //don't allow continuous or begin space(' ')
if((CommandBuf[g_Counter-1] == ' ')||(g_Counter==0)||(g_Counter>MaxLenComBuf)){
//do nothing
#ifdef ShellDebug
Shell_Printf("\r\nRec %d-> %c\r\n",g_Counter,CommandBuf[g_Counter-1]);
#endif
}
else
{
CommandBuf[g_Counter] = ch;
g_Counter++;
putchar(ch); //display and store ch
}
break;
default: //normal key
if (g_Counter>MaxLenComBuf){ //the buf reached MAX
//do nothing
#ifdef ShellDebug
Shell_Printf("\r\nRec %d-> %c\r\n",g_Counter,CommandBuf[g_Counter-1]);
#endif
}
else{
CommandBuf[g_Counter] = ch;
g_Counter++;
putchar(ch); //display and store ch
#ifdef ShellDebug
Shell_Printf("\r\nRec %d-> %c\r\n",g_Counter,CommandBuf[g_Counter-1]);
#endif
}
break;
} //switch
}
SHELL_COMMAND shell_cmds[]=
{
{"help", helpFunc, "help - 显示帮助"},
{"gettime", ShowTime, "gettime - 显示系统时间"},
{"settime", SetTime, "settime - 设置系统时间"},
//{"setport", SetPort, "setport - 设置端口开关"},
//{"setimgcyc", SetImgSendCyc,"setimgcyc - 设置图像定时周期传送参数"},
{"reset", ResetFunc, "reset - 系统复位"},
{"login", Login, "login - 操作用户登录"},
{"logout", Logout, "logout - 操作用户退出"},
{"ver", Vesion, "ver - 程序版本"},
//{"sendjpeg", SendJpeg, "sendjpeg - 通过串口提取图片"},
//{"startjpeg", StartJpeg, "startjpeg - 开始图片采集存储"},
//{"stopjpeg", StopJpeg, "stopjpeg - 停止图片采集存储"},
//{"resetsend", ResetSend, "resetsend - 复位文件发送任务"}
//{"setenv", SetEnv, "setenv - 设置环境变量"},
//{"setdefenv", SetDefEnv, "setdefenv - 恢复出厂环境变量"},
//{"getenv", GetEnv, "getenv - 显示环境变量"},
//{"saveenv", SaveEnv, "saveenv - 保存环境变量"},
//{"resetenv", ResetEnv, "resetenv - 初始化环境变量"},
//{"netstatus", NetStatus, "netstatus - 网络状态"},
//{"mktime", MkTime, "mktime - 当前时间转时间戳"},
//{"gmtime", GmTime, "gmtime - 输入时间戳转时间"},
//{"leddsp", LedDsp, "leddsp - 发送文本到LED"},
//{"queryled", QueryLedDsp, "queryled - 查询LED预置信息"},
//{"clrled", ClrLedDsp, "clrled - LED清除预置信息"},
{NULL,NULL,NULL}
};
void print_help_on_shellcommands(pSHELL_COMMAND commands)
{
int i = 0;
Shell_Printf("\r\n");
while (commands[i].cmdstr != NULL)
{
//if(i%2==0)
// Shell_Printf("%s",commands[i].cmdstrhelp);
//else
Shell_Printf(" %s\r\n",commands[i].cmdstrhelp);
//OSTimeDly(5);
i++;
}
Shell_Printf("\r\n");
}
enum ParseState {
PS_WHITESPACE,
PS_TOKEN,
PS_STRING,
PS_SPECCHAR,
PS_ESCAPE
};
enum ParseState stackedState1;
enum ParseState stackedState2;
enum ParseState stackedState3;
void parseargs(char *argstr,int *argc_p, char **argv)
{
int argc = 0;
char c;
enum ParseState lastState = PS_WHITESPACE;
#ifdef ShellDebug
Shell_Printf("parseargs\r\n");
#endif
// tokenize the argstr
while ((c = *argstr) != 0)
{
enum ParseState newState;
if (lastState == PS_ESCAPE)
{
newState = stackedState3;
}
else if (lastState == PS_STRING)
{
if (c == '"')
{
newState = PS_WHITESPACE;
*argstr = 0;
}
else
{
newState = PS_STRING;
}
}
else if ((c == ' ') || (c == '\t'))
{
// whitespace character
*argstr = 0;
newState = PS_WHITESPACE;
}
else if (c == '"')
{
newState = PS_STRING;
*argstr++ = 0;
argv[argc++] = argstr;
}
else if (c == '\\')
{
stackedState3 = lastState;
newState = PS_ESCAPE;
}
else
{
// token
if (lastState == PS_WHITESPACE)
{
argv[argc++] = argstr;
}
newState = PS_TOKEN;
}
lastState = newState;
argstr++;
}
#ifdef ShellDebug
if (1)
{
int i;
Shell_Printf("parseargs: argc=%d", argc);
for (i = 0; i < argc; i++)
{
Shell_Printf(" ");
Shell_Printf(argv[i]);
Shell_Printf("\r\n");
}
}
#endif
argv[argc] = NULL;
if (argc_p != NULL)
*argc_p = argc;
}
void ShellCommand(char *cmdstr)
{
int argc;
char *argv[128];
argc=0;
memset(argv, 0, sizeof(argv));
#ifdef ShellDebug
Shell_Printf("\r\nShellCommand\r\n");
Shell_Printf(cmdstr);
//Shell_Printf(cmdstr);
#endif
parseargs((char*)cmdstr,&argc, argv);
if (argc > 0)
{
execshellcmd(shell_cmds, argc, (const char **)argv);
}
else
{
print_help_on_shellcommands(shell_cmds);
}
}
int parseshellcmd(SHELL_COMMAND *cmdlist, int argc, const char **argv)
{
/* find the command name */
const char *cmdname = argv[0];
int cmdnum = 0;
if (argc < 1)
return -1;
/* do a string compare for the first offset characters of cmdstr
against each member of the cmdlist */
while (cmdlist[cmdnum].cmdstr != NULL)
{
if (strcmp(cmdlist[cmdnum].cmdstr, cmdname) == 0)
return(cmdnum);
cmdnum++;
}
return(-1);
}
void execshellcmd(pSHELL_COMMAND cmdlist, int argc, const char **argv)
{
int cmdnum = parseshellcmd(cmdlist, argc, argv);
if (1)
{
#ifdef ShellDebug
Shell_Printf("execcmd: argv[0]=%s\r\n",(char*)argv[0]);
Shell_Printf(" argc=%d", argc);
Shell_Printf(" cmdnum=%d", cmdnum);
//OSTimeDlyHMSM(0,0,1,0);
#endif
}
if (cmdnum >= 0)
{
(*cmdlist[cmdnum].cmdfunc)(argc, argv);
}
else if (strcmp(argv[1], "help") == 0)
{
print_help_on_shellcommands(cmdlist);
}
else
{
#if 0
print_help_on_shellcommands(cmdlist);
#else
/* default to the first command and insert it into the head of argv */
int i;
for (i = argc; i >= 0; i--)
{
argv[i+1] = argv[i];
}
argc++;
argv[0] = cmdlist[0].cmdstr;
(*cmdlist[0].cmdfunc)(argc, argv);
#endif
}
}