C语言分层设计模式简介

今天给大家带来单片机、嵌入式中比较常用的一种程序设计方法--分层设计模式,内核中就大量采用这种设计方式,一般对于某种硬件体系分为几层,
以一个核心层来管理,它会抽象出硬件或者个体的共性操作来进行管理,很像在用C语言实现面向对象的设计。
下面就以实际代码来简单说明。假设我们有这么一种需求,需要从某些设备读取一些数据,但是这些设备可能有51体系的,也可能有arm体系的。
那么我们应该抽象一个数据结构来表示这种这些发送数据的设备。这就是核心层需要做的工作,假如我们设备有两个共性:
1.使用前需要初始化
2.能收到数据
那么我们的数据结构就应该这么抽象:
struct ReceiveOpr
{
	int (*getDevData)(char data[]);  //设备接收数据的函数
	int (*devInit)();  //设备初始化函数
};
但是核心层管理的不仅仅是一个设备,为了方便核心层能找到某个设备,那么就需要给设备一个标示,这个标示可以有很多种,比如设备名字,产品id等等,
这里我们以设备名来区分。所以上面结构体就应该继续添加名字成员,变为:
struct ReceiveOpr
{
	char *name;  //接收设备的名字
	int (*getDevData)(char data[]);  //设备接收数据的函数
	int (*devInit)();  //设备初始化函数
};
那么核心层如何管理这些设备呢?比较简单也是比较常见的就是设备链表了,也就是我们普通的数据结构链表,所以还需要一个指针,来操作这个设备链表,
于是,结构体应该再添加一个成员,变为:
struct ReceiveOpr
{
	char *name;  //接收设备的名字
	int (*getDevData)(char data[]);  //设备接收数据的函数
	int (*devInit)();  //设备初始化函数
	struct ReceiveOpr *next;  //用来管理链表
};
内核中有种双向链表的数据结构 list_head,它提供了更为强大的链表管理能力,是内核最核心的数据结构之一,有兴趣也可以移植那个来用。
到这里,我们的接收设备的功能抽象就基本完成了(如果在实现过程中发现还需要其他成员,可以随时添加)。
那么核心层如何具体去实现呢?贴一下代码通过注释就能明白。
----------------------------------------------------------------------------------------------------------------
receive_manager.h---输入设备核心层头文件

#ifndef _RECEIVE_MANAGER_H
#define _RECEIVE_MANAGER_H

struct ReceiveOpr
{
	char *name;  //接收设备的名字
	int (*getDevData)(char data[]);  //设备接收数据的函数
	int (*devInit)();  //设备初始化函数
	struct ReceiveOpr *next;  //用来管理链表
};

//函数声明
int registerRecvOpr(struct ReceiveOpr *p);
int selectRecvDev(char *name);
int getDevData(char data[]);
int recvDevInit();
int recvManagerInit();


#endif /* _RECEIVE_MANAGER_H */
----------------------------------------------------------------------------------------------------------------
receive_manager.c---输入设备核心层实现文件

#include <receive_manager.h>
#include <stdio.h>
#include <string.h>

static struct ReceiveOpr *listReceiveHead = NULL; //设备链表的链表头
static struct ReceiveOpr *defaultDev = NULL;	//需要操作的设备指针

/**
 * @brief 核心层提供给具体设备的注册函数,每个设备都要提供上面的结构体指针,然后注册到核心层
 * @param p  表格行数
 */
int registerRecvOpr(struct ReceiveOpr *p)
{
	struct ReceiveOpr *listTmp;

	if (!listReceiveHead)
	{
		listReceiveHead = p;
		p->next = NULL;
	}
	else
	{
		listTmp = listReceiveHead;
		while (listTmp->next)
		{
			listTmp = listTmp->next;
		}
		listTmp->next = p;
		p->next = NULL;
	}
	
	return 0;
}

/**
 * @brief 			根据name在链表中找到相应的设备,然后赋给指针 defaultDev
 * @param name  设备名字
 */
int selectRecvDev(char *name)
{
	struct ReceiveOpr *listTmp = listReceiveHead;
	while (listTmp)
	{	
		if (strcmp(listTmp->name, name) == 0)
		{
			defaultDev = listTmp;
			return 0;
		}
		listTmp++;
	}

	return -1;
}

/**
 * @brief 			根据指定的defaultDev,取出其中的数据,存到data数组中
 * @param data  数组指针
 */
int getDevData(char data[])
{
	int ret;
	
	if(defaultDev)
	{
		ret = defaultDev->getDevData(data);
		return ret;
	}
	else
	{
		return -1;
	}
	
}

/**
 * @brief 根据指定的defaultDev,对其进行初始化
 */
int recvDevInit()
{
	if(defaultDev)
	{
		if(defaultDev->devInit() == 0)
		{
			return 0;
		}
		else
		{
			return -1;
		}
	}
	else
	{
		return -1;
	}
}

/**
 * @brief 对需要管理的设备进行注册,后边会说到
 */
int recvManagerInit()
{
	registerArmRecv();
	return 0;
}

核心层简单的管理工作就完成了,总结下就是:
1.提供 registerRecvOpr 接口给具体设备用,并把设备添加到设备链表
2.提供 recvDevInit、selectRecvDev、getDevData接口给上层用,来选择设备并使用设备
----------------------------------------------------------------------------------------------------------------
那么我们具体的设备要怎么做呢,就是实现核心层定义的结构体,然后注册到核心层即可,下面以一个模拟设备来说明
arm_recv.c---假设这是arm体系下一个设备,功能没有实现,只是模拟用

#include <receive_manager.h>

static char buf[16];
static int fd;

static int getArmRecvDev(char data[]);
static int armRecvInit();

//这是核心层提供的设备抽象,具体设备文件就是需要去挨个实现这些成员
static struct ReceiveOpr armRecvDev = {
	.name          	= "arm_recv",
	.getDevData	= getArmRecvDev,
	.devInit		= armRecvInit,
};

//提交数据的函数,只是模拟而已
static int getArmRecvDev(char data[])
{
	int i, j=0;
	int ret;

	ret = read(fd, buf, 16);
	if(ret > 0)
	{
		for(i=0; i<16; i++)
		{	
			if(i%2 == 0)
			{
				data[j] = buf[i];
				j++;
			}
		}		
		return (ret / 2);
	}
	else
	{
		return -1;
	}
}

//设备初始化函数
static int armRecvInit()
{
	fd = open("/dev/power", O_RDWR);
	if (fd < 0)
	{
		printf("can't open arm_recv!\n");
		return -1;
	}
	else
	{
		printf("open arm_recv success!\n");
	}

	return 0;
}

//注册函数,核心层初始化时候会依次调用各个设备的注册函数
int registerArmRecv(void)
{
	return registerRecvOpr(&armRecvDev);
}

这里只是举了一个例子,具体的设备功能当然要复杂的多,假如还有个51体系的,或者stm32的,那么完全可以再实现两个文件:51recv.c和stm32.c来注册
到核心层。
----------------------------------------------------------------------------------------------------------------
最后,来看下上层如何通过核心层来操作具体设备
main.c---使用实例

#include "receive_manager.h"

int main(int argc, char **argv)
{
	int ret;
	char buf[8];
	
	recvManagerInit();  //注册各个输入设备
	selectRecvDev("arm_recv");	//选择要操作的设备
	recvDevInit();	//对选择的设备进行初始化


	while(1)
	{
		ret = getDevData(buf);  //操作设备
		printf("%d\n", ret);
	}
}

简单吧,这样的设计使我们的程序层次感更加明了,方便管理我们的项目。这里只是简单的做了介绍,实际项目中使用的核心层管理要复杂的多,具体需要
阅读更多的源码来深入体会。最后,提供几个比较好的开源c源码,有兴趣可以读一下,祝大家学习愉快~
http://developer.51cto.com/art/201410/454880.htm


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

浓咖啡jy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值