电子书---显示子模块

一、显示子模块介绍
本文要实现display文件夹下的两个文件: fb.c   disp_manager.c, 以及include文件夹下的 disp_manager.h、config.h
他们之间的关系如下图所示

电子书-显示子模块

二、显示子模块代码实现
config.h
#ifndef _CONFIG_H
#define _CONFIG_H

// #define DBG_PRINTF(...)  // 取消打印
#define DBG_PRINTF printf
#define FB_DEVICE_NAME "/dev/fb0"

#endif /* _CONFIG_H */
disp_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 dwBkgdColor);
    struct DispOpr *ptNext;
}T_DispOpr, *PT_DispOpr;

#endif /* _DISP_MANAGER_H */
disp_manager.c
#include <disp_manager.h>
#include <config.h>
#include <string.h>  // strcmp

/* g_ptDispOprHead 全局链表头指针 */
static PT_DispOpr g_ptDispOprHead;

/**********************************************************************
* 函数名称: RegisterDispOpr
* 功能描述: 注册DispOpr结构体到g_ptDispOprHead指向的全局链表
* 输入参数: PT_DispOpr ptDispOpr,fb.c或其他下层文件提供的结构体
* 输出参数: int
  * 返 回 值: 0-成功  
   * 其它说明: 无
* 修改日期           版本号      修改人       修改内容
 * -----------------------------------------------
* 2020/05/9   V1.0   XXXX       XXXX
***********************************************************************/
int RegisterDispOpr(PT_DispOpr ptDispOpr)
{
    PT_DispOpr ptTmp;
    
    if(!g_ptDispOprHead)
    {
        g_ptDispOprHead = ptDispOpr;
        g_ptDispOprHead->ptNext = NULL;
    }
    else
    {
        ptTmp = g_ptDispOprHead;
        while (ptTmp->ptNext)
        {
            ptTmp = ptTmp->ptNext;
        }
        ptTmp->ptNext = ptDispOpr;
        ptDispOpr->ptNext = NULL;
    }
    ptTmp = NULL;
    return 0;
}
/**********************************************************************
* 函数名称: ShowDispOpr
* 功能描述: 打印g_ptDispOprHead指向的全局链表的所有节点
* 输入参数: void
* 输出参数: void
  * 返 回 值: 无  
   * 其它说明: 无
* 修改日期           版本号      修改人       修改内容
 * -----------------------------------------------
* 2020/05/9   V1.0   XXXX       XXXX
***********************************************************************/
void ShowDispOpr(void)
{
    int i = 0;
    PT_DispOpr ptTmp = g_ptDispOprHead;
    
    while(ptTmp)
    {
        printf("%02d %s\n", i++, ptTmp->name);
        ptTmp = ptTmp->ptNext;
    }
    ptTmp = NULL;
}
/**********************************************************************
* 函数名称: GetDispOpr
* 功能描述: 根据名字从全局链表找到对应的DispOpr结构体
* 输入参数: char* pcName
* 输出参数: PT_DispOpr
  * 返 回 值: 成功返回指向DispOpr的指针,否则返回NULL 
   * 其它说明: 无
* 修改日期           版本号      修改人       修改内容
 * -----------------------------------------------
* 2020/05/9   V1.0   XXXX       XXXX
***********************************************************************/
PT_DispOpr GetDispOpr(char* pcName)
{
    PT_DispOpr ptTmp = g_ptDispOprHead;
    
    while(ptTmp)
    {
        if(strcmp(ptTmp->name, pcName) == 0)
        {
            return ptTmp;
        }
        ptTmp = ptTmp->ptNext;
    }
    ptTmp = NULL;
    return NULL;
}
/**********************************************************************
* 函数名称: DisplayInit
* 功能描述: 调用下层(如fb.c)的初始化函数进行显示初始化
* 输入参数: void
* 输出参数: int
  * 返 回 值: 返回调用的初始化函数的返回值 
   * 其它说明: 无
* 修改日期           版本号      修改人       修改内容
 * -----------------------------------------------
* 2020/05/9   V1.0   XXXX       XXXX
***********************************************************************/
int DisplayInit(void)
{
    int iError;
    iError = FBInit();
    return iError;
}
fb.c
#include <config.h>
#include <disp_manager.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/fb.h>
#include <string.h>
#include <sys/mman.h>

/* 函数声明 */
static int FBDeviceInit(void);
static int FBShowPixel(int iX, int iY, unsigned int dwColor);
static int FBCleanScreen(void);

/* 全局变量 */
static int g_fd;
static unsigned int g_dwLineWidth ;
static unsigned int g_dwPixelWidth;
static unsigned int g_dwScreenSize;

static unsigned char* g_pucFbMem;
static struct fb_var_screeninfo g_tFBVar;
static struct fb_fix_screeninfo g_tFBFix;

static T_DispOpr g_tFBOpr = {
	.name = "fb",
    	.DeviceInit  = FBDeviceInit,
    	.ShowPixel   = FBShowPixel,
    	.CleanScreen = FBCleanScreen,
};
/**********************************************************************
* 函数名称: FBDeviceInit
* 功能描述: LCD显示的初始化,包括打开LCD设备、获得LCD参数
* 输入参数: void
* 输出参数: int
  * 返 回 值: 0-成功  -1-失败 
   * 其它说明: 无
* 修改日期           版本号      修改人         修改内容
 * -----------------------------------------------
* 2020/05/9       V1.0    XXXX        XXXX
***********************************************************************/
static int FBDeviceInit(void)
{
	g_fd = open(FB_DEVICE_NAME, O_RDWR); 
	if(g_fd < 0)
	{
		DBG_PRINTF("can't open /dev/fb0\n");
		return -1;
	}
 	if(ioctl(g_fd, FBIOGET_VSCREENINFO, &g_tFBVar))
 	{
  		DBG_PRINTF("can't get var\n");
  		return -1;
	}
 	if(ioctl(g_fd, FBIOGET_FSCREENINFO, &g_tFBFix))
 	{
  		DBG_PRINTF("can't get fix\n");
  		return -1;
 	}
 	g_dwLineWidth  = g_tFBVar.xres * g_tFBVar.bits_per_pixel / 8;
 	g_dwPixelWidth = g_tFBVar.bits_per_pixel / 8;
 	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(g_pucFbMem == (unsigned char*)-1)
 	{
  		DBG_PRINTF("can't map g_pucFbMem\n");
  		return -1;
 	}
   	g_tFBOpr.iXres = g_tFBVar.xres;
    	g_tFBOpr.iYres = g_tFBVar.yres;
	g_tFBOpr.iBpp  = g_tFBVar.bits_per_pixel;
    	return 0;
}
/**********************************************************************
* 函数名称: FBShowPixel
* 功能描述: 根据不同bpp,显示LCD某像素点(X,Y)
* 输入参数: int iX, int iY, unsigned int dwColor
             int iX: LCD屏幕上的X坐标
             int iY: LCD屏幕上的Y坐标
             int dwColor: RGB颜色值:0x00RRGGBB
* 输出参数: int
  * 返 回 值: 0-成功  -1-失败 
   * 其它说明: 无
* 修改日期           版本号      修改人         修改内容
 * -----------------------------------------------
* 2020/05/9       V1.0    XXXX        XXXX
***********************************************************************/
static int FBShowPixel(int iX, int iY, unsigned int dwColor)
{
	unsigned char*  pucPen8pp   = NULL;
 	unsigned short* pwPen16pp   = NULL;
 	unsigned int*   pdwPen32pp  = NULL;
 	unsigned short  wColor16bpp;   /* 565 */
 	unsigned int ired;
    	unsigned int igreen;
   	unsigned int iblue;
    	if ((iX >= g_tFBVar.xres) || (iY >= g_tFBVar.yres))
    	{
        	DBG_PRINTF("out of region\n");
        	return -1;
    	}	
    	pucPen8pp  = g_pucFbMem + iY*g_dwLineWidth + iX*g_dwPixelWidth;
 	pwPen16pp  = (unsigned short*)pucPen8pp;
 	pdwPen32pp = (unsigned int*)pucPen8pp;
 	switch(g_tFBVar.bits_per_pixel)
 	{
  		case 8:
  		{
   			*pucPen8pp = (unsigned char)dwColor;
   			break;
  		}
  		case 16:
  		{
   			ired   = (dwColor >> (16+3)) & 0x1f;
   			igreen = (dwColor >> (8+2)) & 0x3f;
   			iblue  = (dwColor >> 3) & 0x1f;
   			wColor16bpp = ((ired << 11) | (igreen << 5) | iblue);
   			*pwPen16pp  = wColor16bpp;
   			break;
  		}
  		case 32:
  		{
   			*pdwPen32pp = dwColor;
   			break;
  		}
  		default:
  		{
   			DBG_PRINTF("can't surport %dbpp\n",var.bits_per_pixel);
   			return -1;
  		}
 	}
    	return 0;
}
/**********************************************************************
* 函数名称: FBCleanScreen
* 功能描述: 将LCD清屏为某种颜色
* 输入参数: unsigned int dwBackColor: RGB颜色值:0x00RRGGBB
* 输出参数: int
  * 返 回 值: 0-成功  -1-失败 
   * 其它说明: 无
* 修改日期           版本号      修改人         修改内容
 * -----------------------------------------------
* 2020/05/9       V1.0    XXXX        XXXX
***********************************************************************/
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
* 功能描述: 调用disp_manager.c提供的注册函数进行初始化
* 输入参数: void
* 输出参数: int
  * 返 回 值: 注册函数的返回值 
   * 其它说明: 无
* 修改日期           版本号      修改人         修改内容
 * -----------------------------------------------
* 2020/05/9       V1.0    XXXX        XXXX
***********************************************************************/
int FBInit(void)
{
	return RegisterDispOpr(&g_tFBOpr);
}
编译检查有无语法或书写错误,如下

显示子模块的编译检查

从上面源码,要掌握什么?
1)编程规范
 	对应变量命名,要见名知意。不仅要标识该变量类型,也要有意义。
 	如g_pucFbMem 表示是一个unsigned char * 类型的全局变量,且表示指向FB的显存起始映射地址
2)static 的 作用
 	用static修饰的变量或函数表示仅限本文件内使用,这样,对其它源文件就看不见了。
3)头文件那么多,怎知道要包含哪些?
 	方法一:对于glibc提供的函数, man -2 函数名 ,或到glibc目录下查找 grep "标识符" -nR
 	方法二:对于第三方库提供的函数,可到对应第三方库目录下搜索: grep   "标志位或函数名等标识符" -nR
 	举个例子,查找“PROT_READ”标志位需包含的头文件,如下图 	

查找头文件举例

4)注释
	对于函数,需在函数前注释函数功能、输入/输出参数、返回值等,如上面源码
	对于全局变量,其实也要加以注释的(上面源码未加),因为全局变量的含义最难理清(可被本文件任何地方使用
	(如果是static的话),或者被任何文件使用(非static)),因此很有必要注释
	此外,除了函数名和变量,在每个文件(.h .c .config等)头部都需注释(然而,上面源码还是没注释,原谅我lan : )

OK,本文到此结束,下文讲解如何获取不同的点阵数据(位图)(点阵数据来源有点阵文件、HZK16、矢量字体(freetype))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值