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

控制/MCU

1878人已加入

描述

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

  软件资源如下:

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

  typedef struct

  {

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

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

  unsigned short length; // shell命令长度大小

  unsigned short cursor; // shell光标位置偏移

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

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

  unsigned short historyCount; // 历史记录数量

  short historyFlag; // 当前记录偏移位置

  short historyOffset; // 历史记录偏移大小

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

  unsigned short commandNumber; // 命令数量

  int keyFuncBase; // 按键响应表基地址

  unsigned short keyFuncNumber; // 按键响应数量

  SHELL_InputMode status; // shell输入状态

  unsigned char isActive; //是不是当前激活的shell

  shellRead read; // shell读函数接口

  shellWrite write; // shell写函数接口

  }SHELL_TypeDef;

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

  void shellInit(SHELL_TypeDef *shell)

  {

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

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

  shellDisplay(shell, “| (C) COPYRIGHT 2019 MindMotion |\r\n”);

  shellDisplay(shell, “| shell v”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);

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

  extern const unsigned int shellCommand$$Base;

  extern const unsigned int shellCommand$$Limit;

  extern const unsigned int shellVariable$$Base;

  extern const unsigned int shellVariable$$Limit;

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

  shell-》commandNumber = ((unsigned int)(&shellCommand$$Limit)

  - (unsigned int)(&shellCommand$$Base))

  / sizeof(SHELL_CommandTypeDef);

  #endif

  }

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

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

  // shell ansi按键处理函数

  void shellAnsi(SHELL_TypeDef *shell, char data)

  {

  switch ((unsigned char)(shell-》status))

  {

  case SHELL_ANSI_CSI:

  switch (data)

  {

  case 0x41: // 键盘方向键向上键

  shellHistory(shell, 0);

  break;

  case 0x42: // 键盘方向键向下键

  shellHistory(shell, 1);

  break;

  case 0x43: // 键盘方向键向右键

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

  {

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

  shell-》cursor++;

  }

  break;

  case 0x44: // 键盘方向键向左键

  if (shell-》cursor 》 0)

  {

  shellDisplayByte(shell, ‘\b’);

  shell-》cursor--;

  }

  break;

  default:

  break;

  }

  shell-》status = SHELL_IN_NORMAL;

  break;

  case SHELL_ANSI_ESC:

  if (data == 0x5B)

  {

  shell-》status = SHELL_ANSI_CSI;

  }

  else

  {

  shell-》status = SHELL_IN_NORMAL;

  }

  break;

  default:

  break;

  }

  }

  上述void shellAnsi(SHELL_TypeDef *shell, char data)函数为shellAnsi处理。

  //shell正常按键处理函数

  static void shellNormal(SHELL_TypeDef *shell, char data)

  {

  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 (short i = 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 (short i = shell-》cursor - 1; i 《 shell-》length; i++)

  {

  shellDisplayByte(shell, shell-》buffer);

  }

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

  {

  shellDisplayByte(shell, ‘\b’);

  }

  }

  }

  else

  {

  shellDisplay(shell, “\r\nWarnig: Command is too long\r\n”);

  shellDisplay(shell, shell-》command);

  shellDisplay(shell, shell-》buffer);

  shell-》cursor = shell-》length;

  }

  }

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

  //shell处理

  void shellHandler(SHELL_TypeDef *shell, char data) //shell处理函数

  {

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

  {

  char keyDefFind = 0;

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

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

  {

  if (base.keyCode == data) {

  if (base.keyFunction) {

  base.keyFunction(shell);

  }

  keyDefFind = 1;

  }

  }

  if (keyDefFind == 0)

  {

  for (short i = 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);//shell ansi处理

  }

  }

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

  int main(void)

  {

  int GetKey;

  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-Link RTT模式的shell,方便用户根据自己实际条件来辅助调试代码。

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

  推荐阅读:shell调试教程之MM32 MCU的J-Link RTT方式实现shell功能

       推荐阅读:shell调试教程之如何在MM32 MCU上使用shell来辅助开发
 

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
评论(0)
发评论
melidna_li 2021-03-01
0 回复 举报
太长了。。还是需要系统的 收起回复

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分