ARM 自己实现一个 shell 解释器

一、在 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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值