当前位置: 首页 > news >正文

Linux应用项目之量产工具(一)——显示系统

目录

前言

项目特点及介绍

① 简单易用

② 软件可配置、易扩展

③ 纯 C 语言编程

软件总框架

显示系统

1.数据结构抽象

disp_manager.h

2.Framebuffer编程

framebuffer.c

3.显示管理

disp_manager.c

4.单元测试

disp_test.c

顶层目录Makefile

顶层目录Makefile.build

底层目录display中的Makefile

底层目录unittest中的Makefile


前言

        今天开始学习Linux的第一个实战项目——电子产品量产测试与烧写工具,简称量产工具。这是一套软件,用在我们的实际生产中,有如下特点:


项目特点及介绍

① 简单易用

        把这套软件烧写在 SD 卡上,插到 IMX6ULL 板子里并启动,它就会自动测试各个模块、烧写 EMMC 系统。
        工人只要按照说明接入几个模块,就可以完成整个测试、烧写过程。
        测试结果一目了然:等 LCD 上所有模块的图标都变绿时,就表示测试通过。

② 软件可配置、易扩展

        通过配置文件添加测试项,可以添加不限个数的测试项。
        每个测试项有自己的测试程序,测试通过后把结果发送给 GUI 即可。各个测试程序互不影响。

③ 纯 C 语言编程

        下图是这个工具的界面,它可以一边测试一边烧写:

        上图中的 led、speaker 按钮,可以点击:
① 当你看到 LED 闪烁时,就点击 led 按钮,它变成绿色表示测试通过;
② 当你从耳机里听到声音时,就点击 speaker 按钮,它变成绿色表示测试通过。
        其他按钮无法点击,接上对应模块后会自动测试,测试通过时图标就会变绿。
        上图中的蓝色按钮表示烧写 EMMC 的进度,烧写成功后它也会变绿。
        LCD 上所有图标都变绿时,就表示测试、烧写全部完成;某项保持红色的话,就表示对应模块测试失败。

        对这个项目,我们要拆分出多个子系统,并且这些子系统与业务无关,以后还可以应用在其他项目上;我们编写各个子系统的代码时,要抽象出它的对外接口,增加它的扩展性,减少和其他模块的耦合性。通过这个项目,能锻炼我们面向对象的编程思想以及对事物的抽象能力等等。这个项目可以无限扩展,比如:


软件总框架

        要想最大程度复用我们写的代码,就需要模块化编程,拿显示系统举例,我们可以通过Framebuffer把数据显示到屏幕上,我们就可以构造出一个结构体,调用结构体里的初始化函数等等来使用这个模块;对于有些设备,它可能不需要用到屏幕,而是用到web输出,通过网络的方式显示数据,在网页打印出来,假设我们以后对于显示系统还要添加更多的模块,对于每个模块我们都要构造出它的结构体吗?显然是不用的,我们可以抽象出同一个结构体类型


显示系统

1.数据结构抽象

        来看看这个框图,我们要先获得一个buffer,我们可以自己在这个buffer里绘制我们想要的图案,绘制好后可以通过Framebuffer刷到屏幕上显示,也可以通过网络传输在浏览器上显示出来。

我们可以定义出下面这个结构体:

disp_manager.h

#ifndef _DISP_MANAGER_H
#define _DISP_MANAGER_H/*编译的时候报错说NULL未定义,我们干脆自己定义好了*/
#ifndef NULL
#define NULL (void *)0
#endif/*存放buffer的信息*/
typedef struct DispBuff {int iXres;/*x坐标的像素值*/int iYres;/*y坐标的像素值*/int iBpp;/*每个像素有多少位(像素的大小)*/char *buff;/*指向得到的buffer,然后就可以操作它了*/
}DispBuff, *PDispBuff;/*存放图像的区域信息*/
typedef struct Region {int iLeftUpX;/*区域左上角的x坐标*/int iLeftUpY;/*区域左上角的y坐标*/int iWidth;/*宽*/int iHeight;/*高*/
}Region, *PRegion;/*模块调用这个结构体里的函数,需要我们自己去实现里面的函数*/
typedef struct DispOpr {char *name;int (*DeviceInit)(void);//初始化函数int (*DeviceExit)(void);//退出函数int (*GetBuffer)(PDispBuff ptDispBuff);//获得buffer,以便绘制图像int (*FlushRegion)(PRegion ptRegion, PDispBuff ptDispBuff);//将buffer刷到对应的设备
(屏幕/网页),将ptDispBuff结构体指针指向的结构体里的buffer信息刷到Region结构体里(存放区域的信息)
表示你想在哪里显示?struct DispOpr *ptNext;//用链表管理这些模块
}DispOpr, *PDispOpr;/*****************************************/
/** 这些声明的函数我们后面再写,我先给出源码,先忽略这部分*/
void RegisterDisplay(PDispOpr ptDispOpr);void DisplayInit(void);
int SelectDefaultDisplay(char *name);
int InitDefaultDisplay(void);
int PutPixel(int x, int y, unsigned int dwColor);
int FlushDisplayRegion(PRegion ptRegion, PDispBuff ptDispBuff);
PDispBuff GetDisplayBuffer(void);#endif

这些结构体都是一步一步改善过来的,所以我尽量把注释写的详细一点,我们想要在屏幕或者网页(网页暂时没有实现)上显示,我们首先要实现 struct DispOpr 这个结构体里的各个函数,然后定义出各个模块的结构体,就可以调用定义出来的结构体里的函数实现各个功能。

2.Framebuffer编程

        对于Framebuffer编程不熟悉的同学可以去看我这篇博客Framebuffer应用编程,下面用到的函数都是直接复制之前写的代码,原理就不再讲解了。

framebuffer.c

        我们先定义出给LCD屏幕使用的结构体,再去实现底层的函数。以后上层APP就可以调用结构体里的 DeviceInit 等函数,不需要关心底层的驱动代码。这就是面向对象的编程思想。

源码如下:

#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)
{/*打开设备结点,获得LCD参数等等*/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;}/*使用mmap函数获得可以直接操作LCD的buffer*/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)
{/*释放buffer,关闭设备结点*/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;
}/*为了方便,我们直接得到可以操作LCD的buffer,因此不需要Flush函数*/
static int FbFlushRegion(PRegion ptRegion, PDispBuff ptDispBuff)
{return 0;
}static DispOpr g_tFramebufferOpr = {.name        = "fb",.DeviceInit  = FbDeviceInit,.DeviceExit  = FbDeviceExit,.GetBuffer   = FbGetBuffer,.FlushRegion = FbFlushRegion,
};/*RegisterDisplay函数是将显示系统的所有设备注册到链表里统一管理,这在后面会讲,这里先忽略*/
void FramebufferInit(void)
{RegisterDisplay(&g_tFramebufferOpr);
}

        这里就是实现了底层的驱动函数,实现 DispOpr 结构里的函数。

3.显示管理

        我们的应用程序当然可以直接使用我们上面构造的结构体,但是我有多个显示模块,我们还需要一个公共的部分,来选择我们要使用的模块,所以需要还需要写出管理底层模块的代码。

框图如下:

        我们要写出 disp_manager.c 这个程序,它起到承上启下的作用,很多函数其实也只是调用最底层的代码,但是我们再经过一层封装,就非常方便的实现管理底层的模块 

disp_manager.c

#include <stdio.h>
#include <string.h>
#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;/*描点函数,是所有图像的基础,我之前写的Framebuffer应用编程里有讲*/
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 ptDispOpr)
{ptDispOpr->ptNext = g_DispDevs;g_DispDevs = ptDispOpr;
}/* 选择函数,传入想要操作的底层模块的名字,如"fb",表示使用Framebuffer在屏幕上显示* 遍历链表,如果模块注册进链表里并且找到了名字,g_DispDefault就会指向我们想操作的模块的结构体*/
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;/*调用g_DispDefault指向的结构体,调用底层的模块初始化函数*/ret = g_DispDefault->DeviceInit();if (ret){printf("DeviceInit err\n");return -1;}/*获得buffer,参数会保存在传入的结构体里面*/ret = g_DispDefault->GetBuffer(&g_tDispBuff);if (ret){printf("GetBuffer err\n");return -1;}/*这两个参数是为了给描点函数用的,看描点函数第一行计算pen_8的地址,需要这两个参数*/line_width  = g_tDispBuff.iXres * g_tDispBuff.iBpp/8;pixel_width = g_tDispBuff.iBpp/8;return 0;
}/*把获得到的buffer返回给上层代码*/
PDispBuff GetDisplayBuffer(void)
{return &g_tDispBuff;
}/*Flush函数,底层的Flush函数我们并没有写,这里可以忽略*/
int FlushDisplayRegion(PRegion ptRegion, PDispBuff ptDispBuff)
{return g_DispDefault->FlushRegion(ptRegion, ptDispBuff);
}/*这里的初始化函数是将模块的结构体注册到链表里*/
void DisplayInit(void)
{extern void FramebufferInit(void);FramebufferInit();
}

虽然代码封装了很多层,但是这样便于以后添加更多的模块,更加容易扩展和移植。

4.单元测试

disp_test.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>#define FONTDATAMAX 4096
/*略*/

        需要自己定义点阵字体,这里我就省略了,可以看我关于Framebuffer的博客,或者去看韦东山老师的相关课程,里面有讲到哪里可以找到这个字体库。

/*********************************************************************** 函数名称: lcd_put_ascii* 功能描述: 在LCD指定位置上显示一个8*16的字符* 输入参数: x坐标,y坐标,ascii码* 输出参数: 无* 返 回 值: 无* 修改日期        版本号     修改人	      修改内容* -----------------------------------------------* 2020/05/12	     V1.0	  zh(angenao)	      创建***********************************************************************/ 
void lcd_put_ascii(int x, int y, unsigned char c)
{unsigned char *dots = (unsigned char *)&fontdata_8x16[c*16];int i, b;unsigned char byte;for (i = 0; i < 16; i++){byte = dots[i];for (b = 7; b >= 0; b--){if (byte & (1<<b)){/* show */PutPixel(x+7-b, y+i, 0xffffff); /* 白 */}else{/* hide */PutPixel(x+7-b, y+i, 0); /* 黑 */}}}
}int main(int argc, char **argv)
{Region region;PDispBuff ptBuffer;/*调用这个函数把所有模块注册到链表里(我们暂时只用到Framebuffer)*/DisplayInit();/*然后选择要操作的模块,传入名字*/SelectDefaultDisplay("fb");/*底层的初始化(打开设备节点等操作)*/InitDefaultDisplay();/*调用显示字符的函数,在这个函数里会调用的描点函数,所以我说描点函数是基础*/lcd_put_ascii(100, 100, 'A');/*这里是初始化一下要传入Flush函数的结构体*/region.iLeftUpX = 100;region.iLeftUpY = 100;region.iWidth   = 8;region.iHeigh   = 16;/*获得buffer*/ptBuffer = GetDisplayBuffer();/*刷到硬件上(暂时只有屏幕)*/FlushDisplayRegion(&region, ptBuffer);return 0;	
}

接下来给大伙看看函数的调用流程。

        多层函数的封装看起来会很乱,但如果看过我之前一篇博客UART开发基础,这篇博客也是我第一次接触这种面向对象的编程思想,像我之前写代码,也是直接APP调用底层函数,快准狠,但是如果以后工作,这种方法显然不可行,而且也锻炼不了什么事物抽象的能力,面对一些大型的项目可能会无从下手,但是这些结构体里的参数,也不是一下子就能想出来的,都是边写边补,缺啥补啥。

上传到Ubuntu时,要整个文件上传,如下:

        并且在要编译的文件夹下添加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 


        量产工具的第一篇博客就到此为止,下一篇是量产工具的输入系统,希望大伙多多关注支持。

相关文章:

Linux应用项目之量产工具(一)——显示系统

目录 前言 项目特点及介绍 ① 简单易用 ② 软件可配置、易扩展 ③ 纯 C 语言编程 软件总框架 显示系统 1.数据结构抽象 disp_manager.h 2.Framebuffer编程 framebuffer.c 3.显示管理 disp_manager.c 4.单元测试 disp_test.c 顶层目录Makefile 顶层目录Makefil…...

Python小白学习教程从入门到入坑------第二十九课 访问模式(语法进阶)

目录 一、访问模式 1.1 r 1.2 w 1.3 1.3.1 r 1.3.2 w 1.3.3 a 1.4 a 一、访问模式 模式可做操作若文件不存在是否覆盖r只能读报错-r可读可写报错是w只能写创建是w可读可写创建是a只能写创建否&#xff0c;追加写a可读可写创建否&#xff0c;追加写 1.1 r r&…...

使用 PageHelper 在 Spring Boot 项目中实现分页查询

目录 前言1. 项目环境配置1.1 添加 PageHelper 依赖1.2 数据库和 MyBatis 配置 2. 统一的分页响应类3. 使用 PageHelper 实现分页查询3.1 Service 层分页查询实现3.2 PageHelper 分页注意事项 4. 控制层调用示例5. 常见问题与解决方案5.1 java.util.ArrayList cannot be cast t…...

深度学习-张量相关

一. 张量的创建 张量简介 张量是pytorch的基本数据结构 张量&#xff0c;英文为Tensor&#xff0c;是机器学习的基本构建模块&#xff0c;是以数字方式表示数据的形式。 例如&#xff0c;图像可以表示为形状为 [3, 224, 224] 的张量&#xff0c;这意味着 [colour_channels, h…...

电脑提示xinput1_3.dll丢失怎么解决,分享6种有效的解决方法

xinput1_3.dll 是一个动态链接库&#xff08;DLL&#xff09;文件&#xff0c;它在Windows操作系统中扮演着重要的角色&#xff0c;特别是在处理游戏控制器和其他输入设备的交互方面。这个文件是Microsoft DirectX软件包的一部分&#xff0c;DirectX是微软公司开发的一个多媒体…...

【计网】数据链路层笔记

【计网】数据链路层 数据链路层概述 数据链路层在网络体系结构中所处的地位 链路、数据链路和帧 链路(Link)是指从一个节点到相邻节点的一段物理线路(有线或无线)&#xff0c;而中间没有任何其他的交换节点。 数据链路(Data Link)是基于链路的。当在一条链路上传送数据时&a…...

蓝牙FTP 协议详解及 Android 实现

文章目录 前言一、什么是蓝牙 FTP 协议&#xff1f;二、FTP 的工作流程1.蓝牙设备初始化2. 设备发现与配对3. 建立OBEX FTP 连接4. 文件传输文件上传&#xff08;通过OBEX PUT命令&#xff09;文件下载&#xff08;通过OBEX GET命令&#xff09; 5. 关闭OBEX会话 三、进阶应用与…...

【前端】Svelte:动画效果

在现代前端开发中&#xff0c;动画效果可以大大提升用户体验&#xff0c;使应用更生动、易用。Svelte 提供了灵活的动画 API&#xff0c;让开发者能够快速实现从简单过渡到复杂动画的各种效果。本文将系统性地介绍 Svelte 的动画功能&#xff0c;并通过多个示例演示如何创建动感…...

2024系统架构师--论基于架构的软件设计方法(ABSD)及应用(论文范文)

题目: 基于架构的软件设计(Architecture-Based Software Design,ABSD)方法以构成软件架构的商业、质量和功能需求等要素来驱动整个软件开发过程。ABSD是一个自顶向下,递归细化的软件开发方法,它以软件系统功能的分解为基础,通过选择架构风格实现质量和商业需求,并强调在架…...

ORU 的 Open RAN 管理平面 (M 平面)

[TOC](ORU 的 Open RAN 管理平面 (M 平面)) ORU 的 Open RAN 管理平面 (M 平面) https://www.techplayon.com/open-ran-management-plane-m-plane-for-open-radio-unit/ ORU M 平面 在 ORAN 中&#xff0c;设置参数的 O-RU 管理功能是通过 M-Plane 完成的。管理功能包括 O-…...

软件缺陷等级评定综述

1. 前言 正确评估软件缺陷等级&#xff0c;在项目的生命周期中有着重要的作用&#xff1a; 指导缺陷修复的优先级和资源分配 在软件开发和维护过程中&#xff0c;资源&#xff08;包括人力、时间和资金&#xff09;是有限的。通过明确缺陷的危险等级&#xff0c;可以帮助团队合…...

Nuxt.js 应用中的 schema:extend事件钩子详解

title: Nuxt.js 应用中的 schema:extend事件钩子详解 date: 2024/11/10 updated: 2024/11/10 author: cmdragon excerpt: schema:extend 钩子使开发者能够扩展默认数据模式,为特定业务需求添加自定义字段和验证。 categories: 前端开发tags: Nuxt钩子数据扩展自定义验证应…...

自然语言处理在客户服务中的应用

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 自然语言处理在客户服务中的应用 自然语言处理在客户服务中的应用 自然语言处理在客户服务中的应用 引言 自然语言处理概述 定义…...

OpenCoder:首个完全开源的顶级代码大模型,训练秘籍全公开!| LLM×MapReduce,无需训练就超越GPT-4!

大模型领域的发展日新月异&#xff0c;每天都有许多有趣的论文值得深入品读。下面是本期觉得比较有意思的论文&#xff1a; 1、OpenCoder&#xff1a;首个完全开源的顶级代码大模型&#xff0c;训练秘籍全公开&#xff01;2、超长文本处理新突破&#xff01;LLMMapReduce&…...

springboot静态资源映射不生效问题

最近有个同事问我&#xff0c;静态资源映射不生效的问题&#xff0c;很正常我想不就是配置下资源路径就可以了吗&#xff1f;类似配置如下代码 Configuration public class CorsConfig implements WebMvcConfigurer {Overridepublic void addResourceHandlers(ResourceHandlerR…...

通过 SSH 隧道将本地端口转发到远程主机

由于服务器防火墙,只开放了22端口,想要通过5901访问服务器上的远程桌面,可以通过下面的方式进行隧道转发。 一、示例命令 这条代码的作用是通过 SSH 创建一个 本地端口转发,将你本地的端口(5901)通过加密的 SSH 隧道连接到远程服务器上的端口(5901)。这种方式通常用于在…...

【北京迅为】itop-3588开发板摄像头使用手册Android12 双摄方案

本章节对应资料在网盘资料“iTOP-3588 开发板\02_【iTOP-RK3588 开发板】开发资料 \07_Android 系统开发配套资料\08_Android12 摄像头使用配套资料”目录下下载。 2.1 Android12 前摄后摄 网盘中默认的 Android12 源码支持四个摄像头单独打开&#xff0c;本小节我们来修改源码…...

初见Linux:基础开发工具

前言&#xff1a; 这篇文章我们将讲述Linux的基本开发工具&#xff0c;以及讨论Linux的生态圈&#xff0c;最后再了解vim开发工具。 Yum&#xff1a; YUM&#xff08;Yellowdog Updater Modified&#xff09;是一个在Linux系统中用于管理软件包的工具&#xff0c;特别是在基于…...

微服务架构面试内容整理-分布式配置管理-Nacos Config

Nacos Config 是 Nacos 提供的一个配置管理功能,专门用于动态管理应用的配置。在微服务架构中,Nacos Config 允许开发者集中管理和动态更新各个服务的配置,从而提升系统的灵活性和可维护性。以下是 Nacos Config 的主要特点、工作原理和使用场景: 主要特点 1. 动态配置管理…...

React官网生成Recat项目的区别

1. Next.js 特点&#xff1a; 页面级路由&#xff1a;使用文件系统路由&#xff0c;基于 /pages 文件夹的结构自动创建 URL 路径。渲染模式&#xff1a;支持三种渲染模式&#xff1a;静态生成 (SSG)、服务器端渲染 (SSR) 和客户端渲染 (CSR)&#xff0c;并允许根据页面的具体需…...

React hook之useRef

React useRef 详解 useRef 是 React 提供的一个 Hook&#xff0c;用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途&#xff0c;下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...

FastAPI 教程:从入门到实践

FastAPI 是一个现代、快速&#xff08;高性能&#xff09;的 Web 框架&#xff0c;用于构建 API&#xff0c;支持 Python 3.6。它基于标准 Python 类型提示&#xff0c;易于学习且功能强大。以下是一个完整的 FastAPI 入门教程&#xff0c;涵盖从环境搭建到创建并运行一个简单的…...

【解密LSTM、GRU如何解决传统RNN梯度消失问题】

解密LSTM与GRU&#xff1a;如何让RNN变得更聪明&#xff1f; 在深度学习的世界里&#xff0c;循环神经网络&#xff08;RNN&#xff09;以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而&#xff0c;传统RNN存在的一个严重问题——梯度消失&#…...

【单片机期末】单片机系统设计

主要内容&#xff1a;系统状态机&#xff0c;系统时基&#xff0c;系统需求分析&#xff0c;系统构建&#xff0c;系统状态流图 一、题目要求 二、绘制系统状态流图 题目&#xff1a;根据上述描述绘制系统状态流图&#xff0c;注明状态转移条件及方向。 三、利用定时器产生时…...

三体问题详解

从物理学角度&#xff0c;三体问题之所以不稳定&#xff0c;是因为三个天体在万有引力作用下相互作用&#xff0c;形成一个非线性耦合系统。我们可以从牛顿经典力学出发&#xff0c;列出具体的运动方程&#xff0c;并说明为何这个系统本质上是混沌的&#xff0c;无法得到一般解…...

项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)

Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败&#xff0c;具体原因是客户端发送了密码认证请求&#xff0c;但Redis服务器未设置密码 1.为Redis设置密码&#xff08;匹配客户端配置&#xff09; 步骤&#xff1a; 1&#xff09;.修…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

dify打造数据可视化图表

一、概述 在日常工作和学习中&#xff0c;我们经常需要和数据打交道。无论是分析报告、项目展示&#xff0c;还是简单的数据洞察&#xff0c;一个清晰直观的图表&#xff0c;往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server&#xff0c;由蚂蚁集团 AntV 团队…...

ip子接口配置及删除

配置永久生效的子接口&#xff0c;2个IP 都可以登录你这一台服务器。重启不失效。 永久的 [应用] vi /etc/sysconfig/network-scripts/ifcfg-eth0修改文件内内容 TYPE"Ethernet" BOOTPROTO"none" NAME"eth0" DEVICE"eth0" ONBOOT&q…...

Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析

Java求职者面试指南&#xff1a;Spring、Spring Boot、MyBatis框架与计算机基础问题解析 一、第一轮提问&#xff08;基础概念问题&#xff09; 1. 请解释Spring框架的核心容器是什么&#xff1f;它在Spring中起到什么作用&#xff1f; Spring框架的核心容器是IoC容器&#…...