基于Linux系统下的S5PV210实现远程控制LED和蜂鸣器

1,实现两个设备驱动:蜂鸣器,led灯
2,写一个服务器程序接收客户端命令,根据命令操作不同的设备
3,实现一个客户端程序,向服务器发送命令,控制设备
/*
home_work_client.c
使用select多路复用实现TCP双向通信服务器端代码
实现一个客户端程序,向服务器发送命令,控制设备
*/
#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <pthread.h>
#include <semaphore.h>
#include <sys/time.h>
#include <unistd.h>
int main(int argc,char *argv[])
{
	if(argc!=3){
		perror("argc error");
		exit(1);
	}
	int socket_fd = socket(AF_INET,SOCK_STREAM,0);//ipv4协议,流式套接字
	if(socket_fd==-1){//创建流式套接字失败
		perror("socket error");
		exit(1);
	}
	int on=1;//端口可以重复使用
	setsockopt(socket_fd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
	char ch[100]={};
	struct sockaddr_in server_addr;//连接服务器
	server_addr.sin_family = AF_INET;//ipv4协议
	server_addr.sin_port = htons(atoi(argv[2]));//服务器端口号
	server_addr.sin_addr.s_addr = inet_addr(argv[1]);//服务器主机号	
	int connect_ret = connect(socket_fd,(struct sockaddr *)&server_addr,sizeof(server_addr));
	if(connect_ret==-1){
		perror("connect error");
		exit(1);		
	}
	fd_set send_set;
	while(1){
		FD_ZERO(&send_set);//清空集合
		FD_SET(0,&send_set);//添加0文件描述符
		FD_SET(socket_fd,&send_set);//添加socket_fd文件描述符
		select(socket_fd+1,&send_set,NULL,NULL,NULL);//监测文件描述符
		if(FD_ISSET(0,&send_set)){//判断标准输入
			bzero(ch,sizeof(ch));
			gets(ch);
			send(socket_fd,ch,strlen(ch),0);//发送数据		
		}
		if(FD_ISSET(socket_fd,&send_set)){//判断接收文件描述符
			bzero(ch,sizeof(ch));
			int recv_ret = recv(socket_fd,ch,sizeof(ch),0);//接收数据
			if(recv_ret==0){
				break;
			}
			printf("%s\n",ch);			
		}
	}
	return 0;
}
/*
home_work_server.c
*/
#include "link.h"
#define	LED_ALL_ON	    _IO('L', 0x01)
#define	LED_ALL_OFF	    _IO('L',0x02)
#define	LED_NUM_ON	    _IOW('L', 0x03, int)
#define	LED_NUM_OFF	    _IOW('L',0x04,int)
#define	Buzzer_ON			_IO('B',0x05)
#define	Buzzer_OFF	        _IO('B',0x06)
int main(int argc,char *argv[])
{
	if(argc!=3){
		perror("argc error");
		exit(1);
	}
	char ch[100] = {};//接收缓冲区
	char buf[100] = {};//发送缓冲区
	char ch_head[100]={};//字符串头
	char ch_cmd[100]={};//字符串命令
	char ch_num[100]={};//字符串数据
	char ch_count=0;
	char head_count=0;
	char cmd_count=0;
	char num_count=0;
	int send_fd;//服务器发送的客户端文件描述符
	int socket_fd = socket(AF_INET,SOCK_STREAM,0);//ipv4协议,流式套接字
	if(socket_fd==-1){//创建流式套接字失败
		perror("socket error");
		exit(1);
	}
    int fd = open("/dev/hello2",O_RDWR);
    if(fd<0){
		perror("open error");
		exit(-1);
    }
	int on=1;//端口可以重复使用
	setsockopt(socket_fd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
	
	struct sockaddr_in server_addr;
	server_addr.sin_family = AF_INET;//iPv4
	server_addr.sin_port = htons(atoi(argv[2]));//服务器端口号
	server_addr.sin_addr.s_addr = inet_addr(argv[1]);//服务器IP地址
	int bind_ret = bind(socket_fd,(struct sockaddr *)&server_addr,sizeof(server_addr));
	if(bind_ret==-1){
		perror("bind error");
		exit(1);
	}
	listen(socket_fd,5);//监听套接字
	plink Describe_Link;//套接字文件描述符链表
	plink temp_link;
	int temp_fd;
	fd_set recv_set;//创建集合
	int accept_ret;//连接后的文件描述符
	int Max_nfds = socket_fd;//起始最大文件描述符值
	int ret;
	Init_Link(&Describe_Link);//初始化文件描述符链表
	while(1){
		FD_ZERO(&recv_set);//清空集合
		FD_SET(0,&recv_set);//添加0文件描述符
		FD_SET(socket_fd,&recv_set);//添加socket_fd文件描述符
		
		display(Describe_Link,&recv_set);//遍历链表,添加所有文件描述符
		select(Max_nfds+1,&recv_set,NULL,NULL,NULL);//阻塞等待
		if(FD_ISSET(socket_fd,&recv_set)){//有客户端请求连接
			accept_ret = accept(socket_fd,NULL,NULL);//获取新的套接字文件描述符
			printf("%d is connnect...\n",accept_ret);
			Insert_Link_Head(Describe_Link,accept_ret);//头插到链表中
			Max_nfds = Find_Link_Node(Describe_Link,0);//更新新的最大文件描述符
			//printf("Max_nfds = %d\n",Max_nfds);
		}
		if(FD_ISSET(0,&recv_set)){
			bzero(buf,sizeof(buf));//清空缓冲区
			bzero(ch,sizeof(ch));
			gets(ch);//输入请按这个格式输入4:hello 客户端名字:内容
			sscanf(ch,"%d:%s",&send_fd,buf);//指定客户端发送数据
			send(send_fd,buf,strlen(buf),0);
		}
		temp_link = Describe_Link->next;
		while(temp_link != Describe_Link){//遍历链表,监测所有套接字文件描述符
			if(FD_ISSET(temp_link->data,&recv_set)){
				bzero(ch,sizeof(ch));
				ret = recv(temp_link->data,ch,sizeof(ch),0);
				if(ret == 0){
					temp_fd = temp_link->data;//保存套接字文件描述符
					Del_Link_Data(Describe_Link,temp_link->data);//删除该套接字文件
					//display_value(Describe_Link);
					close(temp_fd);//关闭客户端对应的文件描述符,释放资源,下次再有客户端连接可以使用该文件描述符
					break;
				}
				bzero(ch_head,sizeof(ch_head));
				bzero(ch_cmd,sizeof(ch_cmd));
				bzero(ch_num,sizeof(ch_num));
				printf("%d:%s\n",temp_link->data,ch);
				while(ch[ch_count] != '\0'){
					while(ch[ch_count]!=':'){
						ch_head[head_count++]=ch[ch_count++];
					}
					ch_count++;
					while(ch[ch_count]!=':'){
						ch_cmd[cmd_count++]=ch[ch_count++];
					}
					ch_count++;
					while(ch[ch_count] != '\0')
						ch_num[num_count++]=ch[ch_count++];
					break;
				}
				ch_count=0;
				head_count=0;
				cmd_count=0;
				num_count=0;
				printf("%s--%s--%s\n",ch_head,ch_cmd,ch_num);
				if(strcasecmp(ch_head,"led")==0){
					if(strcasecmp(ch_cmd,"on")==0){
						ioctl(fd,LED_NUM_ON,atoi(ch_num));
						printf("LED_NUM_ON\n");
					}else if(strcasecmp(ch_cmd,"off")==0){
						ioctl(fd,LED_NUM_OFF,atoi(ch_num));
						printf("LED_NUM_OFF\n");
					}else if(strcasecmp(ch_cmd,"allon")==0){
						ioctl(fd,LED_ALL_ON);
						printf("LED_ALL_ON\n");
					}else if(strcasecmp(ch_cmd,"alloff")==0){
						ioctl(fd,LED_ALL_OFF);
						printf("LED_ALL_OFF\n");
					}
				}else if(strcasecmp(ch_head,"buzzer")==0){
					if(strcasecmp(ch_cmd,"on")==0){
						ioctl(fd,Buzzer_ON);
						printf("Buzzer_ON\n");
					}else if(strcasecmp(ch_cmd,"off")==0){
						ioctl(fd,Buzzer_OFF);
						printf("Buzzer_OFF\n");
					}
				}
			}
			temp_link = temp_link->next;
		}
	}
	 close(fd);
	return 0;
}

/*
led_dev.c
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <asm/io.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <linux/slab.h>
#include <linux/virtio.h>
#include <linux/gpio.h>

#define	LED_ALL_ON			_IO('L', 0x01)
#define	LED_ALL_OFF			_IO('L',0x02)
#define	LED_NUM_ON			_IOW('L', 0x03, int)
#define	LED_NUM_OFF			_IOW('L',0x04,int)
#define	Buzzer_ON			_IO('B',0x05)
#define	Buzzer_OFF	        _IO('B',0x06)

#define	GPD0_BASE	0xE02000A0//蜂鸣器基地址
#define	GPC0_BASE	0xE0200060//LED基地址
//定义设备对象
typedef struct s5pv210_led_dev{
	unsigned int major;
	struct class *class;
	struct device *device;	
}s5pv210_led_dev_t,*s5pv210_led_dev_p;
//定义全局实例化对象指针
s5pv210_led_dev_p	Led_Dev;

unsigned	int *gpd_conf;//蜂鸣器控制寄存器
unsigned int *gpd_data;//蜂鸣器数据寄存器
unsigned int *gpc0_conf;//LED控制寄存器
unsigned int *gpc0_data;//LED数据寄存器


// 3.实现操作设备接口
int led_open(struct inode *inode, struct file * filp)
{
	printk("-----------^_^ %s---------------\n",__FUNCTION__);
/*
	//蜂鸣器初始化
	*gpd_conf &= ~(0xf<<4);
	*gpd_conf |= 0x01<<4;//配置输出模式
	*gpd_data &= ~(0x01<<1);//蜂鸣器不响
	//LED初始化
	*gpc0_conf &=~(0xff<<12);
	*gpc0_conf |= 0x11<<12;//配置为输出模式
	*gpc0_data	&=	~(0x03<<3);//led灭	
*/
	return 0;
}
int led_close (struct inode *inode, struct file *filp)
{
	printk("-----------^_^ %s---------------\n",__FUNCTION__);
	*gpd_data &= ~(0x01<<1);//蜂鸣器不响
	*gpc0_data	&=	~(0x03<<3);//led灭	
	return 0;
}
ssize_t led_write (struct file *filp, const char __user *buf, size_t size, loff_t *flags)
{
	int value;
	int ret;
	printk("-----------^_^ %s---------------\n",__FUNCTION__);
	//应用层数据转为内核空间数据
	ret	=	copy_from_user(&value, buf, size);  
	if(ret>0){
		printk("--------copy_from_user error------\n");
		return -EINVAL;
	}
	//根据value的值控制蜂鸣器
#if 0
	if(value==1){// 1蜂鸣器响
		*gpd_data |= 0x01<<1;
	}else if(value==2){// 2蜂鸣器不响
		*gpd_data &= ~(0x01<<1);
	}else if(value==3){//led1亮
		*gpc0_data	&=	~(0x03<<3);//led灭	
		*gpc0_data	|= 0x01<<3;
	}else if(value==4){
		*gpc0_data	&=	~(0x03<<3);//led灭	
		*gpc0_data	|= 0x01<<4;		
	}
#else
	switch(value){
		case 1://蜂鸣器响
			*gpd_data |= 0x01<<1;
			break;
		case 2://蜂鸣器灭
			*gpd_data &= ~(0x01<<1);
			break;
		case 3://led1亮
			*gpc0_data	&=	~(0x03<<3);//led灭	
			*gpc0_data	|= 0x01<<3;			
			break;
		case 4://led2亮
			*gpc0_data	&=	~(0x03<<3);//led灭	
			*gpc0_data	|= 0x01<<4;	
			break;
		default :
			break;
	}
#endif
	return size;
}
long led_ioctl (struct file *filp, unsigned int cmd, unsigned long arg)
{
	int led_num = arg+2;
	printk("-----------^_^ %s---------------\n",__FUNCTION__);	
	switch(cmd){
		case LED_ALL_ON://开所有灯
			//*gpc0_data	|=	0x03<<3;
			gpio_request(S5PV210_GPC0(3),"gpc0_3");
			gpio_direction_output(S5PV210_GPC0(3),1);
			gpio_free(S5PV210_GPC0(3));
			gpio_request(S5PV210_GPC0(4),"gpc0_3");
			gpio_direction_output(S5PV210_GPC0(4),1);
			gpio_free(S5PV210_GPC0(4));
			break;
		case LED_ALL_OFF://关所有灯
			//*gpc0_data	&=	~(0x03<<3);//led灭
			gpio_request(S5PV210_GPC0(3),"gpc0_3");
			gpio_direction_output(S5PV210_GPC0(3),0);
			gpio_free(S5PV210_GPC0(3));
			gpio_request(S5PV210_GPC0(4),"gpc0_3");
			gpio_direction_output(S5PV210_GPC0(4),0);
			gpio_free(S5PV210_GPC0(4));
			break;
		case LED_NUM_ON://开某个灯
			if(led_num!=3 && led_num!=4){
				printk("--------parameter error------\n");
				return -EINVAL;
			}
			gpio_request(S5PV210_GPC0(led_num),"gpc0_3/4");
			gpio_direction_output(S5PV210_GPC0(led_num),1);
			gpio_free(S5PV210_GPC0(led_num));
			//*gpc0_data	|= 0x01<<led_num;	
			break;
		case LED_NUM_OFF://关闭某个灯
			if(led_num!=3 && led_num!=4){
				printk("--------parameter error------\n");
				return -EINVAL;
			}
			gpio_request(S5PV210_GPC0(led_num),"gpc0_3/4");
			gpio_direction_output(S5PV210_GPC0(led_num),0);
			gpio_free(S5PV210_GPC0(led_num));
			//*gpc0_data	&=	~(0x01<<led_num);//led灭
			break;
		case Buzzer_ON://开蜂鸣器
			gpio_request(S5PV210_GPD0(1), "gpd0_1");
			gpio_direction_output(S5PV210_GPD0(1),1);
			gpio_free(S5PV210_GPD0(1));
			break;
		case Buzzer_OFF://关闭蜂鸣器
			gpio_request(S5PV210_GPD0(1), "gpd0_1");
			gpio_direction_output(S5PV210_GPD0(1),0);
			gpio_free(S5PV210_GPD0(1));			
			break;
		default :
			printk("--------parameter error------\n");
			break;
	}
	return 0;
}
const struct file_operations fops = {
	.open 						= 		led_open,
	.release					=		led_close,
	.write						=		led_write,
	.unlocked_ioctl				=		led_ioctl,
};
//模块加载函数
static int __init led_drv_init(void)
{
	int ret;
	printk("--------%s------\n",__FUNCTION__);
	//申请实例化对象空间
	Led_Dev = kzalloc(sizeof(s5pv210_led_dev_t), GFP_KERNEL);
	
	if(IS_ERR(Led_Dev)){
		printk("--------kzalloc error------\n");
		return -ENOMEM;
	}
	
	// 1.动态申请设备号
	Led_Dev->major= register_chrdev(0, "led_drv", &fops);
	if(Led_Dev->major<0){
		printk("--------register_chrdev error------\n");
		goto err_kfree;
	}
	printk("Led_Dev->major=%d\n",Led_Dev->major);
	// 2.创建设备节点
	Led_Dev->class= class_create(THIS_MODULE, "led_class");
	if(IS_ERR(Led_Dev->class)){
		printk("--------class_create error------\n");
		ret=PTR_ERR(Led_Dev->class);
		goto err_unregister_chrdev;
	}
	Led_Dev->device=device_create(Led_Dev->class, NULL, MKDEV(Led_Dev->major, 5), NULL, "hello2");
	if(IS_ERR(Led_Dev->device)){
		printk("--------device_create error------\n");
		ret = PTR_ERR(Led_Dev->device);
		goto err_destorry_class;
	}
	// 4.硬件初始化---地址映射
	//蜂鸣器地址映射
	gpd_conf = ioremap(GPD0_BASE, 8);
	if(IS_ERR(gpd_conf)){
		printk("--------ioremap error------\n");
		ret = PTR_ERR(gpd_conf);
		goto err_device_destory;
	}
	gpd_data = gpd_conf+1;
	//LED地址映射
	gpc0_conf = ioremap(GPC0_BASE, 8);
	if(IS_ERR(gpc0_conf)){
		printk("--------ioremap error------\n");
		ret = PTR_ERR(gpc0_conf);
		goto err_iounmap;
	}
	gpc0_data = gpc0_conf+1;
	
	return 0;
err_iounmap:
	iounmap(gpd_conf);
err_device_destory:
	device_destroy(Led_Dev->class, MKDEV(Led_Dev->major, 5));
err_destorry_class:
	class_destroy(Led_Dev->class);
err_unregister_chrdev:
	unregister_chrdev(Led_Dev->major, "led_drv");
err_kfree:
	kfree(Led_Dev);
	return ret;
	
}
//模块卸载函数
static void __exit led_drv_exit(void)
{
	printk("--------%s------\n",__FUNCTION__);
	iounmap(gpc0_conf);
	iounmap(gpd_conf);
	device_destroy(Led_Dev->class, MKDEV(Led_Dev->major, 5));
	class_destroy(Led_Dev->class);
	unregister_chrdev(Led_Dev->major, "led_drv");
	kfree(Led_Dev);
}
//注册和认证
module_init(led_drv_init);
module_exit(led_drv_exit);
MODULE_LICENSE("GPL");


/*
link.c
*/
#include "link.h"
/*
头指针初始化
*/
void Init_Link(plink *P_Link)
{
	*P_Link = (plink)malloc(sizeof(link));
	if(*P_Link==NULL){
		printf("*P_Link malloc error %s\n",__FUNCTION__);
		return;
	}
	(*P_Link)->next = *P_Link;
}
/*
创建新节点
*/
plink Creat_Node(datatype d)
{
	plink P_Link = (plink)malloc(sizeof(link));
	if(P_Link==NULL){
		printf("Creat_Node malloc error %s\n",__FUNCTION__);
		return;
	}
	P_Link->data = d;
	P_Link->next = P_Link;
	return P_Link;
}
/*
头插法,添加在第一个元素前面
*/
void Insert_Link_Head(plink head,datatype data)
{
	if(head == NULL){
		return ;
	}
	plink node = Creat_Node(data);
	if(node == NULL){
		printf("Creat_Node malloc error %s\n",__FUNCTION__);
	}
	node->next = head->next;
	head->next = node;
}
/*
尾插法,添加在最后一个元素后面
*/
void Insert_Link_Tail(plink head,datatype data)
{
	if(head == NULL){
		return ;
	}
	plink p = head->next;
	while(p->next != head){
		p = p->next;
	}
	plink node = Creat_Node(data);
	if(node == NULL){
		printf("Creat_Node malloc error %s\n",__FUNCTION__);
	}
	node->next = p->next;
	p->next = node;
}
/*
删除一个节点
*/
void Del_Link_Data(plink head,datatype data)
{
	if(head==NULL){
		return;
	}
	plink p = head;
	plink old_node;
	while(p->next!=head){
		if(p->next->data == data){
			old_node=p->next;
			p->next = p->next->next;
			old_node->next = NULL;
			free(old_node);
			continue;
		}
		p = p->next;
	}
}
/*
修改一个节点
*/
void Updata_Link(plink head,datatype Old_data,datatype New_data)
{
	if(head==NULL){
		return;
	}
	plink p = head;
	plink old_node;
	while(p->next!=head){
		if(p->next->data == Old_data){
			old_node=p->next;
			plink New_node=Creat_Node(New_data);
			if(New_node == NULL){
				return;
			}
			New_node->next=p->next->next;
			p->next = New_node;
			old_node->next = NULL;
			free(old_node);
			continue;
		}
		p = p->next;
	}
}
/*
	查询
*/
datatype Find_Link_Node(plink head,datatype data)
{
	if(head==NULL){
		return;
	}
	
	plink p = head->next;
	while(p!=head){
		if(p->data > data){
			data = p->data;
		}
		p = p->next;
	}
	return data;
}
/*
遍历
*/
void display(plink head,fd_set *recv_set)
{
	if(head == NULL){
		return ;
	}
	plink p = head->next;
	while(p!=head){
		FD_SET(p->data,recv_set);//添加每一个文件描述符到集合中
		p = p->next;
	}
}
/*
遍历链表中的值
*/
void display_value(plink head)
{
	if(head == NULL){
		return ;
	}
	plink p = head->next;
	while(p!=head){
		printf("%d\n",p->data);
		p = p->next;
	}
}
/*
link.h
*/
#ifndef __LINK___
#define __LINK___
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
typedef int datatype;
typedef struct linklist{
	datatype data;//数据域
	struct linklist *next;//指向下一个节点
}link,*plink;

extern void Init_Link(plink *P_Link);
extern void Insert_Link_Head(plink head,datatype data);
extern void display(plink head,fd_set *recv_set);
extern void Insert_Link_Tail(plink head,datatype data);
extern void Del_Link_Data(plink head,datatype data);
extern void Updata_Link(plink head,datatype Old_data,datatype New_data);
extern datatype Find_Link_Node(plink head,datatype data);
extern void display_value(plink head);
#endif
/*
Makefile
*/
KERNEL_DIR = /home/zzz/fs210/kerner/linux-3.0.8

CUR_DIR = $(shell pwd)

MYAPP=home_work_server

all:
		make -C	$(KERNEL_DIR)	M=$(CUR_DIR)	modules
		arm-none-linux-gnueabi-gcc -o $(MYAPP)		link.c $(MYAPP).c
		gcc -o home_work_client	link.c home_work_client.c
clean:
		make -C	$(KERNEL_DIR)	M=$(CUR_DIR)	clean
		rm -rf $(MYAPP)
		rm -rf home_work_client
install:
		cp *.ko	$(MYAPP) 	/opt/rootfs/drv_module
obj-m += led_drv.o

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值