软件总框架
![](https://img-blog.csdnimg.cn/img_convert/849fef7e8d6037b9744ff38a6be9bcd2.png)
1:设计构思-显示管理器
1.1 显示部分-数据结构抽象
![](https://img-blog.csdnimg.cn/img_convert/a01f20351d67d5d47d1c1022de987f3e.png)
对两个不同的设备(Frambuffer与WEB),抽象出同一个结构体类型,
总概括:先得到一个buffer,在这个buffer中你可以绘制图片,程序在buffer中绘制图片,然后刷到硬件上(lcd)去或者浏览器中(WEB网页)
如何获得buffer,以及buffer怎样绘制图片:
1:先获得一个结构体,使用Framebufer中的函数,获得buffer来绘制界面。
2:在buffer中绘制按钮界面,根据ioctl获得LCD分辨率、BPP,最后刷新这个界面。
Framebuffer:在 Linux 系统中通过 Framebuffer 驱动程序来控制 LCD。Frame 是帧的意思,buffer 是缓冲的意思,这意味着 Framebuffer 就是一块内存,里面保存着一帧图像。Framebuffer 中保存着一帧图像的每一个像素颜色值,假设 LCD 的分辨率是 1024x768,每一个像素的颜色用 32 位来表示,那么 Framebuffer 的大小就是:1024x768x32/8=3145728 字节。
WEB:
fd_fb = open("/dev/fb0", O_RDWR); //打开设备节点
ioctl: 获得LCD分辨率、BPP
mmap: 应用程序和驱动程序之间传递数据时,可以通过 read、write 函数进行。这
涉及在用户态 buffer 和内核态 buffer 之间传数据,如下图所示:
![](https://img-blog.csdnimg.cn/img_convert/a0659b45ca48d2abcfa3a6415dd9d89b.png)
应用程序不能直接读写驱动程序中的 buffer,需要在用户态 buffer 和内核buffer 之间进行一次数据拷贝。这种方式在数据量比较小时没什么问题;但是数据量比较大时效率就太低了。比如更新 LCD 显示时,如果每次都让 APP 传递一帧数据给内核,假设 LCD 采用 1024*600*32bpp 的格式,一帧数据就有
1024*600*32/8=2.3MB 左右,这无法忍受。
改进的方法就是让程序可以直接读写驱动程序中的 buffer,这可以通过mmap 实现(memory map),把内核的 buffer 映射到用户态,让 APP 在用户态直接读写。
cross_comepile 交叉编译工具链:交叉编译工具链用来在 Ubuntu 主机上编译应用程序,而这些应用程序是在ARM 等其他平台上运行。
makefile:
在一个正式的软件项目中,由很多个.c和.h文件构成,此时如果直接在命令行编译,就会像这样:gcc a.c b.c c.c d.c e.c f.c g.c -o exe每次编译都要输入一堆东西很麻烦,这时就需要Makefile来解决,这样就能实现只需要写一次即可实现每次都能同时编译多个文件。
————————————————
我参考 Linux 内核的 Makefile 编写了一个通用的 Makefile,它可以用来
编译应用程序:
1支持多个目录、多层目录、多个文件;
2 支持给所有文件设置编译选项;
3 支持给某个目录设置编译选项;
4 支持给某个文件单独设置编译选项;
5 简单、好用。
freetype:
一个外观对象通常使用FT_New_Face()来创建,这个函数接受如下参数:一个FT_Library句柄,一个表示字体文件的C文件路径名,一个决定从文件中装载外观的索引(一个文件中可能有不同的外观),和FT_Face句柄的地址,它返回一个错误码。
FT_Error FT_New_Face( FT_Library library,
const char* filepathname,
FT_Long face_index,
FT_Face* face);
1.1.1 程序
disp_manager.h
#ifndef __DISP_MANAGER_H
#define __DISP_MANAGER_H
typedef struct Region{ //一个区域
int iLeftUpX; //左上角
int iLeftUpY;
int iWidth;
int iHeigh;
}Region,*PRegion; //结构体(Region)指针.
//绘制图片
typedef struct DispOpr{
char *name; //来分辨取得的不同的结构体
char *GetBuffer(int *pXres, int *pYres, int *pBpp); //绘制图片需要buffer,获得一个buffer
//(分辨率,像素占据多少位)
int FlushRegion(PRegion ptRegion, char *buffer);
// 绘制好按钮,刷新区域,刷到设备上去(Framebuffer)
struct DispOpr *ptNext; //为了让这些结构体都能够链接起来,我们加一个指针struct。。。
};
#endif
1.1.2 总结
1.上层APP在这个buffer中绘制图片
typedef struct DispOpr{
char *name;
char *GetBuffer(int *pXres, int *pYres, int *pBpp);
int FlushRegion(PRegion ptRegion, char *buffer);
struct DispOpr *ptNext;
};
2.可以更新某个区域,比如“按钮2”然后把该区域Flush到LCD或者WEB上
typedef struct Region{
int iLeftUpX;
int iLeftUpY;
int iWidth;
int iHeigh;
}Region,*PRegion;
1.2 显示部分-Framebuffer编码
抽象出两个结构体:一个显示结构体 ,一个更新结构体
1.2.1 Framebuffer程序
framebuffer.c
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <linux/fb.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include "disp_manager.h"
static int fd_fb;
static struct fb_var_screeninfo var; /* Current var */
static int screen_size;
static unsigned char *fb_base;
static unsigned int line_width;
static unsigned int pixel_width;
static int FbDeviceInit(void)
{
fd_fb = open("/dev/fb0", O_RDWR);
if (fd_fb < 0)
{
printf("can't open /dev/fb0\n");
return -1;
}
if (ioctl(fd_fb, FBIOGET_VSCREENINFO, &var))
{
printf("can't get var\n");
return -1;
}
line_width = var.xres * var.bits_per_pixel / 8;
pixel_width = var.bits_per_pixel / 8;
screen_size = var.xres * var.yres * var.bits_per_pixel / 8;
fb_base = (unsigned char *)mmap(NULL , screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);
if (fb_base == (unsigned char *)-1)
{
printf("can't mmap\n");
return -1;
}
return 0;
}
static int FbDeviceExit(void)
{
munmap(fb_base, screen_size);
close(fb_base);
return 0;
}
/* 可以返回LCD的framebuffer, 以后上层APP可以直接操作LCD, 可以不用 FbFlushRegion
* 也可以malloc返回一块无关的buffer, 要使用 FbFlushRegion
*
*/
static char *FbGetBuffer(int *pXres, int *pYres, int *pBpp)
{
*pXres = var.xres;
*pYres = var.yres;
*pBpp = var.bits_per_pixel;
return fb_base;
}
static int FbFlushRegion(PRegion ptRegion, char *buffer)
{
return 0;
}
static DispOpr g_tFramebufferOpr = {
.name = "fb",
.DeviceInit = FbDeviceInit,
.DeviceExit = FbDeviceExit,
.GetBuffer = FbGetBuffer,
.FlushRegion = FbFlushRegion,
};
1.2.2 总结
int FbDeviceInit(void); //设备初始化
int FbDeviceExit(void); //exit清除 munmap close
char *FbGetBuffer(int *pXres, int *pYres, int *pBpp);
1.上层APP在这个buffer中绘制图片
int FbFlushRegion(PRegion ptRegion, char *buffer);
2.可以更新某个区域,比如“按钮2”然后把该区域Flush到LCD或者WEB上
1.3 显示系统-显示管理
1.3.1 显示管理
![](https://img-blog.csdnimg.cn/img_convert/da3c9c7064315ff365c8261a4f1beb75.png)
disp_manager.c的作用
1.承上启下
2.下面各个模块把DispOpr注册进来
3.上面选择某个模块
4.还提供一些函数,比如PutPixel
1.3.2