一、在 ubuntu 虚拟机上的简易 shell 程序
程序代码:
#include <stdio.h>
#include <string.h>
#define MAX_LINE_LENGTH 256 // 命令行长度,命令不能超过这个长度
#define PROMPT "X210:~$ "
// 宏定义一些标准命令
#define led "led"
#define lcd "lcd"
#define pwm "pwm"
#define CMD_NUM 99 // 当前系统定义的命令数
const char g_cmdset[CMD_NUM][MAX_LINE_LENGTH];
// 初始化命令列表
static void init_cmd_set(void)
{
memset(g_cmdset, 0, sizeof(g_cmdset)); // 先全部清零
strcpy(g_cmdset[0], led);
strcpy(g_cmdset[1], lcd);
strcpy(g_cmdset[2], pwm);
}
int main(void)
{
int i = 0;
char str[MAX_LINE_LENGTH]; // 用来存放用户输入的命令内容
init_cmd_set();
while (1)
{
// 打印命令行提示符,注意不能加换行
printf(PROMPT);
// 清除str数组以存放新的字符串
memset(str, 0, sizeof(str));
// shell第一步:获取用户输入的命令
scanf("%s", str);
// shell第二步:解析用户输入命令
// shell第三步:处理用户输入命令
for (i=0; i<CMD_NUM; i++)
{
if (!strcmp(str, g_cmdset[i]))
{
// 相等,找到了这个命令,就去执行这个命令所对应的动作。
printf("您输入的命令是:%s,是合法的\n", str);
break;
}
}
if (i >= CMD_NUM)
{
// 找遍了命令集都没找到这个命令
printf("%s不是一个内部合法命令,请重新输入\n", str);
}
}
return 0;
}
实验现象:
root@ubuntu:/home/aston/workspace# ls
main main.c readme.txt 说明.txt
root@ubuntu:/home/aston/workspace# ./main
X210:~$ 231321
231321不是一个内部合法命令,请重新输入
X210:~$ safasf
safasf不是一个内部合法命令,请重新输入
X210:~$ lcd
您输入的命令是:lcd,是合法的
X210:~$ dasfasf
dasfasf不是一个内部合法命令,请重新输入
X210:~$ led
您输入的命令是:led,是合法的
X210:~$ ^C
root@ubuntu:/home/aston/workspace#
二、在 X210 开发板上移植简易的 shell
程序代码:
#define PROMPT "X210 SHELL# "
int main(void)
{
char buf[100] = {0}; // 用来暂存用户输入的命令
uart_init();
//puts("x210 simple shell:\n");
while(1)
{
puts(PROMPT);
memset(buf, 0, sizeof(buf)); // buf弄干净好存储这次用户输入
gets(buf); // 读取用户输入放入buf中
puts("your enter is: ");
puts(buf);
puts("\n");
}
return 0;
实验现象:
三、定义标准命令集及解析
添加 cmd_parser 和 cmd_exec。实现简单的 cmd_parser 和 对应的 cmd_exec。
程序代码:
// 命令解析和命令执行相关的函数
#include "shell.h"
#include "stdio.h"
char g_cmdset[CMD_NUM][MAX_LINE_LENGTH];
// 初始化命令列表
void init_cmd_set(void)
{
memset((char *)g_cmdset, 0, sizeof(g_cmdset)); // 先全部清零
strcpy(g_cmdset[0], led);
strcpy(g_cmdset[1], lcd);
strcpy(g_cmdset[2], pwm);
}
// 解析命令
void cmd_parser(char *str)
{
int i;
for (i=0; i<CMD_NUM; i++)
{
if (!strcmp(str, g_cmdset[i]))
{
// 相等,找到了这个命令,就去执行这个命令所对应的动作。
printf("your enter is: %s\r\n", str);
break;
}
}
if (i >= CMD_NUM)
{
// 找遍了命令集都没找到这个命令
printf("%s is illegal, please try again.\r\n", str);
}
}
// 执行命令
void cmd_exec(void)
{
}
实现现象:
四 、定义 led 和 pwm 相关的命令
程序代码:
// 命令解析和命令执行相关的函数
#include "shell.h"
#include "stdio.h"
#include "main.h"
#include "ctype.h"
#include "lib/vsprintf.h"
char g_cmdset[CMD_NUM][MAX_LINE_LENGTH]; // 命令集,存主命令
char cmd[MAX_CMD_PART][MAX_LEN_PART]; // 当前解析出来的命令
int cmd_index = -1; // 存储解析到的命令是第几个主命令
/****************************具体硬件操作命令处理函数*************************/
// 命令没找到处理方法
void do_cmd_notfound(void)
{
printf("%s Command Error!\r\n", cmd[0]);
}
void inline led_usage(void)
{
printf("LED Usage:\r\n"
" led on\r\n"
" led off\r\n"
" led blink [counts]\r\n");
}
// led命令的处理方法
void do_cmd_led(void)
{
//puts("led cmd");
// 真正的led命令的操作实现
// 目前支持的命令有led on | led off
// cmd[0]里面是led,cmd[1]里面是on|off
if (!strcmp(cmd[1], "on"))
{
// led on
led_on();
}
else if (!strcmp(cmd[1], "off"))
{
// led off
led_off();
}
else if (!strcmp(cmd[1], "blink"))
{
if (!strcmp(cmd[2], ""))
{
led_blink_counts(1);
}
else if(!isdigit(cmd[2]))
{
int cnt = simple_strtoul(cmd[2], cmd[2] + MAX_LEN_PART, 10);
led_blink_counts(cnt);
}
}
// ..... 还可以继续扩展
else
{
// 如果一个都没匹配,则打印使用方法
do_cmd_notfound();
led_usage();
}
}
void inline buzzer_usage(void)
{
printf("PWM Usage:\r\n"
" pwm on\r\n"
" pwm off\r\n"
" pwm freq 10000\r\n"
" pwm freq 2000\r\n"
" pwm freq 100\r\n");
}
// 蜂鸣器命令处理方法
void do_cmd_buzzer(void)
{
//puts("led cmd");
// 真正的buzzer命令的操作实现
// 目前支持的命令有buzzer on | buzzer off
// cmd[0]里面是buzzer,cmd[1]里面是on|off
if (!strcmp(cmd[1], "on"))
{
// buzzer on
buzzer_on();
}
else if (!strcmp(cmd[1], "off"))
{
// buzzer off
buzzer_off();
}
else if (!strcmp(cmd[1], "freq"))
{
if ((!strcmp(cmd[2], "")) || (isdigit(cmd[2])))
{
do_cmd_notfound();
buzzer_usage();
}
else
{
int freq = simple_strtoul(cmd[2], cmd[2] + MAX_LEN_PART, 10);
if (freq != 10000 && freq != 2000 && freq != 100)
{
buzzer_usage();
}
buzzer_set_freq(freq);
}
}
// ..... 还可以继续扩展
else
{
// 如果一个都没匹配,则打印使用方法
do_cmd_notfound();
buzzer_usage();
}
}
// lcd命令处理方法
// ADC命令处理方法
/*********************************shell 命令解析执行框架***********************/
// 初始化命令列表
void init_cmd_set(void)
{
memset((char *)g_cmdset, 0, sizeof(g_cmdset)); // 先全部清零
strcpy(g_cmdset[0], led);
strcpy(g_cmdset[1], lcd);
strcpy(g_cmdset[2], pwm);
memset((char *)cmd, 0, sizeof(cmd));
}
// 将用户输入的字符串命令str按照空格分隔成多个字符串,依次放入cmd二维数组中
void cmdsplit(char cmd[][MAX_LEN_PART], const char *str)
{
int m = 0, n = 0; // m表示二位数组第一维,n表示第二维
while (*str != '\0')
{
if (*str != ' ')
{
cmd[m][n] = *str;
n++;
}
else
{
cmd[m][n] = '\0';
n = 0;
m++;
}
str++;
}
cmd[m][n] = '\0';
}
// 解析命令
void cmd_parser(char *str)
{
int i;
memset((char *)cmd, 0, sizeof(cmd));
// 第一步,先将用户输入的次命令字符串分割放入cmd中
cmdsplit(cmd, str);
// 第二步,将cmd中的次命令第一个字符串和cmdset对比
cmd_index = -1;
for (i=0; i<CMD_NUM; i++)
{
// cmd[0]就是次命令中的第一个字符串,也就是主命令
if (!strcmp(cmd[0], g_cmdset[i]))
{
// 相等,找到了这个命令,就去执行这个命令所对应的动作。
//puts("您输入的命令是:");
//puts(str);
//puts("\n");
cmd_index = i;
break;
}
}
}
// 执行命令
void cmd_exec(void)
{
switch (cmd_index)
{
case 0: // led
do_cmd_led(); break;
case 1: // lcd
case 2: // buzzer
do_cmd_buzzer(); break;
default:
do_cmd_notfound();
led_usage();
buzzer_usage();
break;
}
}
实验现象:
五、定义 adc 和 lcd 命令
实验现象:
^o^ X210 simple shell ^o^
X210 SHELL# ^o^ X210 simple shell ^o^
=============================>
LED Usage:
led on
led off
led blink [counts]
LCD Usage:
lcd test
BUZZER Usage:
buzzer on
buzzer off
buzzer freq 10000
buzzer freq 2000
buzzer freq 100
ADC Usage:
adc test [counts]
=============================>
X210 SHELL# led blink 3
cmd[0] -- led
cmd[1] -- blink
cmd[2] -- 3
cmd[3] --
cmd[4] --
X210 SHELL# led blink 3
cmd[0] -- led
cmd[1] -- blink
cmd[2] -- 3
cmd[3] --
cmd[4] --
X210 SHELL# lcd test
cmd[0] -- lcd
cmd[1] -- test
cmd[2] --
cmd[3] --
cmd[4] --
X210 SHELL# adc test 3
cmd[0] -- adc
cmd[1] -- test
cmd[2] -- 3
cmd[3] --
cmd[4] --
x: bit14 = 0.
x: adc value = 1966.
x: bit14 = 0.
x: adc value = 1961.
x: bit14 = 0.
x: adc value = 1963.
X210 SHELL# buzzer freq 10000
cmd[0] -- buzzer
cmd[1] -- freq
cmd[2] -- 10000
cmd[3] --
cmd[4] --
X210 SHELL# buzzer on
cmd[0] -- buzzer
cmd[1] -- on
cmd[2] --
cmd[3] --
cmd[4] --
X210 SHELL# buzzer off
cmd[0] -- buzzer
cmd[1] -- off
cmd[2] --
cmd[3] --
cmd[4] --
X210 SHELL#
六、开机延时和环境变量
实验现象:
^o^ X210 simple shell ^o^
X210 SHELL# 3
=============================>
LED Usage:
led on
led off
led blink [counts]
LCD Usage:
lcd test
BUZZER Usage:
buzzer on
buzzer off
buzzer freq 10000
buzzer freq 2000
buzzer freq 100
ADC Usage:
adc test [counts]
printenv --- print all environments values.
setenv ENV_NAME --- delete environments values.
setenv ENV_NAME ENV_VAL --- set environments values.
=============================>
X210 SHELL# buzzer on
X210 SHELL# buzzer freq 10000
X210 SHELL# buzzer freq 100
X210 SHELL# buzzer off
X210 SHELL# led off
X210 SHELL# led blink 2
X210 SHELL# adc test
x: bit14 = 0.
x: adc value = 1966.
X210 SHELL# adc test 3
x: bit14 = 0.
x: adc value = 1969.
x: bit14 = 0.
x: adc value = 1970.
x: bit14 = 0.
x: adc value = 1958.
X210 SHELL# help
=============================>
LED Usage:
led on
led off
led blink [counts]
LCD Usage:
lcd test
BUZZER Usage:
buzzer on
buzzer off
buzzer freq 10000
buzzer freq 2000
buzzer freq 100
ADC Usage:
adc test [counts]
printenv --- print all environments values.
setenv ENV_NAME --- delete environments values.
setenv ENV_NAME ENV_VAL --- set environments values.
=============================>
X210 SHELL# lcd test
X210 SHELL# printenv
bootdelay=6
bootcmd=Not found
X210 SHELL# setenv bootargs hello linux.I am x210.
X210 SHELL# printenv
bootdelay=6
bootcmd=Not found
bootargs=hello linux.I am x210.
X210 SHELL# setenv bootcmd 1024
X210 SHELL# printenv
bootdelay=6
bootcmd=1024
bootargs=hello linux.I am x210.
X210 SHELL# setenv bootcmd
X210 SHELL# printenv
bootdelay=6
bootargs=hello linux.I am x210.
X210 SHELL#
ARM 自己实现一个简单的 shell