本帖最后由 Simon21ic 于 2014-8-3 19:02 编辑
虽然有不少专门针对面向对象的开发语言,这里主要讲的还是嵌入式最常用的C语言实现面向对象的编程。
就和我题目说的那样,面向对象是一种编程思想,并不是编程语言,C语言虽然不具备很多面向对象的语法,但是,如果开发人员具备面向对象的编程思想的话,同样可以写出面向对象的代码。
VSF构架的各个驱动模块,中间件,协议栈的设计,都是使用了面向对象的方法来实现各个功能的,当然,并不是所有面向对象的特性都实现了,并且,有部分面向对象的实现针对C语言做一些修改。VSF的类的设计思路,可以理解为完全可重用的模块设计方式。
这里简要介绍一下VSF构架中的模块设计方法,和几个基本原则。
原则:
1. 给用户使用的头文件最小化,只放用户需要知道的结构和函数,其他所有用户不需要知道的结构和函数,不放在给用户使用的头文件里
2. 如果模块实现一个类的话,模块内不能用除类变量以外的所有其他全局变量
举个例子,如果类需要一个实例的计数的话,那这个计数值就是类变量,这个变量不属于类的成员
这样,比较容易实现各个类函数都是可重入的。
3. VSF中的类由类结构和类方法组成
VSF构架下的OOC使用结构来实现一个类,提供的函数接口都是类函数,用于操作所有本类的实例。
4. 软件尽量调用高层的,通用的、抽象的接口,而不要调用底层的
比如,USB的U盘的实现代码,调用mal(内存抽象层的接口),而不是调用实际存储器的驱动。
5. 底层代码不依赖高层,除非高层是一个虚拟层,用来统一访问接口,并且模块只是实现和模块设计功能相关的东西
SD卡的驱动类,需要用到MAL的类(存储器抽象)。
但是framebuffer的驱动不能依赖GUI。
USB主机接口的HID驱动,只是提供各个触发事件的callback函数的接口,至于高层是使用事件队列,还是直接分发事件,也不需要HID驱动关心。
设计举例:
1. 通用驱动类:dal_info_t
struct dal_info_t
{
void *ifs;
void *param;
void *info;
void *extra;
};
根据实现的不同驱动,这个类的各个成员都会被重载。
ifs表示设备需要用到的底层硬件接口;param表示驱动的参数,一般是常量,只占用flash;info是驱动运行的信息,一般是变量占用RAM;extra是一些给和驱动相关的协议栈使用的信息。
再来看一下简单的按键的类驱动:
struct key_interface_t
{
uint8_t port;
uint8_t pin;
};
struct key_param_t
{
bool valid_low;
uint32_t filter_ms;
struct
{
void (*on_PRESS)(struct dal_info_t *info);
void (*on_PRESSED)(struct dal_info_t *info, uint32_t ms);
} callback;
};
struct key_info_t
{
// private
uint32_t tickcnt_on_press;
bool isdown_unfiltered;
bool isdown_filtered;
};
key的底层硬件接口,只需要定义使用哪个端口的哪个引脚。
key的参数是一些基本常数信息和回调函数
key的info是一些key相关的变量。
面向对象的类成员访问控制,在C语言中,无法简单的实现(虽然有其他方式可以实现私有的成员,不过过于麻烦,我这里没有使用),所以,代码上,只是简单标注private,表示是私有变量,用户无需访问。
2. 最简单的framebuffer类,只是实现了页交换
struct vsfui_fb_t
{
struct vsfui_fb_screen_t
{
uint16_t width;
uint16_t height;
uint8_t pixel_size;
struct dal_info_t *dal;
} screen;
// buffer
struct vsf_multibuf_t *mbuffer;
// private
bool displaying;
uint32_t cur_block;
};
其中,screen的dal_info_t其实是一个mal的抽象驱动,显示器的驱动在VSF构架上,实现为存储器的驱动(其实也可以认为是块设备的驱动)。
vsf_multibuf_t是多缓冲的类,实现也交换,就是系统一个进程不停的从多缓冲类中pop可用缓冲并刷到屏幕,其他应用不停地从多缓冲类的要空闲的屏幕缓冲,填好数据后,push进给多缓冲类。
// multi_buffer
struct vsf_multibuf_t
{
uint16_t count;
uint32_t size;
uint8_t **buffer_list;
uint16_t head;
uint16_t tail;
uint16_t length;
};
vsf_err_t vsf_multibuf_init(struct vsf_multibuf_t *mbuffer);
uint8_t* vsf_multibuf_get_empty(struct vsf_multibuf_t *mbuffer);
vsf_err_t vsf_multibuf_push(struct vsf_multibuf_t *mbuffer);
uint8_t* vsf_multibuf_get_payload(struct vsf_multibuf_t *mbuffer);
vsf_err_t vsf_multibuf_pop(struct vsf_multibuf_t *mbuffer);
多缓冲的管理类,其实也只是一个类结构+一系列类函数。
下面贴出fb驱动的所有代码:
vsf_err_t vsfui_fb_init(struct vsfui_fb_t *vsfui_fb)
{
if (vsf_multibuf_init(vsfui_fb->mbuffer) ||
(NULL == vsfui_fb->screen.dal) ||
mal.init(vsfui_fb->screen.dal))
{
return VSFERR_FAIL;
}
vsfui_fb->displaying = false;
return VSFERR_NONE;
}
vsf_err_t vsfui_fb_fini(struct vsfui_fb_t *vsfui_fb)
{
return mal.fini(vsfui_fb->screen.dal);
}
void* vsfui_fb_get_buffer(struct vsfui_fb_t *vsfui_fb)
{
return vsf_multibuf_get_empty(vsfui_fb->mbuffer);
}
vsf_err_t vsfui_fb_validate_buffer(struct vsfui_fb_t *vsfui_fb)
{
return vsf_multibuf_push(vsfui_fb->mbuffer);
}
vsf_err_t vsfui_fb_poll(struct vsfui_fb_t *vsfui_fb)
{
struct dal_info_t *dal_info = vsfui_fb->screen.dal;
struct mal_info_t *mal_info = (struct mal_info_t *)dal_info->extra;
uint64_t block_size = mal_info->capacity.block_size;
uint64_t block_num = mal_info->capacity.block_number;
uint64_t cur_addr;
uint8_t *buffer = vsf_multibuf_get_payload(vsfui_fb->mbuffer);
if (NULL == buffer)
{
return VSFERR_NONE;
}
if (vsfui_fb->displaying)
{
vsf_err_t err;
cur_addr = vsfui_fb->cur_block * block_size;
err = mal.writeblock_nb_isready(dal_info, cur_addr, buffer);
if (err < 0)
{
return err;
}
if (!err)
{
vsfui_fb->cur_block++;
cur_addr = vsfui_fb->cur_block * block_size;
if (vsfui_fb->cur_block >= block_num)
{
mal.writeblock_nb_end(dal_info);
vsf_multibuf_pop(vsfui_fb->mbuffer);
vsfui_fb->displaying = false;
}
else
{
return mal.writeblock_nb(dal_info, cur_addr, &buffer[cur_addr]);
}
}
}
else
{
vsfui_fb->cur_block = 0;
cur_addr = vsfui_fb->cur_block * block_size;
if (mal.writeblock_nb_start(dal_info, 0, block_num, buffer) ||
mal.writeblock_nb(dal_info, cur_addr, &buffer[cur_addr]))
{
return VSFERR_NONE;
}
vsfui_fb->displaying = true;
}
return VSFERR_NONE;
}
在fb驱动高层,是vsfgui的GUI库,这里涉及到的内容太多,就不展开了。
当然,fb驱动并不依赖高层,所以高层使用GUI还是简单的只是刷一些东西,其实并不需要framebuffer层关心。
|