嵌入式终端AtShell的精简版
📅 2026/7/25 9:55:53
👁️ 阅读次数
📝 编程学习
参考
嵌入式终端AtShell.csdn
基于rtdef.h的轻量级设备管理、终端、协程与应用管理框架设计.csdn
zynq的linux驱动版终端AtShellDrv.csdn
将嵌入式终端AtShell.csdn的功能进行精简,方便在串口助手上使用
- 去掉命令历史
- 去掉命令补全
- 去掉AT模式
- 去掉异步缓冲输出
- 去掉日志重定向
代码
SimpleAtShell.h
#ifndef__SIMPLE_ATSHELL_H__#define__SIMPLE_ATSHELL_H__#include<stdint.h>#include<stdbool.h>#defineCON_AT_METHOD_NUM10//命令数#defineRT_FINSH_ARG_MAX8//参数容量#defineFINSH_CMD_SIZE20//最长命令尺寸typedefint(*ATWriteFun)(uint8_t*buf,uint32_tlen);typedefint(*ATServerFun)(intargc,char**argv);typedefstruct{constchar*methodName;constchar*desc;ATServerFun atFun;void*userData;}AT_CMD_ENTRY_TypeDef;#defineAT_FUN(name)#name#defineAT_printf(format,...)g_atShell.Printf(format,##__VA_ARGS__)#defineAT_println(format,...)g_atShell.Printf(format,##__VA_ARGS__);AT_printf("\r\n")#defineAT_m_bufg_atShell.GetBuf()#defineAT_SHELL_EXPORT(cmdName,desc,fun,...)AT_CMD_ENTRY_TypeDef fun##entrycmd={AT_FUN(cmdName),#desc,fun,__VA_ARGS__};at_register(fun##entrycmd)#defineAT_EXPORT(x)AT_SHELL_EXPORT(x,x,x)#ifdef__cplusplusclass AtShell{public:AtShell();boolRegist(AT_CMD_ENTRY_TypeDef cmd);boolRegist(AT_CMD_ENTRY_TypeDef*cmdList,intcmdLen);boolExec(char*cmd);intGetCmdNum()const;constAT_CMD_ENTRY_TypeDef*GetCmdList()const;voidPrintf(constchar*fmt,...);voidWrite(constvoid*buf,uint32_tlen);virtualchar*GetBuf(){returnm_buf;};private:charm_buf[FINSH_CMD_SIZE];boolParse(char*cmd);private:AT_CMD_ENTRY_TypeDef m_cmdList[CON_AT_METHOD_NUM];intm_cmdNum;intm_argc;char*m_argv[RT_FINSH_ARG_MAX];};externAtShell g_atShell;#endif#ifdef__cplusplusextern"C"{#endifvoidat_init(ATWriteFun writeFun);intat_import(uint8_t*buf,uint32_tlen,uint32_tms);boolat_register(AT_CMD_ENTRY_TypeDef cmd);boolat_register_list(AT_CMD_ENTRY_TypeDef*cmdList,intcmdLen);voidat_show_version(void);#ifdef__cplusplus}#endif#endifSimpleAtShell.cpp
#include"SimpleAtShell.h"#include<stdarg.h>#include<stdio.h>#include<string.h>#defineAT_CMDLINE_SIZE128AtShell g_atShell;staticATWriteFun s_writeFun=NULL;staticchars_cmdLine[AT_CMDLINE_SIZE];staticuint32_ts_cmdIndex=0;staticint__help(intargc,char**argv){(void)argc;(void)argv;constAT_CMD_ENTRY_TypeDef*cmd=g_atShell.GetCmdList();intnum=g_atShell.GetCmdNum();AT_printf("AtShell commands:\r\n");for(inti=0;i<num;i++){AT_printf("%2d. %-16s %s\r\n",i,cmd[i].methodName,cmd[i].desc?cmd[i].desc:"");}return0;}staticboolIsNumber(constchar*str){if(*str=='\0')returnfalse;while(*str){if(*str<'0'||*str>'9')returnfalse;str++;}returntrue;}intAtShell::GetCmdNum()const{returnm_cmdNum;}constAT_CMD_ENTRY_TypeDef*AtShell::GetCmdList()const{returnm_cmdList;}voidAtShell::Write(constvoid*buf,uint32_tlen){if(s_writeFun){s_writeFun((uint8_t*)buf,len);}}voidAtShell::Printf(constchar*fmt,...){if(!s_writeFun)return;charbuf[256];va_list args;va_start(args,fmt);intlen=vsnprintf(buf,sizeof(buf),fmt,args);va_end(args);if(len>0){if((uint32_t)len>sizeof(buf))len=sizeof(buf);Write(buf,len);}}AtShell::AtShell(){m_cmdNum=0;m_argc=0;AT_SHELL_EXPORT(help,list cmd,__help);}bool AtShell::Regist(AT_CMD_ENTRY_TypeDef cmd){if(m_cmdNum>=CON_AT_METHOD_NUM){returnfalse;}m_cmdList[m_cmdNum++]=cmd;returntrue;}bool AtShell::Regist(AT_CMD_ENTRY_TypeDef*cmdList,intcmdLen){while(cmdLen--){if(!Regist(*cmdList++)){returnfalse;}}returntrue;}bool AtShell::Parse(char*cmd){m_argc=0;while(*cmd){while(*cmd==' '||*cmd==','||*cmd=='\t'){*cmd++=0;}if(*cmd==0){break;}if(m_argc>=RT_FINSH_ARG_MAX){break;}m_argv[m_argc++]=cmd;while(*cmd&&*cmd!=' '&&*cmd!=','&&*cmd!='\t'&&*cmd!='\r'&&*cmd!='\n'){cmd++;}}return(m_argc>0);}bool AtShell::Exec(char*cmd){if(!Parse(cmd)){returnfalse;}if(IsNumber(m_argv[0])){intindex=atoi(m_argv[0]);if(index>=0&&index<m_cmdNum){m_cmdList[index].atFun(m_argc,m_argv);returntrue;}Printf("Invalid command index: %d\r\n",index);returnfalse;}/* 按名称查找 */for(inti=1;i<m_cmdNum;i++){if(strcmp(m_cmdList[i].methodName,m_argv[0])==0){m_cmdList[i].atFun(m_argc,m_argv);returntrue;}}/* 0号命令:默认处理 */if(m_cmdNum>0&&m_cmdList[0].atFun){m_cmdList[0].atFun(m_argc,m_argv);returntrue;}returnfalse;}voidat_init(ATWriteFun writeFun){s_writeFun=writeFun;(void)s_writeFun;}boolat_register(AT_CMD_ENTRY_TypeDef cmd){returng_atShell.Regist(cmd);}boolat_register_list(AT_CMD_ENTRY_TypeDef*cmdList,intcmdLen){returng_atShell.Regist(cmdList,cmdLen);}intat_import(uint8_t*buf,uint32_tlen,uint32_tms){(void)ms;for(uint32_ti=0;i<len;i++){charch=(char)buf[i];if(ch=='\r'){continue;}if(ch=='\n'){s_cmdLine[s_cmdIndex]=0;if(s_cmdIndex){g_atShell.Exec(s_cmdLine);}s_cmdIndex=0;continue;}if(s_cmdIndex<(AT_CMDLINE_SIZE-1)){s_cmdLine[s_cmdIndex++]=ch;}}returnlen;}voidat_show_version(void){if(!s_writeFun)return;s_writeFun((uint8_t*)" \\ | /\r\n",8);s_writeFun((uint8_t*)"- AT_SHELL - "__DATE__"\r\n",sizeof("- AT_SHELL - "__DATE__"\r\n")-1);s_writeFun((uint8_t*)" / | \\\r\n",8);}esp32上测试
main.cpp
#include<Arduino.h>#include"SimpleAtShell.h"staticintuser_at_write(uint8_t*srcBuf,uint32_ttoSendLen){returnSerial.write(srcBuf,toSendLen);}staticinttest_01(intargc,char**argv){AT_println("hello test_01");AT_println("argc = %d",argc);for(inti=0;i<argc;i++){AT_println("argv[%d] = \"%s\"",i,argv[i]);}return0;}voidsetup(){Serial.begin(115200);at_init(user_at_write);at_show_version();AT_SHELL_EXPORT(test01,测试,test_01);}voidloop(){intlen=Serial.available();if(len>0){Serial.readBytes((uint8_t*)AT_m_buf,len);at_import((uint8_t*)AT_m_buf,len,millis());}}输出
\|/-AT_SHELL-Jul252026/|\[00:11:05.273]发→◇0□[00:11:05.277]收←◆AtShell commands:0.help list cmd1.test01 测试[00:11:12.177]发→◇155rr □[00:11:12.181]收←◆hello test_01 argc=3argv[0]="1"argv[1]="55"argv[2]="rr"
编程学习
技术分享
实战经验