limingth 发表于 2005-6-6 23:31:22

Learn lumit Step 8 : 代码可复用性

Learn lumit Step 8 :代码可复用性
++++++++++++++++++++++++++++++++++++++++++++++++++++++

    至此,前面大致介绍了 lumit4510 开发板上 bootloader 启动的基本知识点。
后面,我们将以板上的每一个硬件设备驱动程序为例,分析一下每个硬件驱动是如何
让硬件工作起来的。

    在重写这些设备接口的过程中,我们希望能够在最大程度上将与硬件无关的代码
提供给大家,以便移植和重用;而把和硬件相关的最底层的那些实现独立出来,单独
实现为一个类似linux设备驱动的driver。这样,大家需要做的仅仅是根据你自己的
硬件设计修改最底层的接口函数,而绝大部分的上层代码都可以无需修改移植到新的
板子上。
   
    首先,我们以 LED 灯的驱动为例,来说明这个想法。本来这个驱动是非常简单的,
甚至只用几个宏定义就能实现 LED 灯的点亮和熄灭,但在这里我们反过来,把简单的
东西复杂化,为的是建立一种结构和层次来应付更多复杂的问题。

    这个项目下有 4 个和 led 相关的文件,分别是 led_driver.c[.h] led_api.c[.h]
顾名思义即可知道 led_driver 是底层的硬件相关实现代码,led_api 是提供给上层的
统一接口,与底层硬件无关。

    我们从底层开始介绍 led_driver 的实现,主要是有如下五个函数:

int led_open( void );

int led_read( char * buf, int count );

int led_write( char * buf, int count );

int led_ioctl( unsigned int cmd, unsigned long arg );

int led_release( void );

    其中 open, read, write, ioctl, release 是模仿了 linux 设备驱动的写法,尽量
采用了统一的接口,将设备操作虚拟为文件读写来进行。以 led_read 为例:

int led_read( char * buf, int count )
{       
        int i = 0;
       
        // the count has exceeds the count of our board
        if( count > 4 )
                return -1;
               
        for( i = 0; i < count; i++ )
                buf = led_status;       
               
        return 0;
}

    我们分析一下 led 设备的读操作,输入参数是读缓冲 buf 指针和要读的字节数 count 。
如果每次读字节数超过 4 个(led),则我们认为错误,返回 -1 ;否则我们将前面 count 个
led 的状态信息,分别写入 buf 指针中,0 表示 OFF,1 表示 ON ,并直接返回 count
表示已经成功读出 count 字节的设备数据。

    同样 led 写操作也类似,即将从上层传入的 buf 信息,写入 led 对应的 led_status
内部状态标识数组中,同时修改 IO 寄存器相应位来实现对硬件的驱动,真正点亮或者熄灭
led 小灯。

    这里我们还定义了 LED_NUM 表示目前只支持 4 个 led 。

    但是对于上层用户来说,这样的驱动接口很不直观,也很难直接用于应用编程中。因此,
我们实现了 led_api 来对 led_driver 进行一次封装,使得 led_api 提供的接口更为直观,
具有更好的代码可读性和可移植性,这两点对于嵌入式程序来说是非常重要的。

    led_api 主要实现了如下一系列接口:
int led_init( void );

/* get 4 leds status to low-4-bits of hex value */
int led_get_value( void );

/* set hex value of low-4-bits to 4 leds */
int led_set_value( int value );

int led_all_light( void );

int led_all_dark( void );

int led_all_blink( void );

int led_one_light( int position );

int led_one_dark( int position );

int led_one_blink( int position );

int led_test( void );

    其中,led_init 是硬件初始化函数,实际调用的即驱动的 open 操作;led_set_value
和 led_get_value 是以 32 位整型数的每一个 bit 表示一个 led 灯,进行设置和读取的接口;
其他的 led_ 函数,主要就是点亮和熄灭以及闪烁的接口,分为全部和单个两组;在最后是一个
led_test 函数,是为了便于用户调用和理解写的一个接口测试例子,如果对 led_api 不熟悉,
就可以先用 led_test 做一下测试,看看应该如何传递参数和获得返回结果。

    对于上层调用来说,使用的是抽象出来的个数为 LED_NUM 的 led 灯。它可以在实际使用中
灵活调整,底层的硬件驱动则保证了当传入的 count 超过 4 的时候,硬件驱动接口返回失败,
表示无法执行对该设备的读/写操作,原因是底层硬件不支持。

    因此,当在一个新的开发板上实现 led 接口的时候,只需要对 led_driver 做改动,而无需
修改 led_api 已有的接口,可以直接重用;这样分层结构的好处是,便于为上层的复杂应用提供
更多的接口,更快地实现上层需求,同时底层共用一个统一的驱动接口,大家就可以为 led_api
增添更多的 api 来实现不同的闪烁效果,例如跑马灯等。

    当每个人都为 led_api 贡献一个 api 的时候,就避免了其他人在自己系统之上再去实现这个
api 的工作,减少了大量的重复劳动,而可以把工作专注于上层的应用开发和底层的驱动接口实现。
我想,这也是 lumit 开源项目的目标之一。

珊瑚虫 发表于 2005-7-1 15:33:10

版主:
  Learn-lumit-Step-8是什么文件啊?怎么打不开啊?

limingth 发表于 2005-7-1 15:35:37

就是一个 zip 的压缩文件,你的下载有问题,我这里下载后可以打开。
页: [1]
查看完整版本: Learn lumit Step 8 : 代码可复用性