参考嵌入式终端AtShell.csdn基于rtdef.h的轻量级设备管理、终端、协程与应用管理框架设计.csdnzynq的linux驱动版终端AtShellDrv.csdn将嵌入式终端AtShell.csdn的功能进行精简,方便在串口助手上使用去掉命令历史去掉命令补全去掉AT模式去掉异步缓冲输出去掉日志重定向代码SimpleAtShell.h#ifndef__SIMPLE_ATSHELL_H__#define__SIMPLE_ATSHELL_H__#includestdint.h#includestdbool.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__cplusplusexternC{#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#includeSimpleAtShell.h#includestdarg.h#includestdio.h#includestring.h#defineAT_CMDLINE_SIZE128AtShell g_atShell;staticATWriteFun s_writeFunNULL;staticchars_cmdLine[AT_CMDLINE_SIZE];staticuint32_ts_cmdIndex0;staticint__help(intargc,char**argv){(void)argc;(void)argv;constAT_CMD_ENTRY_TypeDef*cmdg_atShell.GetCmdList();intnumg_atShell.GetCmdNum();AT_printf(AtShell commands:\r\n);for(inti0;inum;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(*str0||*str9)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);intlenvsnprintf(buf,sizeof(buf),fmt,args);va_end(args);if(len0){if((uint32_t)lensizeof(buf))lensizeof(buf);Write(buf,len);}}AtShell::AtShell(){m_cmdNum0;m_argc0;AT_SHELL_EXPORT(help,list cmd,__help);}bool AtShell::Regist(AT_CMD_ENTRY_TypeDef cmd){if(m_cmdNumCON_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_argc0;while(*cmd){while(*cmd ||*cmd,||*cmd\t){*cmd0;}if(*cmd0){break;}if(m_argcRT_FINSH_ARG_MAX){break;}m_argv[m_argc]cmd;while(*cmd*cmd! *cmd!,*cmd!\t*cmd!\r*cmd!\n){cmd;}}return(m_argc0);}bool AtShell::Exec(char*cmd){if(!Parse(cmd)){returnfalse;}if(IsNumber(m_argv[0])){intindexatoi(m_argv[0]);if(index0indexm_cmdNum){m_cmdList[index].atFun(m_argc,m_argv);returntrue;}Printf(Invalid command index: %d\r\n,index);returnfalse;}/* 按名称查找 */for(inti1;im_cmdNum;i){if(strcmp(m_cmdList[i].methodName,m_argv[0])0){m_cmdList[i].atFun(m_argc,m_argv);returntrue;}}/* 0号命令默认处理 */if(m_cmdNum0m_cmdList[0].atFun){m_cmdList[0].atFun(m_argc,m_argv);returntrue;}returnfalse;}voidat_init(ATWriteFun writeFun){s_writeFunwriteFun;(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_ti0;ilen;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_cmdIndex0;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#includeArduino.h#includeSimpleAtShell.hstaticintuser_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(inti0;iargc;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(){intlenSerial.available();if(len0){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 argc3argv[0]1argv[1]55argv[2]rr