linux应用项目(一)数码相框(3)数码相框之电子书

一、整体思路

这一节我们重点学习框架,就是编程的思想。架构很重要。采用分层的思想,面向对象的编程思想。

linux应用项目(一)数码相框(3)数码相框之电子书_第1张图片

1、怎样在LCD上显示一个文件

linux应用项目(一)数码相框(3)数码相框之电子书_第2张图片

2、如何组织代码

分层的结构

main--draw--XXX_manager--fb.c等

linux应用项目(一)数码相框(3)数码相框之电子书_第3张图片

linux应用项目(一)数码相框(3)数码相框之电子书_第4张图片

二、分层编写-底层实现

1、显示部分代码编写

show_file\display\fb.c
show_file\display\disp_manager.c
show_file\include\config.h
show_file\include\disp_manager.h
show_file\draw\draw.c

先写fb.c 一面向对象编程思想

设置构造一个结构体

结构体需要有哪些成员呢:

显示部分,一定有一个显示函数,FB要显示就要初始化,所以有一个fb初始化函数,换页的时候我们要进行清屏操作,要有一个清屏函数,所以要有3个函数。

(1)    fb初始化

(2)    显示函数

(3)    清屏函数

只有函数还不全,还需要一些属性,如定义一个名字“fb”,X坐标,Y坐标,多少位表示一个像素等属性。

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;
fb.c初始化结构体,并写出对应的函数。
static T_DispOpr g_tFBOpr = {
	.name        = "fb",
	.DeviceInit  = FBDeviceInit,
	.ShowPixel   = FBShowPixel,
	.CleanScreen = FBCleanScreen,
};

结构体用到这些函数 ,所以事先声明一下,都是static所以只能在本文件中使用,外面想用只能通过上一层。

static int FBDeviceInit(void);
static int FBShowPixel(int iX, int iY, unsigned int dwColor);
static int FBCleanScreen(unsigned int dwBackColor);

在哪注册?

int FBInit(void)
{
	return RegisterDispOpr(&g_tFBOpr);
}

这里就不能写成static了。

注册就是把结构体加入链表中,链表比数组更灵活,大小随意。

一开始链表头是空的,所以让指针指向这个结构体。在注册就让next指向新结构体。

实现三个函数:

注意这里是应用程序所以是一些open,read等函数。

如:g_fd = open(FB_DEVICE_NAME, O_RDWR);

这里不应该把设备名字定死,所以写一个config文件

#ifndef _CONFIG_H
#define _CONFIG_H

#include 

#define FB_DEVICE_NAME "/dev/fb0"

#define COLOR_BACKGROUND   0xE7DBB5  /* 泛黄的纸 */
#define COLOR_FOREGROUND   0x514438  /* 褐色字体 */

#define DBG_PRINTF(...)  
//#define DBG_PRINTF printf

#endif /* _CONFIG_H */

DBG_PRINTF:这个宏可以控制打印开关。

显示做好了,但是我们显示内容在哪呢?需要设置显示字体,得到显示的点阵。如显示ASCII还是ABK,还是freetype。同理写出这部分代码。

代码:

fb.c:重点是结构

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

static int FBDeviceInit(void);
static int FBShowPixel(int iX, int iY, unsigned int dwColor);
static int FBCleanScreen(unsigned int dwBackColor);


static int g_fd;

static struct fb_var_screeninfo g_tFBVar;  //可变参数
static struct fb_fix_screeninfo g_tFBFix;	 //固定参数
static unsigned char *g_pucFBMem;          //内存映射
static unsigned int g_dwScreenSize;        //FB屏幕大小

static unsigned int g_dwLineWidth;         //一行宽度:一行的像素*像素位数/8字节    
static unsigned int g_dwPixelWidth;        //每个像素占据多少字节:BPP/8=2字节(一个像素占据2字节)

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);
	if (0 > g_fd)
	{
		DBG_PRINTF("can't open %s\n", FB_DEVICE_NAME);
	}

	ret = ioctl(g_fd, FBIOGET_VSCREENINFO, &g_tFBVar);
	if (ret < 0)
	{
		DBG_PRINTF("can't get fb's var\n");
		return -1;
	}

	ret = ioctl(g_fd, FBIOGET_FSCREENINFO, &g_tFBFix);
	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;
	g_tFBOpr.iYres       = g_tFBVar.yres;
	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;
}

//RRGGBB  16: 24转成565
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;
			iGreen = (dwColor >> (8+2)) & 0x3f;
			iBlue  = (dwColor >> 3) & 0x1f;
			wColor16bpp = (iRed << 11) | (iGreen << 5) | iBlue;
			*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;
}

int FBInit(void)
{
	return RegisterDispOpr(&g_tFBOpr);
}
disp_manager.c:重点是链表操作

#include 
#include 
#include 

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;
}

2、字体部分编写

思路如上一样,分配、设置、注册结构体。

3、编码部分编写

思路如上一样,分配、设置、注册结构体。

三、分层编写-上层实现

1、draw.c

组织底层代码
linux应用项目(一)数码相框(3)数码相框之电子书_第5张图片

2、main.c

解析命令-打开文本-显示文本-换页-返回上一页等

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 


/* ./show_file [-s Size] [-f freetype_font_file] [-h HZK]  */
int main(int argc, char **argv)
{
	int iError;
	unsigned int dwFontSize = 16;
	char acHzkFile[128];
	char acFreetypeFile[128];
	char acTextFile[128];

	char acDisplay[128];

	char cOpr;
	int bList = 0;

	acHzkFile[0]  = '\0';
	acFreetypeFile[0] = '\0';
	acTextFile[0] = '\0';

	strcpy(acDisplay, "fb");
	
	while ((iError = getopt(argc, argv, "ls:f:h:d:")) != -1)
	{
		switch(iError)
		{
			case 'l':
			{
				  bList = 1;
				  break;
			}
			case 's':
			{
				  dwFontSize = strtoul(optarg, NULL, 0);
				  break;
			}
			case 'f':
			{
				  strncpy(acFreetypeFile, optarg, 128);
				  acFreetypeFile[127] = '\0';
				  break;
			}			
			case 'h':
			{
					strncpy(acHzkFile, optarg, 128);
					acHzkFile[127] = '\0';
					break;
			}
			case 'd':
			{
				strncpy(acDisplay, optarg, 128);
				acDisplay[127] = '\0';
				break;
			}
			default:
			{
					printf("Usage: %s [-s Size] [-d display] [-f font_file] [-h HZK] \n", argv[0]);
					printf("Usage: %s -l\n", argv[0]);
					return -1;
					break;
			}
		}
	}

	if (!bList && (optind >= argc))
	{
		printf("Usage: %s [-s Size] [-d display] [-f font_file] [-h HZK] \n", argv[0]);
		printf("Usage: %s -l\n", argv[0]);
		return -1;
	}
		
	iError = DisplayInit();
	if (iError)
	{
		printf("DisplayInit error!\n");
		return -1;
	}

	iError = FontsInit();
	if (iError)
	{
		printf("FontsInit error!\n");
		return -1;
	}

	iError = EncodingInit();
	if (iError)
	{
		printf("EncodingInit error!\n");
		return -1;
	}

	if (bList)
	{
		printf("supported display:\n");
		ShowDispOpr();

		printf("supported font:\n");
		ShowFontOpr();

		printf("supported encoding:\n");
		ShowEncodingOpr();
		return 0;
	}

	strncpy(acTextFile, argv[optind], 128);
	acTextFile[127] = '\0';
		
	iError = OpenTextFile(acTextFile);
	if (iError)
	{
		printf("OpenTextFile error!\n");
		return -1;
	}

	iError = SetTextDetail(acHzkFile, acFreetypeFile, dwFontSize);
	if (iError)
	{
		printf("SetTextDetail error!\n");
		return -1;
	}

	DBG_PRINTF("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);

	iError = SelectAndInitDisplay(acDisplay);
	if (iError)
	{
		printf("SelectAndInitDisplay error!\n");
		return -1;
	}
	
	DBG_PRINTF("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
	iError = ShowNextPage();
	DBG_PRINTF("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
	if (iError)
	{
		printf("Error to show first page\n");
		return -1;
	}

	while (1)
	{
		printf("Enter 'n' to show next page, 'u' to show previous page, 'q' to exit: ");

		do {
			cOpr = getchar();			
		} while ((cOpr != 'n') && (cOpr != 'u') && (cOpr != 'q'));

		if (cOpr == 'n')
		{
			ShowNextPage();
		}
		else if (cOpr == 'u')
		{
			ShowPrePage();			
		}
		else 
		{
			return 0;
		}			
	}
	return 0;
}
(1)解析命令参数

getopt(argc, argv, "ls:f:h:d:")

:需要带参数

-l 不需要带参数

strncpy(acTextFile, argv[optind], 128);得到文件名

(2)初始化显示、字体、编码--》注册相关结构体

	iError = DisplayInit();
	iError = FontsInit();
	iError = EncodingInit();
(3)打开文件

 OpenTextFile(acTextFile)
(4)打开字体文件

SetTextDetail(acHzkFile, acFreetypeFile, dwFontSize);

(5)根据名字选择初始化一个显示器

SelectAndInitDisplay(acDisplay);
(6)显示第一页或者下一页

ShowNextPage();

(7)等待命令参数,显示下一页,上一页等


你可能感兴趣的:(S3C2440)