韦东山 Linux 数码相框(电子阅览器)

数码相框

  • 输入进程 : 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 具体初始化在下一层函数
*/
​

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值