电子产品量产工具-学习笔记(1)总体结构及显示部分

​​

TOC](100ask电子产品量产工具)

程序架构

程序总体框架如下:
请添加图片描述
图中有多种设备,目前,百问网该项目只实现了main page,framebuffer,触摸屏输入,网络输入和freetype。
全部代码参考链接:https://github.com/studyalldaya/100ask_project1
1. 100ask电子产品量产工具学习笔记(2)输入部分
2. 100ask电子产品量产工具学习笔记(3)字体显示部分
3. 100ask电子产品量产工具学习笔记(4)按钮及页面抽象
4. 100ask电子产品量产工具学习笔记(5)业务部分

与韦老师不同的是,我是使用clion远程连接Ubuntu进行开发,使用cmake组织代码。
CMakeLists如下:

cmake_minimum_required(VERSION 3.10)
project(100ask_project1 C)

set(CMAKE_C_STANDARD 99)
#添加tslib库
set(INC_DIR ~/100ask_imx6ull-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/arm-buildroot-linux-gnueabihf/sysroot/usr/include)
set(LINK_DIR ~/100ask_imx6ull-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/arm-buildroot-linux-gnueabihf/sysroot/usr/lib)
include_directories(
        ${INC_DIR}
        ${INC_DIR}/freetype2
)

link_directories(${LINK_DIR})

add_executable(100ask_project1 main.c include/disp_manager.h display/framebuffer.c display/disp_manager.c include/input_manager.h input/touchscreen.c input/net_input.c input/input_manager.c include/font_manager.h font/font_freetype.c font/font_manager.c include/common.h include/UI.h UI/button.c include/page_manager.h page/page_manager.c page/main_page.c include/config.h config/config.c)

target_link_libraries(
        100ask_project1
        ts
        pthread
        freetype
        m
)

显示部分

上层display_manager

通过结构体抽象出一个Display_device,然后通过结构体里面 的函数指针实现不同显示设备的执行不同函数。最底层的是设备文件,如framebuffer设备,或者在web上显示,然后上面一层是一个显示管理器,来管理下层的不同设备,在这个显示管理器中实现一个单向链表连接不同设备,后续可通过name来找到设备。并且要提供api供其它文件使用。
通过Display_buffer 来表示得到的一个framebuffer相关信息。

typedef struct Display_buffer {
    int xres;
    int yres;
    int bpp;
    char *fb_base;
} Display_buffer;
typedef struct Display_device {
    char *name;

    //函数指针用作多态
    int (*device_init)(void);//open
    int (*device_exit)(void);//close
    int (*get_buffer)(Display_buffer *disp_buffer);

    int (*flush_region)(Region *region, Display_buffer *buffer);

    struct Display_device *next;//支持多个输出  lcd or web
} Display_device;

通过register_display函数提供给底层的设备文件,用来注册该设备到链表,底层设备文件的函数都应该是static的,通过函数指针暴露给上层代码。其中display_dev为链表的头。

void register_display(Display_device *dev)
{
    dev->next = display_dev;//
    display_dev = dev;//注册上来
}

register_display函数提供给底层设备文件,底层设备文件需要调用register_display函数,这里是在设备文件的framebuffer_register函数里面使用register_display函数。
所以上层api要提供一个display_init函数来调用底层的framebuffer_register函数来注册framebuffer设备。

extern void framebuffer_register(void);//声明该函数,在其它文件寻找该函数
void display_init()
{
    framebuffer_register();
}

通过select_default_display函数找到对应name的设备,遍历设备链表。

int select_default_display(char *name)
{
    Display_device *tmp = display_dev;
    while (tmp) {
        if (strcmp(name, tmp->name) == 0) {
            display_default = tmp;
            return 0;
        }
        tmp = tmp->next;
    }
    return -1;
}

通过init_default_display函数,调用对应设备的init函数,get_buffer函数,初始化framebuffer设备并获得framebuffer的base及相关信息。

int init_default_display(void)
{
    int ret;
    ret = display_default->device_init();
    if (ret) {
        printf("device_init err!\n");
        return -1;
    }
    ret = display_default->get_buffer(&display_buffer);
    if (ret) {
        printf("get_buffer err!\n");
        return -1;
    }
    line_width = display_buffer.xres * display_buffer.bpp / 8;
    pixel_width = display_buffer.bpp / 8;
    return 0;
}

底层支持framebuffer设备

如上所述,底层调用register_display向上注册该设备并接入设备链表。

void framebuffer_register(void)
{
    register_display(&framebuffer_dev);
}

实现Display_device 结构体为framebuffer_dev ,name为fb。

static Display_device framebuffer_dev = {
        .name = "fb",
        .device_init = fb_device_init,
        .device_exit = fb_device_exit,
        .get_buffer = fb_get_buffer,
        .flush_region = fb_flush_region,
};

fb_device_init函数就是framebuffer的应用层编程了。打开/dev/fb0设备节点,通过ioctl函数获得framebuffer的info放入全局变量var中,从而计算出屏幕的大小screen_size ,
我需要多大内存来映射framebuffer,通过mmap函数将文件映射到内存空间,然后可以通过读写内存来读写文件,应用层得到映射内存的起始base值,也就是对应屏幕左上角。
MAP_SHARED表示对映射区域的写入数据会复制回文件内,而且允许其他映射该文件的进程共享。

static int fb_device_init(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;

}

fb_get_buffer函数填充Display_buffer 。上层直接调用get_buffer函数就会执行对应的设备的get_buffer函数。

static int fb_get_buffer(Display_buffer *disp_buffer)
{
    disp_buffer->xres = var.xres;
    disp_buffer->yres = var.yres;
    disp_buffer->bpp = var.bits_per_pixel;
    disp_buffer->fb_base = fb_base;
    return 0;
}

取消内存映射,关闭文件描述符。

static int fb_device_exit(void)
{
    munmap(fb_base, screen_size);
    close(fd_fb);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值