数码相框
-
输入进程 : tslib 操作触摸屏 具体事件类型、事件和方向 ,进行封装
-
线程1 :主控:得到事件,socket 发出 到显示进程
-
线程2 :触摸屏 : tslib 读触摸屏,封装事件 ,上报
-
线程3 :按键 : 读按键、封装事件上报
-
-
显示进程 :多个线程实现以下功能
-
线程1 : 接收socket
-
放大线程:准备当前图片的放大数据
-
缩小线程:准备当前图片的缩小数据
-
上一幅线程: 准备好上一幅图片
-
下一幅线程:准备好下一幅图片
-
当前图片线程:准备好当前图片
-
主控:根据事件决定显示哪一幅图片
-
内存通过DMA (Direct Memory Access)将数据传送给显存 然后LCD 显示
-
而不是用memcpy 用于在内存之间复制数据
-
-
驱动程序: 分配五块内存,mmap
LCD点阵的字符显示
-
LCD从frameBUffer 中取数据!不断的在显存中取
-
内核中存在对应ASCII 的点阵(搜索font), 8x16 就是16个字节 ,宽8 高16
电子书框架
-
在文件中获取文字,得到其中的“码”!
-
根据码 得到字体数据 ,点阵
-
把点阵 在LCD中显示出来
代码框架
第一层 : draw.c
第二层:encoding_manager.c 解析文件获得编码 ,font_manger.c 处理编码获得字体,display_manager.c 来输出点阵
第三层:各个manager.c下面对应结构体 T_DispOpr ,T_FontOpr,T_EncodingOpr
代码解读
-
draw.c 为顶层文件,管理下面3个C文件
main.c
调用draw.c中的函数进行绘画
首先 对参数进行处理
./show_file [-s Size] [-f freetype_font_file] [-h HZK] <text_file>
采用get_opt函数进行参数处理
第三个参数后面带冒号就表示需要接收一个参数,不然就是不需要参数
ls: 就表示 -l 不需要参数 -s 需要参数
函数会将需要的参数值存在 一个全局变量optarg中 ,这个变量不用去设定,是一个字符串类型,每次存一个
然后将传入的参数cpy 到事先创建的数组中
int getopt(int argc, char *const argv[], const char *optstring); //返回值 -1 为报错 while ((iError = getopt(argc, argv, "ls:f:h:d:")) != -1) { switch(iError) { case 'l': { bList = 1; break; } case 's': { dwFontSize = strtoul(optarg, NULL, 0); //str to unsigned long ,参数3为0 表示根据前缀进行识别 break; } …… case 'f': case 'h': case 'd': default: } }
接下来进行判断:参数未完全未实现,打印一些信息
if (!bList && (optind >= argc)) { printf("Usage: %s [-s Size] [-d display] [-f font_file] [-h HZK] <text_file>\n", argv[0]); printf("Usage: %s -l\n", argv[0]); return -1; }
-
进行初始化操作:
iError = DisplayInit(); iError = FontsInit(); iError = EncodingInit();
-
如果参数传入正确 ,optind 会刚好位于数组最后一个值,将其拷贝
-
打开要浏览的文件夹 , 具体函数实现在draw.c
-
设置和初始化显示
iError = OpenTextFile(acTextFile); /* 打开文件,最终效果是完成映射g_pucTextFileMem 并且找到对应该文件编码的结构体,也就是选择 ASCII 还是GB 还是 UTF-8 同时记录第一页的位置g_pucLcdFirstPosAtFile = */ iError = SetTextDetail(acHzkFile, acFreetypeFile, dwFontSize); /* 参数包括:汉字库文件名,freetype 文件名 ,字体大小 寻找对应的FontOpr ,也就是位图 ,找到后对其进行初始化,调用结构体中的初始化函数 int (*FontInit) */ iError = SelectAndInitDisplay(acDisplay); /* 通过参数,在链表中找到对饮的结构体g_ptDispOpr 同时对该结构体进行初始化 */ iError = ShowNextPage();//显示下一页,内部调用show one page 最复杂的函数 int ShowNextPage(void);
-
Show one Page
-
获得编码值
-
获得位图
-
计算位置,是否需要换行,或者翻页
-
显示
-
int ShowOnePage(unsigned char *pucTextFileMemCurPos) { int iLen; int iError; unsigned char *pucBufStart; unsigned int dwCode; PT_FontOpr ptFontOpr; T_FontBitMap tFontBitMap; int bHasNotClrSceen = 1; int bHasGetCode = 0; tFontBitMap.iCurOriginX = 0; tFontBitMap.iCurOriginY = g_dwFontSize; pucBufStart = pucTextFileMemCurPos; while (1) { iLen = g_ptEncodingOprForFile->GetCodeFrmBuf(pucBufStart, g_pucTextFileMemEnd, &dwCode); if (0 == iLen) { if (!bHasGetCode) { return -1; } else { return 0; } } bHasGetCode = 1; pucBufStart += iLen; if (dwCode == '\n') { g_pucLcdNextPosAtFile = pucBufStart; tFontBitMap.iCurOriginX = 0; tFontBitMap.iCurOriginY = IncLcdY(tFontBitMap.iCurOriginY); if (0 == tFontBitMap.iCurOriginY) { return 0; } else { continue; } } else if (dwCode == '\r') { continue; } else if (dwCode == '\t') { dwCode = ' '; } DBG_PRINTF("dwCode = 0x%x\n", dwCode); ptFontOpr = g_ptEncodingOprForFile->ptFontOprSupportedHead; while (ptFontOpr) { DBG_PRINTF("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__); iError = ptFontOpr->GetFontBitmap(dwCode, &tFontBitMap); DBG_PRINTF("%s %s %d, ptFontOpr->name = %s, %d\n", __FILE__, __FUNCTION__, __LINE__, ptFontOpr->name, iError); if (0 == iError) { DBG_PRINTF("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__); if (RelocateFontPos(&tFontBitMap))//重新定位,也就是确定该字体是否月结 { return 0; } DBG_PRINTF("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__); if (bHasNotClrSceen) { g_ptDispOpr->CleanScreen(COLOR_BACKGROUND); bHasNotClrSceen = 0; } DBG_PRINTF("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__); if (ShowOneFont(&tFontBitMap)) { return -1; } tFontBitMap.iCurOriginX = tFontBitMap.iNextOriginX; tFontBitMap.iCurOriginY = tFontBitMap.iNextOriginY; g_pucLcdNextPosAtFile = pucBufStart; break; } ptFontOpr = ptFontOpr->ptNext; } } return 0; }
draw.c 最复杂
-
结构体创建
typedef struct PageDesc { int iPage; unsigned char *pucLcdFirstPosAtFile; unsigned char *pucLcdNextPageFirstPosAtFile; struct PageDesc *ptPrePage; struct PageDesc *ptNextPage; } T_PageDesc, *PT_PageDesc;
int OpenTextFile(char *pcFileName) { struct stat tStat;//stat 是存储文件信息的一个结构体 ,里面可以存大小 g_iFdTextFile = open(pcFileName, O_RDONLY); if (0 > g_iFdTextFile) { DBG_PRINTF("can't open text file %s\n", pcFileName); return -1; } if(fstat(g_iFdTextFile, &tStat))//fstat 应该是提取信息 { DBG_PRINTF("can't get fstat\n"); return -1; } g_pucTextFileMem = (unsigned char *)mmap(NULL , tStat.st_size, PROT_READ, MAP_SHARED, g_iFdTextFile, 0);//mmap 内存映射 if (g_pucTextFileMem == (unsigned char *)-1) { DBG_PRINTF("can't mmap for text file\n"); return -1; } g_pucTextFileMemEnd = g_pucTextFileMem + tStat.st_size;//开始地址为g_pucTextFileMem ,结束为g_pucTextFileMemEnd g_ptEncodingOprForFile = SelectEncodingOprForFile(g_pucTextFileMem);//选择对应的编码格式在链表中找 //该指针指向一个EncodingOpr 结构体 ,获得对应编码的结构体 if (g_ptEncodingOprForFile) { g_pucLcdFirstPosAtFile = g_pucTextFileMem + g_ptEncodingOprForFile->iHeadLen; //加上头部,编码文件会在开始有几个字符标注,记录第一页的开始位置 return 0; } else { return -1; } } int SetTextDetail(char *pcHZKFile, char *pcFileFreetype, unsigned int dwFontSize) { int iError = 0; PT_FontOpr ptFontOpr; PT_FontOpr ptTmp; int iRet = -1; g_dwFontSize = dwFontSize;//字体大小,转换为一个全局变量 ptFontOpr = g_ptEncodingOprForFile->ptFontOprSupportedHead; while (ptFontOpr) { if (strcmp(ptFontOpr->name, "ascii") == 0) { iError = ptFontOpr->FontInit(NULL, dwFontSize); } else if (strcmp(ptFontOpr->name, "gbk") == 0) { iError = ptFontOpr->FontInit(pcHZKFile, dwFontSize); } else { iError = ptFontOpr->FontInit(pcFileFreetype, dwFontSize); } DBG_PRINTF("%s, %d\n", ptFontOpr->name, iError); ptTmp = ptFontOpr->ptNext; if (iError == 0) { iRet = 0; } else { DelFontOprFrmEncoding(g_ptEncodingOprForFile, ptFontOpr); } ptFontOpr = ptTmp; } return iRet; } int SelectAndInitDisplay(char *pcName) { int iError; g_ptDispOpr = GetDispOpr(pcName); if (!g_ptDispOpr) { return -1; } iError = g_ptDispOpr->DeviceInit(); return iError; }
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;
参数对应:名字,最大宽度,最大高度,每像素位数 ,初始化函数,描点函数,清屏函数 ,以及next指针,链表
disp_manager.c
-
主要负责初始化DisplayInit()
-
注册结构体、查询
-
维护一个链表,将新的结构体添加到链表中
static PT_DispOpr g_ptDispOprHead;//头节点 ,一开始为空 ,静态变量默认指向NULL 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; }
-
encoding_manager.h
-
结构体定义,名字,编码文件头部长度(负责判断是哪种编码), 支持编码类型的链表,是否支持函数,获取编码函数
typedef struct EncodingOpr { char *name; int iHeadLen; PT_FontOpr ptFontOprSupportedHead; int (*isSupport)(unsigned char *pucBufHead); int (*GetCodeFrmBuf)(unsigned char *pucBufStart, unsigned char *pucBufEnd, unsigned int *pdwCode); struct EncodingOpr *ptNext; }T_EncodingOpr, *PT_EncodingOpr;
encoding_manager.c
/* 具体eocding 函数 实现 int (*isSupport)(unsigned char *pucBufHead); int (*GetCodeFrmBuf)(unsigned char *pucBufStart, unsigned char *pucBufEnd, unsigned int *pdwCode); 同时注册 :int RegisterEncodingOpr(PT_EncodingOpr ptEncodingOpr) 负责将其添加到结构体中 void ShowEncodingOpr(void) : 打印链表中支持的编码格式 PT_EncodingOpr SelectEncodingOprForFile(unsigned char *pucFileBufHead) 负责寻找对应的编码 ,通过调用每个结构体的isSupport 函数来进行匹配 int AddFontOprForEncoding(PT_EncodingOpr ptEncodingOpr, PT_FontOpr ptFontOpr) 通过头节点插入新的结构体 int DelFontOprFrmEncoding(PT_EncodingOpr ptEncodingOpr, PT_FontOpr ptFontOpr) 删除编码格式 int EncodingInit(void) 调用各种init 具体初始化在下一层函数 */