这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » MCU » shell是什么?shell实现原理分析基于MM32MCU的shell脚本源码

共2条 1/1 1 跳转至

shell是什么?shell实现原理分析基于MM32MCU的shell脚本源码

工程师
2020-12-06 23:01:43     打赏

在前两节中,我们讲解了如何在MM32MCU上使用shell来辅助开发,分别介绍的是通过串口方式和J-LinkRTT方式的shell,本次课程我们分析源码来讲解shell实现原理。

软件资源如下:

以下为函数初始化配置及相关全局变量定义内容,代码如下:

typedefstruct

{

char*command;//shell命令提示符

charbuffer[SHELL_COMMAND_MAX_LENGTH];//shell命令缓冲buffer

unsignedshortlength;//shell命令长度大小

unsignedshortcursor;//shell光标位置偏移

char*param[SHELL_PARAMETER_MAX_NUMBER];//shell参数变量

charhistory[SHELL_HISTORY_MAX_NUMBER][SHELL_COMMAND_MAX_LENGTH];//历史记录区域

unsignedshorthistoryCount;//历史记录数量

shorthistoryFlag;//当前记录偏移位置

shorthistoryOffset;//历史记录偏移大小

SHELL_CommandTypeDef*commandBase;//命令表基地址

unsignedshortcommandNumber;//命令数量

intkeyFuncBase;//按键响应表基地址

unsignedshortkeyFuncNumber;//按键响应数量

SHELL_InputModestatus;//shell输入状态

unsignedcharisAcTIve;//是不是当前激活的shell

shellReadread;//shell读函数接口

shellWritewrite;//shell写函数接口

}SHELL_TypeDef;

如上所示,为对象的定义接口,具体说明看注释,我们需要关注的是shell的读写接口。

voidshellInit(SHELL_TypeDef*shell)

{

shelldisplay(shell,“\r\n\r\n”);

shellDisplay(shell,“+=========================================================+\r\n”);

shellDisplay(shell,“|(C)COPYRIGHT2019MindMoTIon|\r\n”);

shellDisplay(shell,“|shellv”SHELL_VERSION“|\r\n”);

shellDisplay(shell,“|Build:”__DATE__“”__TIME__“|\r\n”);

shellDisplay(shell,“+=========================================================+\r\n”);

shell-》length=0;

shell-》cursor=0;

shell-》historyCount=0;

shell-》historyFlag=0;

shell-》historyOffset=0;

shell-》status=SHELL_IN_NORMAL;

shell-》command=SHELL_DEFAULT_COMMAND;

shell-》isAcTIve=0;

shellAdd(shell);

shellDisplay(shell,shell-》command);

#IFdefined(__CC_ARM)||(defined(__ARMCC_VERSION)&&__ARMCC_VERSION》=6000000)

externconstunsignedintshellCommand$$Base;

externconstunsignedintshellCommand$$Limit;

externconstunsignedintshellVariable$$Base;

externconstunsignedintshellVariable$$Limit;

shell-》commandBase=(SHELL_CommandTypeDef*)(&shellCommand$$Base);

shell-》commandNumber=((unsignedint)(&shellCommand$$Limit)

-(unsignedint)(&shellCommand$$Base))

/sizeof(SHELL_CommandTypeDef);

#endif

}

上述代码voidshellInit(SHELL_TypeDef*shell)用来初始化shell对象,首先打印shell界面,然后对shell对象进行初始化为默认状态,然后给shell命令表指定区域和数量。

对于shell输入处理,需要分两种类型判断,一个是正常的字母按键,如A、B、C、D等,一个是功能按键,如方向键等。下面给出两种类型处理代码。

//shellansi按键处理函数

voidshellAnsi(SHELL_TypeDef*shell,chardata)

{

switch((unsignedchar)(shell-》status))

{

caseSHELL_ANSI_CSI:

switch(data)

{

case0x41://键盘方向键向上键

shellHistory(shell,0);

break;

case0x42://键盘方向键向下键

shellHistory(shell,1);

break;

case0x43://键盘方向键向右键

if(shell-》cursor《shell-》length)

{

shellDisplayByte(shell,shell-》buffer[shell-》cursor]);

shell-》cursor++;

}

break;

case0x44://键盘方向键向左键

if(shell-》cursor》0)

{

shellDisplayByte(shell,‘\b’);

shell-》cursor--;

}

break;

default:

break;

}

shell-》status=SHELL_IN_NORMAL;

break;

caseSHELL_ANSI_ESC:

if(data==0x5B)

{

shell-》status=SHELL_ANSI_CSI;

}

else

{

shell-》status=SHELL_IN_NORMAL;

}

break;

default:

break;

}

}

上述voidshellAnsi(SHELL_TypeDef*shell,chardata)函数为shellAnsi处理。

//shell正常按键处理函数

staticvoidshellNormal(SHELL_TypeDef*shell,chardata)

{

if(data==0)

{

return;

}

if(shell-》length《SHELL_COMMAND_MAX_LENGTH-1)

{

if(shell-》length==shell-》cursor)

{

shell-》buffer[shell-》length++]=data;

shell-》cursor++;

shellDisplayByte(shell,data);

}

else

{

for(shorti=shell-》length-shell-》cursor;i》0;i--)

{

shell-》buffer[shell-》cursor+i]=shell-》buffer[shell-》cursor+i-1];

}

shell-》buffer[shell-》cursor++]=data;

shell-》buffer[++shell-》length]=0;

for(shorti=shell-》cursor-1;i《shell-》length;i++)

{

shellDisplayByte(shell,shell-》buffer);

}

for(shorti=shell-》length-shell-》cursor;i》0;i--)

{

shellDisplayByte(shell,‘\b’);

}

}

}

else

{

shellDisplay(shell,“\r\nWarnig:Commandistoolong\r\n”);

shellDisplay(shell,shell-》command);

shellDisplay(shell,shell-》buffer);

shell-》cursor=shell-》length;

}

}

基于上述的两个类型代码,即可封装得到shell的处理代码,如下所示:

//shell处理

voidshellHandler(SHELL_TypeDef*shell,chardata)//shell处理函数

{

if(shell-》status==SHELL_IN_NORMAL)//shell工作在正常模式

{

charkeyDefFind=0;

SHELL_KeyFunctionDef*base=(SHELL_KeyFunctionDef*)shell-》keyFuncBase;

for(shorti=0;i《shell-》keyFuncNumber;i++)

{

if(base.keyCode==data){

if(base.keyFunction){

base.keyFunction(shell);

}

keyDefFind=1;

}

}

if(keyDefFind==0)

{

for(shorti=0;

i《sizeof(shellDefaultKeyFunctionList)/sizeof(SHELL_KeyFunctionDef);

i++)

{

if(shellDefaultKeyFunctionList.keyCode==data){

if(shellDefaultKeyFunctionList.keyFunction){

shellDefaultKeyFunctionList.keyFunction(shell);

}

keyDefFind=1;

}

}

}

if(keyDefFind==0)

{

shellNormal(shell,data);

}

}

else

{

shellAnsi(shell,data);//shellansi处理

}

}

以上就是shell的全部介绍,融合两节的代码,如下:

intmain(void)

{

intGetKey;

delay_init();

LED_Init();

uart_nvic_init(115200);//串口初始化为115200

//uart_shell.read=shellRead;

uart_shell.write=Uart_PutChar;

shellInit(&uart_shell);

/*配置通道0,上行配置*/

SEGGER_RTT_ConfigUpBuffer(0,“RTTUP”,NULL,0,SEGGER_RTT_MODE_NO_BLOCK_SKIP);

/*配置通道0,下行配置*/

SEGGER_RTT_ConfigDownBuffer(0,“RTTDOWN”,NULL,0,SEGGER_RTT_MODE_NO_BLOCK_SKIP);

//rtt_shell.read=shellRead;

rtt_shell.write=RTT_PutChar;

shellInit(&rtt_shell);

while(1)

{

if(SEGGER_RTT_HasKey())

{

GetKey=SEGGER_RTT_GetKey();

shellHandler(&rtt_shell,GetKey);

}

}

}

通过上述代码,可以同时支持串口方式和J-LinkRTT模式的shell,方便用户根据自己实际条件来辅助调试代码。

以上实现方式可能会影响MCU的运行效率,我们在本教程中优先考虑提供实现shell的方式。




工程师
2020-12-09 22:46:09     打赏
2楼

源码做的非常不错


共2条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]