量产工具一一显示系统(一)

news2024/10/7 16:16:21

目录

前言

一、项目介绍和应用

1.简单易用

2.软件可配置、易扩展

3.纯 C 语言编程

4.类似界面应用

二、项目总体框架

三、显示系统

1.显示系统数据结构抽象

(1)common.h

(2)disp_manager.h

2.Framebuffer编程

(1)framebuffer.c

3.显示管理

(1)disp_manager.c

4.测试单元

(1)测试代码

(2)通用Makefile

四、上机测试


前言

该项目是韦东山老师Linux入门基础课程的第一个项目,在这里我用的是IMX6ULL开发板。通过学习这个项目,可以学到良好的编程规范,面向对象的编程思想,对事物的抽象能力,对整个系统的把控能力。

一、项目介绍和应用

电子产品量产测试与烧写工具,这是一套软件,用在我们的实际生产中, 有如下特点:

1.简单易用

把这套软件烧写在 SD 卡上,插到 IMX6ULL 板子里并启动,它就会自动测试各个模块、烧写 EMMC 系统。

工人只要按照说明接入几个模块,就可以完成整个测试、烧写过程。

测试结果一目了然:等 LCD 上所有模块的图标都变绿时,就表示测试通过。

2.软件可配置、易扩展

通过配置文件添加测试项,可以添加不限个数的测试项。

每个测试项有自己的测试程序,测试通过后把结果发送给 GUI 即可。各个测试程序互不影响。

3.纯 C 语言编程

工具设计的界面,它可以一边测试一边烧写:

a18bbf83af014dcaaa2ef2f419c9805e.png

上图中的 led、speaker 按钮,可以点击: 

1.当你看到 LED 闪烁时,就点击 led 按钮,它变成绿色表示测试通过;

2. 当你从耳机里听到声音时,就点击 speaker 按钮,它变成绿色表示测试通过。

  • 其他按钮无法点击,接上对应模块后会自动测试,测试通过时图标就会变绿。
  • 上图中的蓝色按钮表示烧写 EMMC 的进度,烧写成功后它也会变绿。
  • LCD 上所有图标都变绿时,就表示测试、烧写全部完成;某项保持红色的话,就表示对应模块测试失败。

4.类似界面应用

二、项目总体框架

在软件编程当中,可以把一个项目拆分成各个子系统,并且这些子系统跟业务无关,以后还可以用在其他项目上。对于一个子系统,可以抽象出它的对外接口,减少与其他模块的耦合,方便扩展。

接下来先分析他的第一个框架,显示系统。

三、显示系统

1.显示系统数据结构抽象

我们添加的一个显示管理器中有Framebuflerweb输出,对于两个不同的设备我们可以抽象出同一个结构体类型。

(1)common.h

该头文件用来包含通用区域结构体

#ifndef _COMMON_H
#define _COMMON_H

#ifndef NULL
#define NULL (void *)0

#endif

typedef struct Region {
	int iLeftUpX;
	int iLeftUpY;
	int iWidth;
	int iHeigh;
}Region, *PRegion;


#endif

(2)disp_manager.h

#ifndef _DISP_MANAGER_H
#define _DISP_MANAGER_H
 
#include <common.h>

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


typedef struct DispOpr {
	char *name;
	int (*DeviceInit)(void);
	int (*DeviceExit)(void);
	int (*GetBuffer)(PDispBuff ptPDispBuff);
	int (*FlushRegion)(PRegion ptRegion, PDispBuff ptPDispBuff);
	struct DispOpr *ptNext;
}DispOpr, *PDispOpr;

int PutPixel(int x, int y, unsigned int dwColor);
void RegisterDisplay(PDispOpr ptPDispOpr);
int SelectDefaultDisplay(char *name);
int InitDefaultDisplay(void);
PDispBuff GetDisplayBuffer(void);
int FlushDisplayRegion(PRegion ptPRegion, PDispBuff ptPDispBuff);
void DisplaySystemRegister(void);

#endif

2.Framebuffer编程

Framebuffer编程原理和实操可以看:

(1)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)
{
	munmap(fb_base, 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  = (char *)fb_base;
	return 0;
}


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


static DispOpr g_tFramebufferOpr = {
	.name        = "fb",
	.DeviceInit  = FbDeviceInit,
	.DeviceExit  = FbDeviceExit,
	.GetBuffer   = FbGetBuffer,
	.FlushRegion = FbFlushRegion,
};


void FramebufferRegister(void)
{
	RegisterDisplay(&g_tFramebufferOpr);
}

3.显示管理

上层函数想要选择哪个设备进行显示,需要中间加一个函数进行选择,起到承上启下的作用,用来实现显示管理,是操作Framebuffer还是WEB设备,需要我们选择某个模块,以便于可以提供一些函数,描点等。

(1)disp_manager.c

#include <disp_manager.h>
#include <stdio.h>
#include <string.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 = (unsigned char *)(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);
			return -1;
			break;
		}
	}

	return 0;

}


void RegisterDisplay(PDispOpr ptPDispOpr)
{


	ptPDispOpr->ptNext = g_DispDevs;
	g_DispDevs = ptPDispOpr;
}

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 0;
}

int InitDefaultDisplay(void)
{
	int ret;

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

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

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

	return 0;
}

PDispBuff GetDisplayBuffer(void)
{
	return &g_tDispBuff;
}

int FlushDisplayRegion(PRegion ptPRegion, PDispBuff ptPDispBuff)
{
	return g_DispDefault->FlushRegion(ptPRegion, ptPDispBuff);
}

void DisplaySystemRegister(void)
{
	extern void FramebufferRegister(void);
	FramebufferRegister();
}

4.测试单元

display目录存放 framebuffer.c,disp_manager.c 文件

include目录存放头文件

unittest目录存放单元测试.c文件

(1)测试代码

disp_test.c

(2)通用Makefile

通用Makefile的原理和使用可以看:

顶层目录Makefile

CROSS_COMPILE ?= 
AS		= $(CROSS_COMPILE)as
LD		= $(CROSS_COMPILE)ld
CC		= $(CROSS_COMPILE)gcc
CPP		= $(CC) -E
AR		= $(CROSS_COMPILE)ar
NM		= $(CROSS_COMPILE)nm

STRIP		= $(CROSS_COMPILE)strip
OBJCOPY		= $(CROSS_COMPILE)objcopy
OBJDUMP		= $(CROSS_COMPILE)objdump

export AS LD CC CPP AR NM
export STRIP OBJCOPY OBJDUMP

CFLAGS := -Wall -O2 -g
CFLAGS += -I $(shell pwd)/include

LDFLAGS := 

export CFLAGS LDFLAGS

TOPDIR := $(shell pwd)
export TOPDIR

TARGET := test


obj-y += display/
obj-y += unittest/

all : start_recursive_build $(TARGET)
	@echo $(TARGET) has been built!

start_recursive_build:
	make -C ./ -f $(TOPDIR)/Makefile.build

$(TARGET) : built-in.o
	$(CC) -o $(TARGET) built-in.o $(LDFLAGS)

clean:
	rm -f $(shell find -name "*.o")
	rm -f $(TARGET)

distclean:
	rm -f $(shell find -name "*.o")
	rm -f $(shell find -name "*.d")
	rm -f $(TARGET)
	

顶层目录Makefile.build

PHONY := __build
__build:


obj-y :=
subdir-y :=
EXTRA_CFLAGS :=

include Makefile

# obj-y := a.o b.o c/ d/
# $(filter %/, $(obj-y))   : c/ d/
# __subdir-y  : c d
# subdir-y    : c d
__subdir-y	:= $(patsubst %/,%,$(filter %/, $(obj-y)))
subdir-y	+= $(__subdir-y)

# c/built-in.o d/built-in.o
subdir_objs := $(foreach f,$(subdir-y),$(f)/built-in.o)

# a.o b.o
cur_objs := $(filter-out %/, $(obj-y))
dep_files := $(foreach f,$(cur_objs),.$(f).d)
dep_files := $(wildcard $(dep_files))

ifneq ($(dep_files),)
  include $(dep_files)
endif


PHONY += $(subdir-y)


__build : $(subdir-y) built-in.o

$(subdir-y):
	make -C $@ -f $(TOPDIR)/Makefile.build

built-in.o : $(cur_objs) $(subdir_objs)
	$(LD) -r -o $@ $^

dep_file = .$@.d

%.o : %.c
	$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -Wp,-MD,$(dep_file) -c -o $@ $<
	
.PHONY : $(PHONY)

底层目录display中的Makefile

EXTRA_CFLAGS  := 
CFLAGS_file.o := 

obj-y += disp_manager.o
obj-y += framebuffer.o

底层目录unittest中的Makefile

EXTRA_CFLAGS  := 
CFLAGS_file.o := 

obj-y += disp_test.o

四、上机测试

打开ubuntu,将交叉编译编译成功的文件复制到nfs目录。

上电开发板,挂载 Ubuntu 的 NFS 目录,详细可看:

开发板挂载 Ubuntu 的 NFS 目录_开发板nfs挂载ubuntu-CSDN博客

mount -t nfs -o nolock,vers=3 192.168.5.11:/home/book/nfs_rootfs /mnt

进入NFS目录,编译测试:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1879309.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Conformal Prediction

1 A Gentle Introduction to Conformal Prediction and Distribution-Free Uncertainty Quantification 2 Language Models with Conformal Factuality Guarantees

《数据结构与算法基础 by王卓老师》学习笔记——类C语言有关操作补充

1.元素类型说明 2.数组定义 3.C语言的内存动态分配 4..C中的参数传递 5.传值方式 6.传地址方式 例子

grpc学习golang版( 一、基本概念与安装 )

系列文章目录 第一章 grpc基本概念与安装 第二章 grpc入门示例 第三章 proto文件数据类型 第四章 多服务示例 第五章 多proto文件示例 第六章 服务器流式传输 第七章 客户端流式传输 第八章 双向流示例 文章目录 一、基本介绍1.1 什么是rpc1.2 什么是grpc1.3 grpc的作用1.4 grp…

Django之邮箱注册

目录 一、邮箱验证-环境搭建 1.1、注册流程 1.2、环境搭建 二、封装工具类 三、发送邮件接口开发 四、用户调用发送邮件接口 4.1、Fetch API 4.1.1、GET请求 4.1.2、POST请求 五、完成注册功能 一、邮箱验证-环境搭建 1.1、注册流程 1.2、环境搭建 创建项目 django-a…

4 快速傅里叶变换(fast Fourier transform,FFT)

目录 基2FFT的基本原理&#xff0c;蝶形运算符 第L级旋转因子的计算公式 4点与8点鲽形图 确定输入x(n)的顺序 倒序算法 抽样算法 DFT与FFT运算次数公式 基2FFT的基本原理&#xff0c;蝶形运算符 第L级旋转因子的计算公式 4点与8点鲽形图 确定输入x(n)的顺序 倒序算法 1…

Java开发-实际工作经验和技巧-0003-容易被忽视的Git提交代码规范

Java开发-实际工作经验和技巧-0003-容易被忽视的Git提交代码规范 更多内容欢迎关注我&#xff08;持续更新中&#xff0c;欢迎Star✨&#xff09; Github&#xff1a;CodeZeng1998/Java-Developer-Work-Note 技术公众号&#xff1a;CodeZeng1998&#xff08;纯纯技术文&…

C# Benchmark

创建控制台项目&#xff08;或修改现有项目的Main方法代码&#xff09;&#xff0c;Nget导入Benchmark0.13.12&#xff0c;创建测试类&#xff1a; public class StringBenchMark{int[] numbers;public StringBenchMark() {numbers Enumerable.Range(1, 20000).ToArray();}[Be…

互联网算法备案 | 填报指南

一、填报入口 登陆互联网信息服务算法备案系统&#xff08;以下简称备案系统&#xff09;进行填报&#xff0c;网址为https://beian.cac.gov.cn。系统首页如图1所示。 图1备案系统首页&#xff08;示意图&#xff09; 二、填报流程 填报人员需首先注册并登陆备案系统&#x…

Hugging Face发布重量级版本:Transformer 4.4.2

Hugging Face 宣布发布Transformer 4.4.2&#xff0c;该版本为流行的机器学习库带来了许多新功能和增强功能。此版本引入了几个高级模型&#xff0c;支持新工具和检索增强生成 &#xff08;RAG&#xff09;&#xff0c;提供 GGUF 微调&#xff0c;并整合了量化的 KV 缓存&#…

机械设计简单介绍

机械设计简单介绍 1 介绍1.1 概述1.2 机械机构设计基本步骤1.3 关键1.3.1 静力学1.3.2 动力学1.3.3 运动学1.3.4 刚度学 1.4 示例【机械臂】 2 资料2.1 知识体系2.2 博客类汇总2.3 免费CAD模型获取2.4 3D打印2.5 SolidWorks 3 具备能力3.1 熟练翻阅 机械设计手册3.2 知道 N 家常…

BeautifulSoup 类通过查找方法选取节点

BeautifulSoup 类提供了一些基于 HTML 或 XML 节点树选取节点的方法&#xff0c;其中比较主流 的两个方法是 find() 方法和 find_all() 方法。 find() 方法用于查找符合条件的第一个节点&#xff1b; find_all() 方法用于查找所有符合条件的节点&#xff0c;并以列表的…

代码随想录算法训练营第三十五天(dp)|509. 斐波那契数、70. 爬楼梯、746. 使用最小花费爬楼梯

509. 斐波那契数 题目链接&#xff1a;509. 斐波那契数 文档讲解&#xff1a;代码随想录 状态&#xff1a;so easy 思路&#xff1a;最简单的递归就不说了。使用动态规划的话&#xff0c;状态转移方程 dp[i] dp[i - 1] dp[i - 2] 题解&#xff1a; public int fib(int n) {…

miniconda 弹出黑窗

etc\conda\activate.d 和 envs 中不同环境中的 etc\conda\activated.d&#xff0c;只保留下图中的三个文件即可。

综合项目实战--jenkins节点模式

一、DevOps流程 DevOps是一种方法论,是一系列可以帮助开发者和运维人员在实现各自目标的前提下,向自己的客户或用户交付最大化价值及最高质量成果的基本原则和实践,能让开发、测试、运维效率协同工作的方法。 DevOps流程(自动化测试部分) DevOps完整流程 二、gitee+j…

Leica Cyclone 3DR2024 一款功能强大的点云建模软件下载License获取

Leica Cyclone 3DR 2024 是一款功能强大的点云建模软件&#xff0c;使用旨在为用户提供全面的点云管理、自动化的点云分析&#xff0c;结合强大的建模&#xff0c;在一个直观友好的环境中&#xff0c;专注的完成挑战&#xff0c;提高生产力&#xff0c;轻松创建并交付专业的成果…

AWTK 用 icon_at 属性设置图标位置

1. style 在 style 文件中通过 icon_at 属性设置图标位置。 <style name"right_bottom" icon_at"right_bottom"><normal icon"unchecked_right_bottom" /><pressed icon"unchecked_right_bottom" /><over i…

揭开大语言模型(LLM)内部运作的算法逻辑

本文探讨了 Anthropic 的突破性技术&#xff0c;以揭示大型语言模型 (LLM) 的内部工作原理&#xff0c;揭示其不透明的本质。通过深入研究LLM Claude Sonnet 的“大脑”&#xff0c;Anthropic 增强了人工智能的安全性和可解释性&#xff0c;为人工智能的决策过程提供了更深入的…

语言模型:文本表征词嵌入技术调研

1 文本表征 文本表征是自然语言处理中的关键部分&#xff0c;尤其在当前大模型快速发展的背景下。由于大模型存在知识有限、处理文本长度有限、保密要求和大模型幻觉等问题&#xff0c;结合外部数据显得尤为重要。 为了便于存储和检索&#xff0c;除了保存纯文本外&#xff0…

机器学习基础:开源库学习-Numpy科学计算库

目录 Numpy科学计算库 什么是多维数组 数组基础 高维数组 操作和创建数组 Numpy介绍 创建数组 数组的属性 二维数组 三维数组 数组元素的数据类型 创建特殊的数组 np.arange() np.ones() np.zeros() np.eye() np.linspace() np.logspace() asarray() 数组运…

数据结构—判断题

1.数据的逻辑结构说明数据元素之间的顺序关系&#xff0c;它依赖于计算机的存储结构。 答案&#xff1a;错误 2.(neuDS)在顺序表中逻辑上相邻的元素&#xff0c;其对应的物理位置也是相邻的。 答案&#xff1a;正确 3.若一个栈的输入序列为{1, 2, 3, 4, 5}&#xff0c;则不…