发 帖  
原厂入驻New
[资料]

从u-boot移植出来的shell命令界面

2011-11-29 12:41:35  3092 Linux Shell
分享
以前搞过u-boot,,有很多命令,,用超级终端操作,,比如help、tftp、erase、fatload,
其实就是下面这段代码接受超级终端命令的。
最近打算给产品做一个shell,用超级终端输入命令,,所以从u-boot找到这段代码并移植出来了
使用方法是:
main()
{
    char buffer[16];//缓冲区长度根据命令长度可调整
    while(1){
        _delay_ms(100);
        //其中"LW-C360#"就是显示在超级终端的输入命令前端的,叫什么?
        readline_into_buffer ("LW-C360#", buffer);
    }
}


使用截图:




/*
**********************************************************************************
*  实现一个简单的Shell命令交互界面,命令行接收部分移植自u-boot-1.3.4
**********************************************************************************
*/
#define  tab_seq  ("        ")/* used to expand TABs */
#define  erase_seq  ("\b \b") /* erase sequence */
//删除一个字符
static char * delete_char(char *buffer, char *p, int *colp, int *np, int plen)
{
    char *s;

    if (*np == 0) {
          return (p);
    }

    if (*(--p) == '\t') {  /* will retype the whole line */
          while (*colp > plen) {
               USART_PutStr(COMMUNICATE_USART, erase_seq);
               (*colp)--;
            }

          for (s=buffer; s<p; ++s) {
               if (*s == '\t') {
                    USART_PutStr(COMMUNICATE_USART, tab_seq+((*colp) & 07));
                    *colp += 8 - ((*colp) & 07);
               } else {
                    ++(*colp);
                    USART_PutChar(COMMUNICATE_USART, *s);
               }
          }
    } else {
          USART_PutStr(COMMUNICATE_USART, erase_seq);
          (*colp)--;
    }

    (*np)--;

    return (p);
}

//从超级终端读取命令行
int readline_into_buffer (const char *const prompt, char * buffer)
{
    char *p = buffer;
    char * p_buf = p;
    /* buffer index */
    int n = 0;
    /* prompt length */
    int plen = 0;
    /* output column cnt */
    int col;
    char c;

    /* print prompt */
    if (prompt) {
          plen = strlen (prompt);
          USART_PutStr(COMMUNICATE_USART, prompt);
    }

    col = plen;
    for (;;) {
          //从at91sam9260串口读取一个字符
          while( 0 == (AT91C_BASE_US1->US_CSR & AT91C_US_RXRDY) );
          c = AT91C_BASE_US1->US_RHR;
         
            /*
           * Special character handling
           */
           switch (c) {
                  case '\r': /* Enter */
                  case '\n':
                           //回车表示命令输入结束
                           *p = '\0';
                           USART_PutStr(COMMUNICATE_USART, "\r\n");
                           return (p - p_buf);
                  case '\0': /* nul */
                           continue;
                  case 0x03: /* ^C - break */
                           //CTRL+C表示取消命令输入
                           p_buf[0] = '\0'; /* discard input */
                           USART_PutStr(COMMUNICATE_USART, "\r\n");//luodefu
                           return (-1);
                  case 0x15: /* ^U - erase line */
                           //CTRL+U表示擦除一行命令输入
                           while (col > plen) {
                            USART_PutStr(COMMUNICATE_USART, erase_seq);
                            --col;
                           }
                           p = p_buf;
                           n = 0;
                           continue;
                  case 0x17: /* ^W - erase word */
                           //CTRL+W表示删除一个词
                           p=delete_char(p_buf, p, &col, &n, plen);
                           while ((n > 0) && (*p != ' ')) {
                                p=delete_char(p_buf, p, &col, &n, plen);
                           }
                           continue;
                  case 0x08: /* ^H  - backspace */
                  case 0x7F: /* DEL - backspace */
                           //表示删除一个字符
                           p=delete_char(p_buf, p, &col, &n, plen);
                           continue;
                  default:
                           /*
                            * Must be a normal character then
                            */
                           if (n < 16-2) {//luodefu-命令行缓冲区大小16
                                    if (c == '\t') { /* expand TABs */
                                             USART_PutStr(COMMUNICATE_USART, tab_seq+(col&07));
                                             col += 8 - (col&07);
                                    } else {
                                             ++col;  /* echo input */
                                             USART_PutChar(COMMUNICATE_USART, c);
                                    }
                                    *p++ = c;
                                    ++n;
                           } else {   /* Buffer full */
                                    USART_PutChar(COMMUNICATE_USART, '\a');
                           }
          }//switch
}//for
}

这几天在进行shell编码和测试,参照u-boot的命令,我也实现了以下命令,功能方面相比u-boot做了简化:
h - help命令,用来输出所有支持的命令以及功能;
f - find命令,用来在yaffs文件系统中查找文件夹或文件;
o - open命令,用来打开目录;
g - get命令, 用来上传文件,通过串口和超级终端实现的zmodem协议,从yaffs中上传指定文件到PC中;
b - back命令,用来返回到yaffs文件系统根目录;
n - next命令,用来显示文件夹接下来的10个目录项(目录项可以是文件夹或文件);
t - top命令, 用来回到目录顶部;
e - exit命令,用来退出shell界面,串口进入机器正常工作时的方式,接收自己定义的串口协议指令


//命令结构体
struct CMD_STRUCT{
char name; /* Command Name */
char *usage;/* Usage message */
void (*CmdFun)(char *para);/* Command execute function */
};

//命令列表
struct CMD_STRUCT CmdTbl[] = {
{'h',  "h - help, list all cmd\n\r",     HelpCmdExeFun},
{'f',  "f - find directory\n\r",       FindCmdExeFun},
{'o',  "o - open directory\n\r",       OpenCmdExeFun},
{'g',  "g - get file\n\r",       GetCmdExeFun},
{'b',  "b - back to root directory\n\r",  BackCmdExeFun},
{'n',  "n - next 10 dirent\n\r",        NextCmdExeFun},
{'t',  "t - go to top of directory\n\r",  TopCmdExeFun},
{'e',  "e - exit shell\n\r",        NULL}
};

以下是操作截图:


shell.PNG (80.94 KB)
下载次数:3
2011-1-27 09:01







//命令结构体
struct CMD_STRUCT{
        char name;        /* Command Name        */
        char *usage;/* Usage message */
        void (*CmdFun)(char *para);/* Command execute function */        
};
//命令列表
struct CMD_STRUCT CmdTbl[] = {
        {'h', "h - help, list all cmd\n\r",                 HelpCmdExeFun},
        {'s', "s - view log status\n\r",                         StatusCmdExeFun},
        {'f', "f - find in root dir\n\r",                        FindCmdExeFun},
        {'o', "o - open directory\n\r",                         OpenCmdExeFun},
        {'g', "g - get specific file\n\r",                         GetCmdExeFun},
        {'b', "b - back to root directory\n\r",         BackCmdExeFun},
        {'n', "n - next 10 dirent\n\r",                         NextCmdExeFun},
        {'t', "t - go to top of directory\n\r",         TopCmdExeFun},
        {'d', "d - download a file from pc\n\r",         DownloadCmdExeFun},
        {'e', "e - exit shell\n\r",                                 NULL}
};

//打印当前目录名字
static void ShowCurDirectory(void)
{
        USART_PutStr(COMMUNICATE_USART, "---------------- in directory : ");
        USART_PutStr(COMMUNICATE_USART, CirDirName);
        USART_PutStr(COMMUNICATE_USART, " ----------------\n\r");
}

//帮助
void HelpCmdExeFun(char *para)
{
        int n;

        USART_PutStr(COMMUNICATE_USART, "---------------- here is all cmd supported ----------------\n\r");
        for(n=0; n<sizeof(CmdTbl)/sizeof(struct CMD_STRUCT); n++){
                USART_PutStr(COMMUNICATE_USART, CmdTbl[n].usage);                                       
        }        
}

//查看日志系统状态
void StatusCmdExeFun(char *para)
{
        unsigned int num;

        num = 100 * yaffs_freespace(ROOT_DIR_NAME) / yaffs_totalspace(ROOT_DIR_NAME);
        USART_PutStr(COMMUNICATE_USART, "---------------- here is log system status ----------------\n\r");
        if(1 == pSystemUnitModule->LogFileSystemCtrl)
                USART_PutStr(COMMUNICATE_USART, "log system status : open\n\r");
        else
                USART_PutStr(COMMUNICATE_USART, "log system status : close\n\r");
        USART_PutStr(COMMUNICATE_USART, "yaffs space use status : ");
        USART_PutChar(COMMUNICATE_USART, '0' + num/10%10 );
        USART_PutChar(COMMUNICATE_USART, '0' + num%10 );
        USART_PutChar(COMMUNICATE_USART, '%' );
        USART_PutStr(COMMUNICATE_USART, "\n\r");
}

//在根目录中查找参数中指定的文件夹或文件,并列出以它开始的10个目录项
void FindCmdExeFun(char *DirentName)
{        
        struct yaffs_dirent *pDirent;
        int n;
        char NameBuff[64];

        //切换到根目录
        yaffs_closedir(pCurDirectory);
        pCurDirectory = yaffs_opendir(ROOT_DIR_NAME);
        yaffs_rewinddir(pCurDirectory);
        
        //设置当前目录名字
        strcpy(CirDirName, ROOT_DIR_NAME);
        //打印当前目录名字
        ShowCurDirectory();

        //名字连接,例如:将根目录"/nand/"和文件夹"2010-01-26"连接为"/nand/2010-01-26"
        strcpy(NameBuff, ROOT_DIR_NAME);
        strncpy(NameBuff + strlen(ROOT_DIR_NAME), DirentName, sizeof(NameBuff)-strlen(ROOT_DIR_NAME));
        
        do{
                pDirent = yaffs_readdir(pCurDirectory);
                if(0 == strcmp(pDirent->d_name, DirentName))
                        break;
        }while(NULL != pDirent);

        if(NULL == pDirent){
                USART_PutStr(COMMUNICATE_USART, "not find\n\r");
                return;
        }

        //打印找到的目录项名字
        strncpy(ListFileName[0], pDirent->d_name, FILE_NAME_MAXLEN);
        ListFileName[0][FILE_NAME_MAXLEN-1] = 0;
        USART_PutChar(COMMUNICATE_USART, '0');
        if(YAFFS_OBJECT_TYPE_DIRECTORY == pDirent->d_type)
                USART_PutStr(COMMUNICATE_USART, " - dir  - ");
        else
                USART_PutStr(COMMUNICATE_USART, " - file - ");
        USART_PutStr(COMMUNICATE_USART, ListFileName[0]);
        USART_PutStr(COMMUNICATE_USART, "\n\r");
        //打印紧跟找到目录后面的9个目录项名字
        for(n=1; n<DIRENT_MAXNUM; n++){
                pDirent = yaffs_readdir(pCurDirectory);
                if(NULL == pDirent){
                        ListFileName[n][0] = 0;
                }else{
                        strncpy(ListFileName[n], pDirent->d_name, FILE_NAME_MAXLEN);
                        ListFileName[n][FILE_NAME_MAXLEN-1] = 0;
                        USART_PutChar(COMMUNICATE_USART, '0' + n);
                        if(YAFFS_OBJECT_TYPE_DIRECTORY == pDirent->d_type)
                                USART_PutStr(COMMUNICATE_USART, " - dir  - ");
                        else
                                USART_PutStr(COMMUNICATE_USART, " - file - ");
                        USART_PutStr(COMMUNICATE_USART, ListFileName[n]);
                        USART_PutStr(COMMUNICATE_USART, "\n\r");
                }                                       
        }
        
        if(NULL == pDirent){
                USART_PutStr(COMMUNICATE_USART, "Note: reach the bottom of directory, no more file\n\r");
        }        
}

//打开目录
void OpenCmdExeFun(char *para)
{
        struct yaffs_dirent *pDirent;
        yaffs_DIR *pTempDirectory;
        int n;
        char NameBuff[64];

        //目录连接,例如:将"/nand/"和"2011-01-25"连接为"/nand/2011-01-25/"
        strcpy(NameBuff, CirDirName);
        strncpy(NameBuff + strlen(NameBuff), ListFileName[*para - '0'], sizeof(NameBuff)-strlen(NameBuff));
        strcpy(NameBuff + strlen(NameBuff), "/");

        pTempDirectory = yaffs_opendir(NameBuff);

        if(NULL == pTempDirectory){
                USART_PutStr(COMMUNICATE_USART, "faild to open directory\n\r");
                return;
        }else{
                yaffs_closedir(pCurDirectory);
                pCurDirectory = pTempDirectory;
        }
        
        //设置当前目录名字
        strncpy(CirDirName, NameBuff, sizeof(CirDirName));
        
        yaffs_rewinddir(pCurDirectory);
        NextCmdExeFun(NULL);        
}

//上传文件
void GetCmdExeFun(char *para)
{
        char NameBuff[64];

        //名字连接,例如:将"/nand/2011-01-25/"和"lw-c360.txt"连接为"/nand/2011-01-25/lw-c360.txt"
        strcpy(NameBuff, CirDirName);
        strncpy(NameBuff + strlen(NameBuff), ListFileName[*para - '0'], sizeof(NameBuff)-strlen(NameBuff));
        //打印要上传的文件名
        USART_PutStr(COMMUNICATE_USART, "Please open zmodem to receive the file : ");
        USART_PutStr(COMMUNICATE_USART, ListFileName[*para - '0']);
        USART_PutStr(COMMUNICATE_USART, "\n\r");
        
        if(0 == ZmodemSendOneFile(NameBuff)){//ZMODEMOK
                USART_PutStr(COMMUNICATE_USART, "send file ok\n\r");
        }else{
                USART_PutStr(COMMUNICATE_USART, "send file error\n\r");
        }
}

//返回根目录
void BackCmdExeFun(char *para)
{        
        yaffs_closedir(pCurDirectory);
        pCurDirectory = yaffs_opendir(ROOT_DIR_NAME);
        yaffs_rewinddir(pCurDirectory);
        
        //设置当前目录名字
        strncpy(CirDirName, ROOT_DIR_NAME, sizeof(CirDirName));
        
        NextCmdExeFun(NULL);        
}

//下10个目录项
void NextCmdExeFun(char *para)
{
        struct yaffs_dirent *pDirent;
        int n;

        //打印当前目录名字
        ShowCurDirectory();

        for(n=0; n<DIRENT_MAXNUM; n++){
                pDirent = yaffs_readdir(pCurDirectory);
                if(NULL == pDirent){
                        ListFileName[n][0] = 0;
                }else{
                        strncpy(ListFileName[n], pDirent->d_name, FILE_NAME_MAXLEN);
                        ListFileName[n][FILE_NAME_MAXLEN-1] = 0;
                        USART_PutChar(COMMUNICATE_USART, '0' + n);
                        if(YAFFS_OBJECT_TYPE_DIRECTORY == pDirent->d_type)
                                USART_PutStr(COMMUNICATE_USART, " - dir  - ");
                        else
                                USART_PutStr(COMMUNICATE_USART, " - file - ");
                        USART_PutStr(COMMUNICATE_USART, ListFileName[n]);
                        USART_PutStr(COMMUNICATE_USART, "\n\r");
                }                                       
        }
        
        if(NULL == pDirent){
                USART_PutStr(COMMUNICATE_USART, "Note: reach the bottom of directory, no more file\n\r");
        }        
}

//返回目录开始位置
void TopCmdExeFun(char *para)
{
        yaffs_rewinddir(pCurDirectory);
        NextCmdExeFun(NULL);        
}

//从PC机下载一个文件
void DownloadCmdExeFun(char *para)
{
        ZmodemReceiveFiles();        
}


/*
* shell命令界面,进入shell界面之前,需要设置COMMUNICATE_USART
* 工作串口波特率为115200,并关闭COMMUNICATE_USART工作串口中断。
*/
void shell(void)
{
        int n, CmdIndex;
        unsigned char CmdBuffer[32];
        
        //执行帮助命令
        HelpCmdExeFun(NULL);
        //打开根目录
        pCurDirectory = yaffs_opendir(ROOT_DIR_NAME);
        yaffs_rewinddir(pCurDirectory);
        strncpy(CirDirName, ROOT_DIR_NAME, sizeof(CirDirName));

        while(1){
                readline_into_buffer("lw360>", CmdBuffer);
                if(0 == CmdBuffer[0]){
                        continue;
                }               

                //检查命令
                if( ('f' == CmdBuffer[0] || 'o' == CmdBuffer[0] || 'g' == CmdBuffer[0]) ){
                        //f、o、g命令和参数之间用1个空格隔开
                        if(' ' != CmdBuffer[1]){
                                USART_PutStr(COMMUNICATE_USART, "cmd error, you can input h for help\n\r");
                                continue;                                
                        }
                }else{
                        //其他命令不带参数,第二个字符必须是结束符'/0'
                        if(0 != CmdBuffer[1]){
                                USART_PutStr(COMMUNICATE_USART, "cmd error, you can input h for help\n\r");
                                continue;
                        }
                }

                //查找命令
                CmdIndex = -1;
                for(n=0; n<sizeof(CmdTbl)/sizeof(struct CMD_STRUCT); n++){
                        if(CmdTbl[n].name == CmdBuffer[0]){
                                CmdIndex = n;
                                break;
                        }                                
                }

                if(-1 == CmdIndex){
                        //查找命令失败
                        USART_PutStr(COMMUNICATE_USART, "cmd error, you can input h for help\n\r");
                        continue;
                }

                //如果是exit命令,则退出shell界面,机器进入正常工作模式
                if('e' == CmdTbl[CmdIndex].name){
                        yaffs_closedir(pCurDirectory);
                        USART_PutStr(COMMUNICATE_USART, "Exit shell, return to work mode, good bye!^_^\n\r");
                        delay_ms(1000);
                        return;
                }

                //检查enter和get命令参数
                if( ('o' == CmdTbl[CmdIndex].name || 'g' == CmdTbl[CmdIndex].name)\
                        && (CmdBuffer[2]<'0' || '9'<CmdBuffer[2]) ){
                        USART_PutStr(COMMUNICATE_USART, "cmd para error\n\r");
                        continue;
                }

                //执行命令
                (CmdTbl[CmdIndex].CmdFun)(&CmdBuffer[2]);
                USART_PutStr(COMMUNICATE_USART, "-\n\r");
        }//end while

}
0
分享淘帖 显示全部楼层

评论

高级模式
您需要登录后才可以回帖 登录 | 注册

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容图片侵权或者其他问题,请联系本站作侵删。 侵权投诉
发资料
快速回复 返回顶部 返回列表