打印
[应用相关]

VSF构架之面向对象的编程思想

[复制链接]
1941|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
Simon21ic|  楼主 | 2014-8-3 01:39 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 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层关心。
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:www.versaloon.com --- under construction

266

主题

2597

帖子

104

粉丝