本文章以韦东山三期项目实战为基础,进行学习笔记和总结,所用源码出自教程,加上一些自己理解的注释
首先编写fb.c
定义一个opriation结构体
static T_DispOpr g_tFBOpr = {
.name = "fb",
.DeviceInit = FBDeviceInit, //设备初始化
.ShowPixel = FBShowPixel, //显示像素
.CleanScreen = FBCleanScreen,//清除屏幕
};
完善三个函数
首先设备初始化函数
static int FBDeviceInit(void)
{
int ret;
g_fd = open(FB_DEVICE_NAME, O_RDWR); //打开fb设备
if (0 > g_fd)
{
DBG_PRINTF("can't open %s\n", FB_DEVICE_NAME);
}
ret = ioctl(g_fd, FBIOGET_VSCREENINFO, &g_tFBVar); //调用ioctl获取可变参数
if (ret < 0)
{
DBG_PRINTF("can't get fb's var\n");
return -1;
}
ret = ioctl(g_fd, FBIOGET_FSCREENINFO, &g_tFBFix);//调用ioctl获取固定参数
if (ret < 0)
{
DBG_PRINTF("can't get fb's fix\n");
return -1;
}
g_dwScreenSize = g_tFBVar.xres * g_tFBVar.yres * g_tFBVar.bits_per_pixel / 8; //设置屏幕分辨率
//内存映射
g_pucFBMem = (unsigned char *)mmap(NULL , g_dwScreenSize, PROT_READ | PROT_WRITE, MAP_SHARED, g_fd, 0);
if (0 > g_pucFBMem)
{
DBG_PRINTF("can't mmap\n");
return -1;
}
g_tFBOpr.iXres = g_tFBVar.xres; //设置定义的结构体的可变参数的X坐标
g_tFBOpr.iYres = g_tFBVar.yres; //设置定义的结构体的可变参数的Y坐标
g_tFBOpr.iBpp = g_tFBVar.bits_per_pixel; //设置定义的结构体的可变参数的像素位
g_dwLineWidth = g_tFBVar.xres * g_tFBVar.bits_per_pixel / 8; //每行有多少位
g_dwPixelWidth = g_tFBVar.bits_per_pixel / 8; //每个像素占据多少位
return 0;
}
显示像素函数
static int FBShowPixel(int iX, int iY, unsigned int dwColor)
{
unsigned char *pucFB;
unsigned short *pwFB16bpp;
unsigned int *pdwFB32bpp;
unsigned short wColor16bpp; /* 565 */
int iRed;
int iGreen;
int iBlue;
if ((iX >= g_tFBVar.xres) || (iY >= g_tFBVar.yres))
{
DBG_PRINTF("out of region\n");
return -1;
}
pucFB = g_pucFBMem + g_dwLineWidth * iY + g_dwPixelWidth * iX;
pwFB16bpp = (unsigned short *)pucFB;
pdwFB32bpp = (unsigned int *)pucFB;
switch (g_tFBVar.bits_per_pixel) //判断像素为多少位
{
case 8:
{
*pucFB = (unsigned char)dwColor;
break;
}
case 16:
{
iRed = (dwColor >> (16+3)) & 0x1f; //保留5位
iGreen = (dwColor >> (8+2)) & 0x3f; //保留6位
iBlue = (dwColor >> 3) & 0x1f; //保留5位
wColor16bpp = (iRed << 11) | (iGreen << 5) | iBlue; //新的16位像素
*pwFB16bpp = wColor16bpp;
break;
}
case 32:
{
*pdwFB32bpp = dwColor;
break;
}
default :
{
DBG_PRINTF("can't support %d bpp\n", g_tFBVar.bits_per_pixel);
return -1;
}
}
return 0;
}
清屏函数
static int FBCleanScreen(unsigned int dwBackColor)
{
unsigned char *pucFB;
unsigned short *pwFB16bpp;
unsigned int *pdwFB32bpp;
unsigned short wColor16bpp; /* 565 */
int iRed;
int iGreen;
int iBlue;
int i = 0;
pucFB = g_pucFBMem;
pwFB16bpp = (unsigned short *)pucFB;
pdwFB32bpp = (unsigned int *)pucFB;
switch (g_tFBVar.bits_per_pixel)
{
case 8:
{
memset(g_pucFBMem, dwBackColor, g_dwScreenSize);
break;
}
case 16:
{
iRed = (dwBackColor >> (16+3)) & 0x1f;
iGreen = (dwBackColor >> (8+2)) & 0x3f;
iBlue = (dwBackColor >> 3) & 0x1f;
wColor16bpp = (iRed << 11) | (iGreen << 5) | iBlue;
while (i < g_dwScreenSize)
{
*pwFB16bpp = wColor16bpp;
pwFB16bpp++;
i += 2;
}
break;
}
case 32:
{
while (i < g_dwScreenSize)
{
*pdwFB32bpp = dwBackColor;
pdwFB32bpp++;
i += 4;
}
break;
}
default :
{
DBG_PRINTF("can't support %d bpp\n", g_tFBVar.bits_per_pixel);
return -1;
}
}
return 0;
}
fbinit用于向上层注册
int FBInit(void)
{
return RegisterDispOpr(&g_tFBOpr); //向上层注册fb_operation
}
上面就完成了fb.c文件的编写,如果有其他显示设备以此为框架进行模仿,最后向上层注册就可以。
上层的disp.manager.c文件
首先在dis_manager.h 定义一个结构体
typedef struct DispOpr {
char *name; //名字
int iXres; //X坐标
int iYres; //Y坐标
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;
当mian.c中调用需要显示初始化时
int DisplayInit(void)
{
int iError;
iError = FBInit();
return iError;
}
从上边这个初始化函数就能走到刚才的fb.c的init函数,从而在注册结构体并写进disp链表里。
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;
}
显示的一块的差不多就是这样