电子量产工具:显示系统-显示管理

总框图



显示管理:


我们需要在上层代码和底层代码之间抽象出一个管理层代码(disp_manager.c),它的作用如下

  • 承上启下
  • 底层将各个模块(LCD或Web DispOpr结构体)注册进disp_manager.c
  • 上层APP选择使用哪个模块(LCD或Web)
  • 可以提供一些函数,比如PutPixel(描点),然后将修改过的区域刷到LCD或Web上

disp_manager.c内容:

#include "disp_manager.h"

/* 链表:管理底层的LCD WEB */
static PDispOpr g_DispDevs = NULL;
static PDispOpr g_DispDefault = NULL;
static DispBuff g_tDispBuff;
static int line_width;
static int pixel_width;

int PutPixel(int x, int y, unsigned int dwColor)
{
    unsigned char *pen_8 = g_tDispBuff.buff + y * line_width + x * pixel_width;
    unsigned short *pen_16;
    unsigned int *pen_32;

    unsigned int red, green, blue;

    pen_16 = (unsigned short *)pen_8;
    pen_32 = (unsigned int *)pen_8;

    switch (g_tDispBuff.iBpp)
    {
    case 8:
    {
        *pen_8 = dwColor;
        break;
    }
    case 16:
    {
        /* 565 */
        red = (dwColor >> 16) & 0xff;
        green = (dwColor >> 8) & 0xff;
        blue = (dwColor >> 0) & 0xff;
        dwColor = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3);
        *pen_16 = dwColor;
        break;
    }
    case 32:
    {
        *pen_32 = dwColor;
        break;
    }
    default:
    {
        printf("can't surport %dbpp\n", g_tDispBuff.iBpp);
        break;
    }
    }
}

void RegisterDisply(PDispOpr ptDispOpr)
{
    ptDispOpr->ptNext = g_DispDevs; //ptNext指向链表头
    g_DispDevs = ptDispOpr;
}

int SelectDefaultDisplay(char *name)
{
    PDispOpr pTmp = g_DispDevs;
    while (pTmp) //遍历链表
    {
        if (strcmp(name, pTmp->name) == 0)
        {
            g_DispDefault = pTmp;
            return 0;
        }
        pTmp = pTmp->ptNext;
    }
    return -1;
}

int InitDefaultDisplay(void)
{
    int ret;

    ret = g_DispDefault->DeviceInit();
    if (ret)
    {
        print("DeviceInit err\n");
        return -1;
    }

    ret = g_DispDefault->GetBuffer(&g_tDispBuff);
    {
        print("GetBuffer err\n");
        return -1;
    }

    line_width = g_tDispBuff.iXres * g_tDispBuff.iBpp / 8;
    pixel_width = g_tDispBuff.iBpp / 8;

    return 0;
}

int FlushDisplayRegion(PRegion ptRegion, PDispBuff ptDispBuff)
{
    return g_DispDefault->FlushRegion(ptRegion, ptDispBuff);
}

void DisplayInit(void)
{
    FramebufferInit();
}

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)
{
    int munmap(screen_size, screen_size); //解除映射关系
    close(fd_fb);
    return 0;
}

/* 
 *可以返回LCD的Framebuffer,以后上层APP可以直接操作LCD,可以不用FbFlushRegion
 *也可以malloc返回一块无关的buffer,要使用FbFlushRegion
 */

static int FbGetBuffer(PDispBuff ptDispBuff)
{
    ptDispBuff->iXres = var.xres;
    ptDispBuff->iYres = var.yres;
    ptDispBuff->iBpp = var.bits_per_pixel;
    ptDispBuff->buff = fb_base;
    return 0;
}

static int FbFlushRegion(PRegion ptRegion, PDispBuff ptDispBuff)
{
    return 0;
}

/* 需要实现DispOpr结构体,结构体需要增加DeviceInit和DeviceExit两个函数 */
static DispOpr g_tFramebufferOpr = {
    .name = "fb",
    .DeviceInit = FbDeviceInit,
    .DeviceExit = FbDeviceExit,
    .GetBuffer = FbGetBuffer,
    .FlushRegion = FbFlushRegion,
};

void FramebufferInit(void)
{
    RegisterDisply(&g_tFramebufferOpr);
}

disp_manager.h 内容

#ifndef _DISP_MANAGER_H
#define _DISP_MANAGER_H

typedef struct DispBuff
{
    int iXres;
    int iYres;
    int iBpp;
    char *buff;
} DispBuff, *PDispBuff;

typedef struct Region
{
    /* 某个按钮的区域需要以下内容表示*/
    int iLeftUpX; //左上角X坐标
    int iLeftUpY; //左上角Y坐标
    int iWidth;   //宽度
    int iHeigh;   //高度
} Region, *PRegion;

/* 上层代码调用DispOpr结构体函数就可以显示数据;此时可以通过拷贝数据到Framebuffer或者通过网络将数据发送至web浏览器 */

typedef struct DispOpr
{
    char *name;                                              //通过名字取得不同的结构体(比如:Framebuffer或者web输出)
    int DeviceInit(void);                                    //设备初始化
    int DeviceExit(void);                                    //设备退出
    int GetBuffer(PDispBuff ptDispBuff);                     //绘制图片,需要获得一个buffer,返回内存的起始地址,还可以得到分辨率和每个像素的位数
    int FlushRegion(PRegion ptRegion, PDispBuff ptDispBuff); //刷新区域,比如某个按钮的区域
    struct DispOpr *ptNext;                                  //可能支持多个输出设备(Freambuffer,或者web输出),需要链表将结构体链接起来
} DispOpr, *PDispOpr;

void RegisterDisply(PDispOpr ptDispOpr);
int SelectDefaultDisplay(char *name);
int InitDefaultDisplay(void);
void FramebufferInit(void);
void DisplayInit(void);
int PutPixel(int x, int y, unsigned int dwColor);
int FlushDisplayRegion(PRegion ptRegion, PDispBuff ptDispBuff);

#endif

程序调用流程

1、应用程序调用DisplayInit,DisplayInit调用底层FramebufferInit(也可以添加WebbufferInit)

2、底层FramebufferInit调用RegisterDisply 注册函数,将g_tFramebufferOpr结构体放入链表。

3、假设链表有很多项,对应不同的显示方式。此时调用SelectDefaultDisplay选择默认的显示设备。

4、选择默认的显示设备后,可以使用InitDefaultDisplay初始化显示设备

 InitDefaultDisplay 调用g_DispDefault->DeviceInit和g_DispDefault->GetBuffer完成设备的初始化和获得buffer工作。

5、此时可以调用PutPixel绘制图片,然后调用FlushDisplayRegion将绘制好的区域刷到硬件上。

1、DisplayInit

        ->FramebufferInit

                ->RegisterDisply 

2、SelectDefaultDisplay

3、InitDefaultDisplay

        ->g_DispDefault->DeviceInit

        ->g_DispDefault->GetBuffer

4、PutPixel

5、FlushDisplayRegion

总结:
程序虽然变复杂了,但是程序变的更加容易扩展,以后更换显示硬件,不需要改动disp_manager.c 这一层程序,只需要将底层的结构体实现即可,这便是程序分层的概念.。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值