数码相册——电子书的实现

  • 硬件平台:韦东山嵌入式Linxu开发板(S3C2440.v3)
  • 软件平台:运行于VMware Workstation 12 Player下UbuntuLTS16.04_x64 系统
  • 参考资料:《嵌入式Linux应用开发手册》、《嵌入式Linux应用开发手册第2版》
  • 开发环境:Linux 3.4.2内核、arm-linux-gcc 4.3.2工具链
  • 源码仓库:https://gitee.com/d_1254436976/Embedded-Linux-Phase-3

目录

  • 数码相册——电子书的实现
    • 一、大致框架
      • 1、框架图
      • 2、代码间的有效管理
    • 二、`config.h`文件分析
    • 三、挑display显示部分来进行分析
      • 1、`disp_manager.h`文件分析
      • 2、`disp_manager.c`文件分析
      • 3、`fb.c`文件分析
        • 3.1 分配结构体
        • 3.2 设置结构体
        • 3.3 注册结构体
        • 3.4 完整文件
    • 四、程序的运行
      • 1、编译
      • 2、执行
      • 3、现象

一、大致框架

1、框架图


对于在LCD中显示一个文件,总体上进行下面几件事:

  1. 去文件中获得编码信息,对于每个文件,保存的时候,系统对自动或手动的根据编码规范,对文件的信息进行编码:如保存为ASCII、GBK、UTF-8、UTF16LE、UTF16BE
  2. 根据获得的编码信息得到字体数据(LCD上表示为点阵)
  3. 把字体数据(点阵)显示在LCD上

所以根据这个信息,可以总结出上述的框架。

2、代码间的有效管理

对于上述完成主要功能的4个部分:encoding编码部分、fonts获取字体点阵部分、display显示部分、draw协调部分,会仿照Linux内核的方式采用模块化进行管理,对于每个部分:

  • 代码上实现一个manager向下支持各种文件的拓展,把所支持的文件放入链表中进行管理向上提供各种接口,使其可以根据实际情况进行从链表中选择不同的拓展文件来进行功能的实现。
  • 每个部分都会定义一个结构体变量拓展文件可以根据自己的情况:分配结构体、设置结构体、注册结构体
  • 对于每个部分之间进行数据的沟通,可以通过main.c和draw.c的协调,通过获得各个部分的结构体变量draw.c文件中进行交互

二、config.h文件分析

对于这个文件,从名字就知道,它是一个配置文件,定义了一些宏定义,供所有文件调用

  • 源码
    对于#define DBG_PRINTF(...) 与 #define DBG_PRINTF printf
    当我们调试的时候,可以//#define DBG_PRINTF(...) #define DBG_PRINTF printf,打印调试信息;
    当我们程序发布时,可以#define DBG_PRINTF(...) //#define DBG_PRINTF printf,屏蔽调试信息的打印。

#ifndef _CONFIG_H
#define _CONFIG_H#include <stdio.h>#define FB_DEVICE_NAME "/dev/fb0"#define COLOR_BACKGROUND   0xE7DBB5/* 泛黄的纸 */
#define COLOR_FOREGROUND   0x514438/* 褐色字体 *///#define DBG_PRINTF(...)
#define DBG_PRINTF printf#endif/* _CONFIG_H */

三、挑display显示部分来进行分析

1、disp_manager.h文件分析

在这个文件中,定义了一个结构体和相关函数,供拓展文件来分配结构体、设置结构体、注册结构体

#ifndef _DISP_MANAGER_H
#define _DISP_MANAGER_Htypedef struct DispOpr {char *name;int Xres;int Yres;int Bpp;int (*DeviceInit)(void);int (*ShowPixel)(int PenX, int PenY, unsigned int Color);int (*CleanScreen)(unsigned int BackColor);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 */

2、disp_manager.c文件分析

这个文件就是负责上述disp_manager.h文件的函数实现:


#include <config.h>
#include <disp_manager.h>
#include <string.h>static PT_DispOpr s_ptDispOprHead;/* 函数名:         注册函数* 函数功能:构建一个链表:把多个拓展文件的结构体“串”起来* 函数实现:根据传入的结点,首先判断该链表头是否为空*             空则,头结点指向传入的节点,且把节点的ptNext域指向NULL*             不空则,尾插法插入链表*/
int RegisterDispOpr(PT_DispOpr ptDispOpr)
{PT_DispOpr ptTmp;if (!s_ptDispOprHead){s_ptDispOprHead   = ptDispOpr;ptDispOpr->ptNext = NULL;}else{ptTmp = s_ptDispOprHead;while (ptTmp->ptNext){ptTmp = ptTmp->ptNext;}ptTmp->ptNext     = ptDispOpr;ptDispOpr->ptNext = NULL;}return 0;
}/* 显示支持拓展文件的名字 */
void ShowDispOpr(void)
{int i = 0;PT_DispOpr ptTmp = s_ptDispOprHead;while (ptTmp){printf("%02d %s\n", i++, ptTmp->name);ptTmp = ptTmp->ptNext;}
}/* 获取指定的名字的拓展文件 */
PT_DispOpr GetDispOpr(char *pName)
{PT_DispOpr ptTmp = s_ptDispOprHead;while (ptTmp){if (strcmp(ptTmp->name, pName) == 0){return ptTmp;}ptTmp = ptTmp->ptNext;}return NULL;
}/* 初始化函数 */
int DisplayInit(void)
{int error;error = FBInit();return error;
}

3、fb.c文件分析

3.1 分配结构体

static T_DispOpr s_tFBDispOpr = {.name         = "fb",.DeviceInit   = FBDeviceInit,.ShowPixel    = FBShowPixel,.CleanScreen  = FBCleanScreen,
};

3.2 设置结构体


/* LCD设备初始化函数 */
static int FBDeviceInit(void)
{/* 打开设备:支持读写 */s_FBFD = open(FB_DEVICE_NAME, O_RDWR);if (s_FBFD < 0) {DBG_PRINTF("can not open %s , err code :%d\n", FB_DEVICE_NAME, s_FBFD);return -1;}/* 获得可变信息 */if (ioctl(s_FBFD, FBIOGET_VSCREENINFO, &s_tVar)) {DBG_PRINTF("can not get s_tVar\n");return -1;}/* 获得固定信息 */if (ioctl(s_FBFD, FBIOGET_FSCREENINFO, &s_tFix)) {DBG_PRINTF("can not get s_tVar\n");return -1;}s_tFBDispOpr.Xres = s_tVar.xres;s_tFBDispOpr.Yres = s_tVar.yres;s_tFBDispOpr.Bpp   = s_tVar.bits_per_pixel;s_ScreenSize = s_tVar.xres * s_tVar.yres * s_tVar.bits_per_pixel / 8; // 屏幕总像素所占的字节数s_LineWidth   = s_tVar.xres * s_tVar.bits_per_pixel / 8; // 每行像素所占的字节数s_PixelWidth  = s_tVar.bits_per_pixel / 8;  // 每个像素所占字节数/* 直接映射到内存的Framebuffer */s_pFbmem = (unsigned char *)mmap(NULL, s_ScreenSize, PROT_READ | PROT_WRITE, MAP_SHARED, s_FBFD, 0);if (s_pFbmem == (unsigned char *)-1) {DBG_PRINTF("can not mmap\n");return -1;}return 0;
}/* LCD像素显示函数 */
static int FBShowPixel(int PenX, int PenY, unsigned int Color)
{unsigned char  *pPen8;unsigned short *pPen16;unsigned int   *pPen32;unsigned int   red, green, blue;if ((PenX >= s_tVar.xres) || (PenY >= s_tVar.yres)){DBG_PRINTF("out of region\n");return -1;}/* 该坐标在内存中对应像素的位置 */pPen8  = s_pFbmem + PenY * s_LineWidth + PenX * s_PixelWidth;pPen16 = (unsigned short *)pPen8;pPen32 = (unsigned int   *)pPen8;switch (s_tFBDispOpr.Bpp) {case 8:*pPen8 = (unsigned char)Color;break;case 16:/* RGB:565 */red      = ((Color >> 16) & 0xffff) >> 3;green    = ((Color >> 8 )  & 0xffff) >> 2;blue     = ((Color >> 0 )  & 0xffff) >> 3;*pPen16  = (red << 11) | (green << 5) | blue;break;case 32:*pPen32 = Color;break;default:DBG_PRINTF("can not surport %d bpp\n", s_tFBDispOpr.Bpp);return -1;}return 0;
}/* 清屏函数 */
static int FBCleanScreen(unsigned int BackColor)
{int i;unsigned char  *pPen8;unsigned short *pPen16;unsigned int   *pPen32;unsigned int   red, green, blue;pPen8  = s_pFbmem;pPen16 = (unsigned short *)pPen8;pPen32 = (unsigned int   *)pPen8;switch (s_tFBDispOpr.Bpp) {case 8:memset(pPen8, BackColor, s_ScreenSize);break;case 16:/* RGB:565 */red      = ((BackColor >> 16) & 0xffff) >> 3;green    = ((BackColor >> 8 )  & 0xffff) >> 2;blue     = ((BackColor >> 0 )  & 0xffff) >> 3;BackColor = (red << 11) | (green << 5) | blue;for (i = 0; i < s_ScreenSize;) {*pPen16 = BackColor;pPen16++;i += 2;}break;case 32:for (i = 0; i < s_ScreenSize;) {*pPen32 = BackColor;pPen32++;i += 4;}break;default:DBG_PRINTF("can not surport %dbpp\n", s_tFBDispOpr.Bpp);return -1;}return 0;
}

3.3 注册结构体

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

3.4 完整文件

#include <config.h>
#include <disp_manager.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <linux/fb.h>
#include <string.h>static int s_FBFD;
static int s_ScreenSize;
static int s_LineWidth;
static int s_PixelWidth;
static struct fb_var_screeninfo s_tVar;
static struct fb_fix_screeninfo s_tFix;
static unsigned char *s_pFbmem;static int FBDeviceInit(void);
static int FBShowPixel(int PenX, int PenY, unsigned int Color);
static int FBCleanScreen(unsigned int BackColor);static T_DispOpr s_tFBDispOpr = {.name         = "fb",.DeviceInit   = FBDeviceInit,.ShowPixel    = FBShowPixel,.CleanScreen  = FBCleanScreen,
};/* LCD设备初始化函数 */
static int FBDeviceInit(void)
{/* 打开设备:支持读写 */s_FBFD = open(FB_DEVICE_NAME, O_RDWR);if (s_FBFD < 0) {DBG_PRINTF("can not open %s , err code :%d\n", FB_DEVICE_NAME, s_FBFD);return -1;}/* 获得可变信息 */if (ioctl(s_FBFD, FBIOGET_VSCREENINFO, &s_tVar)) {DBG_PRINTF("can not get s_tVar\n");return -1;}/* 获得固定信息 */if (ioctl(s_FBFD, FBIOGET_FSCREENINFO, &s_tFix)) {DBG_PRINTF("can not get s_tVar\n");return -1;}s_tFBDispOpr.Xres = s_tVar.xres;s_tFBDispOpr.Yres = s_tVar.yres;s_tFBDispOpr.Bpp   = s_tVar.bits_per_pixel;s_ScreenSize = s_tVar.xres * s_tVar.yres * s_tVar.bits_per_pixel / 8; // 屏幕总像素所占的字节数s_LineWidth   = s_tVar.xres * s_tVar.bits_per_pixel / 8; // 每行像素所占的字节数s_PixelWidth  = s_tVar.bits_per_pixel / 8;  // 每个像素所占字节数/* 直接映射到内存的Framebuffer */s_pFbmem = (unsigned char *)mmap(NULL, s_ScreenSize, PROT_READ | PROT_WRITE, MAP_SHARED, s_FBFD, 0);if (s_pFbmem == (unsigned char *)-1) {DBG_PRINTF("can not mmap\n");return -1;}return 0;
}/* LCD像素显示函数 */
static int FBShowPixel(int PenX, int PenY, unsigned int Color)
{unsigned char  *pPen8;unsigned short *pPen16;unsigned int   *pPen32;unsigned int   red, green, blue;if ((PenX >= s_tVar.xres) || (PenY >= s_tVar.yres)){DBG_PRINTF("out of region\n");return -1;}/* 该坐标在内存中对应像素的位置 */pPen8  = s_pFbmem + PenY * s_LineWidth + PenX * s_PixelWidth;pPen16 = (unsigned short *)pPen8;pPen32 = (unsigned int   *)pPen8;switch (s_tFBDispOpr.Bpp) {case 8:*pPen8 = (unsigned char)Color;break;case 16:/* RGB:565 */red      = ((Color >> 16) & 0xffff) >> 3;green    = ((Color >> 8 )  & 0xffff) >> 2;blue     = ((Color >> 0 )  & 0xffff) >> 3;*pPen16  = (red << 11) | (green << 5) | blue;break;case 32:*pPen32 = Color;break;default:DBG_PRINTF("can not surport %d bpp\n", s_tFBDispOpr.Bpp);return -1;}return 0;
}/* 清屏函数 */
static int FBCleanScreen(unsigned int BackColor)
{int i;unsigned char  *pPen8;unsigned short *pPen16;unsigned int   *pPen32;unsigned int   red, green, blue;pPen8  = s_pFbmem;pPen16 = (unsigned short *)pPen8;pPen32 = (unsigned int   *)pPen8;switch (s_tFBDispOpr.Bpp) {case 8:memset(pPen8, BackColor, s_ScreenSize);break;case 16:/* RGB:565 */red      = ((BackColor >> 16) & 0xffff) >> 3;green    = ((BackColor >> 8 )  & 0xffff) >> 2;blue     = ((BackColor >> 0 )  & 0xffff) >> 3;BackColor = (red << 11) | (green << 5) | blue;for (i = 0; i < s_ScreenSize;) {*pPen16 = BackColor;pPen16++;i += 2;}break;case 32:for (i = 0; i < s_ScreenSize;) {*pPen32 = BackColor;pPen32++;i += 4;}break;default:DBG_PRINTF("can not surport %dbpp\n", s_tFBDispOpr.Bpp);return -1;}return 0;
}int FBInit(void)
{return RegisterDispOpr(&s_tFBDispOpr);
}

四、程序的运行

1、编译

执行make命令,编译出show_file可执行文件,把show_file、MSYH.TTF、hz.txt、utf8.txt utf16be.txt、utf16le.txt传输到开发板的根文件系统中

2、执行

执行./show_file -s 16 -h HZK16 -f ./MSYH.TTF hz.txt命令

  • ./show_file:编译出来可执行程序
  • -s 16:设置字体的大小为16
  • -h HZK16:字库文件为当前目录下的HZK16,根据里面的信息获取点阵
  • -f ./MSYH.TTF:字体文件为当前目录下的MSYH.TTF,供FreeType来设置字体大小
  • hz.txt:所要显示的文件为当前目录下的hz.txt

3、现象

  • 在开发板上:
  • 根文件系统上:
    循环根据输入信息进行对应操作:
    n: 显示下一页信息
    u: 显示上一页信息
    q: 退出程序

第三阶段应用层——1.7 数码相册—电子书(1)—实现相关推荐

  1. 第三阶段应用层——2.6 视频监控—CMOS摄像头的硬件原理

    视频监控-CMOS摄像头的硬件原理 硬件平台:韦东山嵌入式Linxu开发板(S3C2440.v3) 软件平台:运行于VMware Workstation 12 Player下UbuntuLTS16.0 ...

  2. 第三阶段应用层——2.7 视频监控—从零写CMOS摄像头驱动

    视频监控-从零写CMOS摄像头驱动 硬件平台:韦东山嵌入式Linxu开发板(S3C2440.v3),OV7740摄像头 软件平台:运行于VMware Workstation 12 Player下Ubu ...

  3. 第三阶段应用层——2.4 视频监控—从0写USB摄像头驱动(1)-描述符的分析与打印

    视频监控-从0写USB摄像头驱动(1)-描述符的分析与打印 硬件平台:韦东山嵌入式Linxu开发板(S3C2440.v3) 软件平台:运行于VMware Workstation 12 Player下U ...

  4. Linux运维 第三阶段 (一) 网络配置及openssl加密

    Linux运维 第三阶段 (一) 网络配置及openssl加密 主机接入网络:IP,netmask,gateway,hostname,DNS1,DNS2,DNS3,route,dhcp(dynamic ...

  5. 中国石油大学(北京)-《计算机网络应用基础》第三阶段在线作业

    第三阶段在线作业 单选题 (共20道题) 收起 1.(2.5分) 以下关于VPN说法正确的是 A.VPN指的是用户自己租用线路,和公共网络物理上完全隔离的.安全的线路 B.VPN指的是用户通过公用网络 ...

  6. 中国石油大学《计算机应用基础#》第三阶段在线作业

    第三阶段在线作业 单选题 (共20道题) 收起 1.(2.5分) PowerPoint演示文稿的作者必须非常注意幻灯片集的两个要素是(). A.内容和设计 B.内容和模板 C.内容和视觉效果 D.问题 ...

  7. java 高并发第三阶段实战_JAVA多线程编程实战视频-第三阶段(共80节)

    高并发编程第三阶段01讲 AtomicInteger多线程下测试讲解 高并发编程第三阶段02讲 AtomicInteger API详解,以及CAS算法详细介绍 高并发编程第三阶段03讲 利用CAS构造 ...

  8. 自学it18大数据笔记-第三阶段Spark-day04——会持续更新……

    笔记为自学时随手记录,如有错误,欢迎指正,不胜感激!现已广州转移至上海,欢迎小伙伴们加qq或微博沟通交流(QQ,微博和博客同名) 笔记分享:自学it18大数据笔记-第三阶段Spark-day04--会 ...

  9. 5G全球声量升级:Verizon宣布固定+移动齐步走,中国第三阶段试验倒计时

    就在CES2018国际消费类电子产品展和2018世界移动大会即将召开的时候,5G的信号在全球范围也来了一次集体释放. 1月2日,工业和信息化部召开评审会,为有效指导5G第三阶段试验做准备.同一天,韩国 ...

  10. Linux运维 第三阶段 (二) DHCP

    Linux运维 第三阶段 (二) DHCP服务 dhcp(dynamic host configuration protocol) 前期bootp(无盘工作站)-->dhcp(引入租约lease ...

最新文章

  1. NeurIPS 2021六篇杰出论文公布,谷歌工程师11年前论文获时间检验奖
  2. ubuntu workerman kaer
  3. DefaultSingletonBeanRegistry源码解析
  4. python dict遍历_Python学习笔记:19个pythonic编程习惯,让你的Python入门更优雅
  5. Netfilter 详解
  6. 精妙SQL语句【转】
  7. php环境搭建sqlserver,ThinkPHP5.0/5.1对接SQLServer数据库(宝塔环境)
  8. 计算机辅助抗体设计,计算机辅助设计提高单克隆抗体亲和力的研究
  9. 计算几何 —— 欧拉公式
  10. Highcharts使用指南
  11. 判断php对象不包含的key,如何判断一个对象是否包含指定Key
  12. 配置SQL Server 2008 R2 Reporting Services
  13. win10 jFrameDesigner安装
  14. Ubuntu 安装 peek 动态截图软件
  15. 无刷直流电动机及其控制
  16. 分享3个自动生成文案的工具,月入6000,做自媒体不会写文案?
  17. java租车_Java 哒哒租车系统(控制台)
  18. 要实现一台电脑可以上公司内网也可以访问外网
  19. 58同城2021校招笔试真题-前端
  20. 【转载】Matlab与C#连接的几种方式比较

热门文章

  1. 初级第五旬07— 初级课程第五旬试题
  2. 指数分布(一种连续分布)、爱尔朗分布
  3. Elasticseach api keys are not enabled
  4. None of the following candidates is applicable because of a receiver type mismatch
  5. 贴片晶振为智能手环带来了哪些功能?
  6. 十二平均律的数学描述
  7. 小白vba之批量数据整理(excel自动化入门)
  8. 上网行为管理软件的主要功能、并简要说明上网行为管理类的软件的原理。
  9. MAC big sur桌面图片在哪个文件夹
  10. 会matlab的简历怎么写,算法工程师简历项目经验填写样本