分类: 嵌入式
2015-08-23 16:39:07
display_manager.c
15年8月22日12:55:21
#include <config.h>
#include <disp_manager.h>
#include <string.h>
static PT_DispOpr g_ptDispOprHead;
int RegisterDispOpr(PT_DispOpr ptDispOpr)
{
PT_DispOpr ptTmp;
if (!g_ptDispOprHead)
{
g_ptDispOprHead = ptDispOpr;
ptDispOpr->ptNext = NULL;
}
else
{
ptTmp = g_ptDispOprHead;
while (ptTmp->ptNext)
{
ptTmp = ptTmp->ptNext;
}
ptTmp->ptNext = ptDispOpr;
ptDispOpr->ptNext = NULL;
}
return 0;
}
void ShowDispOpr(void)
{
int i = 0;
PT_DispOpr ptTmp = g_ptDispOprHead;
while (ptTmp)
{
printf("%02d %s\n", i++, ptTmp->name);
ptTmp = ptTmp->ptNext;
}
}
PT_DispOpr GetDispOpr(char *pcName)
{
PT_DispOpr ptTmp = g_ptDispOprHead;
while (ptTmp)
{
if (strcmp(ptTmp->name, pcName) == 0)
{
return ptTmp;
}
ptTmp = ptTmp->ptNext;
}
return NULL;
}
int DisplayInit(void)
{
int iError;
iError = FBInit();
return iError;
}
display_manager.h
#ifndef _DISP_MANAGER_H
#define _DISP_MANAGER_H
typedef struct DispOpr {
char *name;
int iXres;
int iYres;
int iBpp;
int (*DeviceInit)(void);
int (*ShowPixel)(int iPenX, int iPenY, unsigned int dwColor);
int (*CleanScreen)(unsigned int dwBackColor);
struct DispOpr *ptNext;
}T_DispOpr, *PT_DispOpr;
int RegisterDispOpr(PT_DispOpr ptDispOpr);
void ShowDispOpr(void);
int DisplayInit(void);
int FBInit(void);
#endif /* _DISP_MANAGER_H */
下面来分析这两个文件:
首先来分析display_manager.h这个头文件:
(1)文件的开头用了一个这样的技巧,是为了防止包含重复的头文件,这个技巧应该会运用。
#ifndef _DISP_MANAGER_H
#define _DISP_MANAGER_H
(2)分析DispOpr 这个结构体:
typedef struct DispOpr {
char *name; /* 名称,根据名字来找到这个设备 */
int iXres; /* x方向的最大分辨率 */
int iYres; /* y方向的最大分辨率 */
int iBpp; /* bit per pixel */
int (*DeviceInit)(void); /* 初始化设备 */
int (*ShowPixel)(int iPenX, int iPenY, unsigned int dwColor);
/* 在(iPenX,iPenY)这个点上显示 dwColor这个颜色 */
int (*CleanScreen)(unsigned int dwBackColor); /* 清屏 */
struct DispOpr *ptNext; /* 链表中指向下一个结构体的指针 */
}T_DispOpr, *PT_DispOpr;
这个结构体中这样设置成员是因为在显示的时候,需要使用到比如说lcd屏幕的x,y方向的最大值,bpp等信息,同时,包含显示所用到的函数,包括设备的初始化DeviceInit,显示像素 ShowPixel和清屏 CleanScreen等操作。对于每一个显示器,它都应该对应一个这样的结构体,而这个结构体应该包含所有显示器用到的所有特点。
(3)其他的是diaplay_manager.c中定义的函数的声明。
下面分析diaplay_manager.c这个文件:
diaplay_manager.c这个文件中定义了可以供draw.c调用的用于显示的函数。
(1)首先定义一个链表头:static PT_DispOpr g_ptDispOprHead;这个电子书所有支持的显示器都包含在这个链表中,如fb(LCD)和crt(串口)。
(2)注册显示器操作函数,每个显示器对应一个 PT_DispOpr结构体,这个函数是将所有的显示器对应的结构体添加到 g_ptDispOprHead这个链表中,这样用到的时候就可以通过名字来从这个链表中找到对应的结构体,找到以后在初始化这个显示器。
int RegisterDispOpr(PT_DispOpr ptDispOpr)
{
PT_DispOpr ptTmp;
if (!g_ptDispOprHead)
{
g_ptDispOprHead = ptDispOpr;
ptDispOpr->ptNext = NULL;
}
/* 如果链表头为空的话, ptDispOpr就为这个链表中的第一项,同时, ptDispOpr->ptNext指
* 向一个NULL,这是链表的基本操作。
*/
else
{
ptTmp = g_ptDispOprHead;
while (ptTmp->ptNext)
{
ptTmp = ptTmp->ptNext;
}
ptTmp->ptNext = ptDispOpr;
ptDispOpr->ptNext = NULL;
}
/* 如果链表头不为空,用while循环来遍历链表,直到找到这个链表的最后一项(即ptTmp->ptNext为
* 空的一项),将最后一项的ptNext指向新加入的结构体,同时 ptDispOpr->ptNext指向NULL。
*/
return 0;
}
函数返回值: 成功 --- 0
失败 --- 其他值
(3)这个函数将链表中的每一项一一取出,打印出来他们的名字。
void ShowDispOpr(void)
{
int i = 0;
PT_DispOpr ptTmp = g_ptDispOprHead;
while (ptTmp) /* 遍历链表中的每一项 */
{
printf("%02d %s\n", i++, ptTmp->name);
ptTmp = ptTmp->ptNext;
}
}
(4)获取显示操作函数:
PT_DispOpr GetDispOpr(char *pcName)
{
PT_DispOpr ptTmp = g_ptDispOprHead;
while (ptTmp)
{
if (strcmp(ptTmp->name, pcName) == 0)
{
return ptTmp;
}
ptTmp = ptTmp->ptNext;
}
return NULL;
}
/* 将函数传进来的参数pcName与链表中每一项的名字做比较,如果相同,就返回这个结构体,如果遍历
* 链表以后仍没有找到名字相同的一项,则返回NULL。
*/
(5)显示器初始化函数:
int DisplayInit(void)
{
int iError;
iError = FBInit();
return iError;
}
/* 这个函数只是调用 FBInit()函数注册了一下。 */