rk3588 驱动开发(一)字符设备开发
3.字符设备驱动开发
3.1 什么是字符设备驱动
字符设备:就是一个个字节,按照字节流进行读写操作的设备,读写是按照先后顺序的。
举例子:IIC 按键 LED SPI LCD 等
Linux 应用程序调用驱动程序流程:
Linux中驱动加载成功后会在/dev 中生成一个/dev/xxx(xxx是驱动文件名字)文件 应用程序对/dev/xxx进行open write read close 等操作
应用程序open函数调用c库函数,c库中的open函数调用系统内核态的open函数,然后调用驱动中的open函数。
3.2字符设备驱动开发
3.2.1 驱动模块的加载和卸载
驱动运行方式有两种:
1、将驱动编译到内核中启动时自动运行驱动程序
2、在 Linux 内核启动以后使用“modprobe”或者“insmod”命令加载驱动模块
这里有两个函数:
module_init(xxx_init); //注册模块加载函数
module_exit(xxx_exit); //注册模块卸载函数
使用modprobe时module_init函数被调用
使用rmmod时module_exit函数被调用
入口函数:
static int __init xxx_init(void)
{/* 入口函数具体内容 */return 0;
}
出口函数:
static void __exit xxx_exit(void)
{
/*出口函数内容*/
}
insmod和modprobe的关系:
insmod 命令不能解决模块的依赖关系,比如 drv.ko 依赖 first.ko 这个模块,就必须先使用insmod 命令加载 first.ko 这个模块,然后再加载 drv.ko 这个模块。
modprobe 就不会存在这个问题,modprobe 会分析模块的依赖关系,然后会将所有的依赖模块都加载到内核中,因此 modprobe 命令相比 insmod 要智能一些。
modprobe 命令主要智能在提供了模块的依赖性分
析、错误检查、错误报告等功能,推荐使用 modprobe 命令来加载驱动。modprobe 命令默认会去/lib/modules/<kernel-version>目录中查找模块,kernel-version为内核版本号。
驱动模块卸载
驱动模块的卸载使用命令“rmmod”即可,比如要卸载 drv.ko,使用如下命令即可:
rmmod drv.ko
也可以使用“modprobe -r”命令卸载驱动,比如要卸载 drv.ko,命令如下:
modprobe -r drv
使用 modprobe 命令可以卸载掉驱动模块所依赖的其他模块,前提是这些依赖模块已经没有被其他模块所使用,否则就不能使用 modprobe 来卸载驱动模块。所以对于模块的卸载,还是推荐使用 rmmod 命令。
3.2.2 字符设备注册与注销
当驱动模块加载成功后,需要注册字符设备。当驱动模块卸载成时,需要将字符设备注销。
注册和注销设备驱动函数原型如下:
static inline int register_chrdev(unsigned int major,
const char *name,
const struct file_operations *fops)
static inline void unregister_chrdev(unsigned int major,
const char *name)
register_chrdev 函数用于注册字符设备,此函数一共有三个参数,这三个参数的含义如下:
major:主设备号,Linux 下每个设备都有一个设备号,设备号分为主设备号和次设备号两部分,
name:设备名字,指向一串字符串。
fops:结构体 file_operations 类型指针,指向设备的操作函数集合变量。
unregister_chrdev 函数用户注销字符设备,此函数有两个参数,这两个参数含义如下:
major:要注销的设备对应的主设备号。
name:要注销的设备对应的设备名。
查看已使用的设备号:cat /proc/devices
3.2.3 实现设备的具体操作函数
file_operation结构体就是具体的操作函数,如open read write release
29 static struct file_operations test_fops = {
30 .owner = THIS_MODULE,
31 .open = chrtest_open,
32 .read = chrtest_read,
33 .write = chrtest_write,
34 .release = chrtest_release,
35 };
指定初始化器(designated initializer),.成员名 = 值 的语法格式在 C99 标准中被引入。
3.2.4 添加LICENSE和作者信息
LICENSE 是必须添加的,
否则的话编译的时候会报错,作者信息可以添加也可以不添加。LICENSE 和作者信息的添加
使用如下两个函数:
MODULE_LICENSE() //添加模块 LICENSE 信息
MODULE_AUTHOR() //添加模块作者信息
GPL(GNU General Public License,GNU通用公共许可证)是一种开源软件许可协议,由自由软件基金会(FSF)制定,旨在保护软件自由的使用、修改和再发布权利。
GPL 是“你用了我的代码,你就得开源你的代码” 的开源协议。
3.3设备号
3.3.1什么是设备号
设备号(Device Number)是 Linux 内核中用于标识一个设备的数字标识,它由两个部分组成:
🧩 1. 主设备号(Major Number)
表示这个设备属于哪一个驱动程序。
也就是说,哪个内核驱动模块来处理这个设备的请求。
🧩 2. 次设备号(Minor Number)
表示由同一个驱动程序管理的多个设备中的哪一个。
相当于:驱动负责整条生产线,次设备号表示哪个产品。
Linux 提供了一个名为 dev_t 的数据类型表示设备号,dev_t 定义在文件 include/linux/types.h 里面,定义
如下:
13 typedef u32 __kernel_dev_t;
......
16 typedef __kernel_dev_t dev_t;
可以看出 dev_t 是 u32 类型的,也就是 unsigned int,所以 dev_t 其实就是 unsigned int 类型,是一个 32 位的数据类型。这 32 位的数据构成了主设备号和次设备号两部分,其中高 12位为主设备号,低 20 位为次设备号。因此 Linux 系统中主设备号范围为 0~4095,所以大家在选择主设备号的时候一定不要超过这个范围。
在文件 include/linux/kdev_t.h 中提供了几个关于设备号的操作函数(本质是宏),如下所示:
7 #define MINORBITS 20
8 #define MINORMASK ((1U << MINORBITS) - 1)
9
10 #define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS))
11 #define MINOR(dev) ((unsigned int) ((dev) & MINORMASK))
12 #define MKDEV(ma,mi) (((ma) << MINORBITS) | (mi))
第 7 行,宏 MINORBITS 表示次设备号位数,一共是 20 位。
第 8 行,宏 MINORMASK 表示次设备号掩码。
第 10 行,宏 MAJOR 用于从 dev_t 中获取主设备号,将 dev_t 右移 20 位即可。
第 11 行,宏 MINOR 用于从 dev_t 中获取次设备号,取 dev_t 的低 20 位的值即可。
第 12 行,宏 MKDEV 用于将给定的主设备号和次设备号的值组合成 dev_t 类型的设备
号。
3.3.2 设备号的分配
设备号分配为:静态分配和动态分配
1、静态分配
cat /proc/devices 查看当前设备中使用的设备号如果没有被使用的设备号就能注册
2、动态分配
在注册字符设备之前先申请一个设备号,系统会自动给你一个没有被使用的设备号,这样就避免了冲突。卸载驱动的时候释放掉这个设备号即可,设备号的申请函数如下
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name)
函数 alloc_chrdev_region 用于申请设备号,此函数有 4 个参数:
dev:保存申请到的设备号。
baseminor:次设备号起始地址,alloc_chrdev_region 可以申请一段连续的多个设备号,这
些设备号的主设备号一样,但是次设备号不同,次设备号以 baseminor 为起始地址地址开始递
增。一般 baseminor 为 0,也就是说次设备号从 0 开始。
count:要申请的设备号数量。
name:设备名字。
注销字符设备之后要释放掉设备号,设备号释放函数如下:
void unregister_chrdev_region(dev_t from, unsigned count)
此函数有两个参数:
from:要释放的设备号。
count:表示从 from 开始,要释放的设备号数量。
3.4 chrdevbase 字符设备驱动开发实验
我们就以 chrdevbase 这个虚拟设备为
例,完整的编写一个字符设备驱动模块。chrdevbase 不是实际存在的一个设备,是为了方便讲解字符设备的开发而引入的一个虚拟设备。chrdevbase 设备有两个缓冲区,一个读缓冲区,一个写缓冲区,这两个缓冲区的大小都为 100 字节。在应用程序中可以向 chrdevbase 设备的写缓冲区中写入数据,从读缓冲区中读取数据。
驱动文件
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>#define CHRDEVBASE_MAJOR 200 /* 主设备号 */
#define CHRDEVBASE_NAME "chrdevbase" /* 设备名 */static char readbuf[100]; /* 读缓冲区 */
static char writebuf[100]; /* 写缓冲区 */
static char kerneldata[] = {"kernel data!"};/** @description : 打开设备* @param - inode : 传递给驱动的inode* @param - filp : 设备文件,file结构体有个叫做private_data的成员变量* 一般在open的时候将private_data指向设备结构体。* @return : 0 成功;其他 失败*/
static int chrdevbase_open(struct inode *inode, struct file *filp)
{//printk("chrdevbase open!\r\n");return 0;
}/** @description : 从设备读取数据 * @param - filp : 要打开的设备文件(文件描述符)* @param - buf : 返回给用户空间的数据缓冲区* @param - cnt : 要读取的数据长度* @param - offt : 相对于文件首地址的偏移* @return : 读取的字节数,如果为负值,表示读取失败*/
static ssize_t chrdevbase_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{int retvalue = 0;/* 向用户空间发送数据 */memcpy(readbuf, kerneldata, sizeof(kerneldata));retvalue = copy_to_user(buf, readbuf, cnt);if(retvalue == 0){printk("kernel senddata ok!\r\n");}else{printk("kernel senddata failed!\r\n");}//printk("chrdevbase read!\r\n");return 0;
}/** @description : 向设备写数据 * @param - filp : 设备文件,表示打开的文件描述符* @param - buf : 要写给设备写入的数据* @param - cnt : 要写入的数据长度* @param - offt : 相对于文件首地址的偏移* @return : 写入的字节数,如果为负值,表示写入失败*/
static ssize_t chrdevbase_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{int retvalue = 0;/* 接收用户空间传递给内核的数据并且打印出来 */retvalue = copy_from_user(writebuf, buf, cnt);if(retvalue == 0){printk("kernel recevdata:%s\r\n", writebuf);}else{printk("kernel recevdata failed!\r\n");}//printk("chrdevbase write!\r\n");return 0;
}/** @description : 关闭/释放设备* @param - filp : 要关闭的设备文件(文件描述符)* @return : 0 成功;其他 失败*/
static int chrdevbase_release(struct inode *inode, struct file *filp)
{//printk("chrdevbase release!\r\n");return 0;
}/** 设备操作函数结构体*/
static struct file_operations chrdevbase_fops = {.owner = THIS_MODULE, .open = chrdevbase_open,.read = chrdevbase_read,.write = chrdevbase_write,.release = chrdevbase_release,
};/** @description : 驱动入口函数 * @param : 无* @return : 0 成功;其他 失败*/
static int __init chrdevbase_init(void)
{int retvalue = 0;/* 注册字符设备驱动 */retvalue = register_chrdev(CHRDEVBASE_MAJOR, CHRDEVBASE_NAME, &chrdevbase_fops);if(retvalue < 0){printk("chrdevbase driver register failed\r\n");}printk("chrdevbase init!\r\n");return 0;
}/** @description : 驱动出口函数* @param : 无* @return : 无*/
static void __exit chrdevbase_exit(void)
{/* 注销字符设备驱动 */unregister_chrdev(CHRDEVBASE_MAJOR, CHRDEVBASE_NAME);printk("chrdevbase exit!\r\n");
}/* * 将上面两个函数指定为驱动的入口和出口函数 */
module_init(chrdevbase_init);
module_exit(chrdevbase_exit);/* * LICENSE和作者信息*/
MODULE_LICENSE("GPL");
MODULE_AUTHOR("123");
MODULE_INFO(intree, "Y");
驱动程序书写流程:
1、写入口函数 出口函数
module_init(chrdevbase_init);
module_exit(chrdevbase_exit);
2、实现入口函数出口函数
入口函数中注册字符设备
出口函数注销字符设备
static int __init chrdevbase_init(void)
{int retvalue = 0;/* 注册字符设备驱动 */retvalue = register_chrdev(CHRDEVBASE_MAJOR, CHRDEVBASE_NAME, &chrdevbase_fops);if(retvalue < 0){printk("chrdevbase driver register failed\r\n");}printk("chrdevbase init!\r\n");return 0;
}/** @description : 驱动出口函数* @param : 无* @return : 无*/
static void __exit chrdevbase_exit(void)
{/* 注销字符设备驱动 */unregister_chrdev(CHRDEVBASE_MAJOR, CHRDEVBASE_NAME);printk("chrdevbase exit!\r\n");
}
3、实现file_operations 结构体 和open read write release函数
/** @description : 打开设备* @param - inode : 传递给驱动的inode* @param - filp : 设备文件,file结构体有个叫做private_data的成员变量* 一般在open的时候将private_data指向设备结构体。* @return : 0 成功;其他 失败*/
static int chrdevbase_open(struct inode *inode, struct file *filp)
{//printk("chrdevbase open!\r\n");return 0;
}/** @description : 从设备读取数据 * @param - filp : 要打开的设备文件(文件描述符)* @param - buf : 返回给用户空间的数据缓冲区* @param - cnt : 要读取的数据长度* @param - offt : 相对于文件首地址的偏移* @return : 读取的字节数,如果为负值,表示读取失败*/
static ssize_t chrdevbase_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{int retvalue = 0;/* 向用户空间发送数据 */memcpy(readbuf, kerneldata, sizeof(kerneldata));retvalue = copy_to_user(buf, readbuf, cnt);if(retvalue == 0){printk("kernel senddata ok!\r\n");}else{printk("kernel senddata failed!\r\n");}//printk("chrdevbase read!\r\n");return 0;
}/** @description : 向设备写数据 * @param - filp : 设备文件,表示打开的文件描述符* @param - buf : 要写给设备写入的数据* @param - cnt : 要写入的数据长度* @param - offt : 相对于文件首地址的偏移* @return : 写入的字节数,如果为负值,表示写入失败*/
static ssize_t chrdevbase_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{int retvalue = 0;/* 接收用户空间传递给内核的数据并且打印出来 */retvalue = copy_from_user(writebuf, buf, cnt);if(retvalue == 0){printk("kernel recevdata:%s\r\n", writebuf);}else{printk("kernel recevdata failed!\r\n");}//printk("chrdevbase write!\r\n");return 0;
}/** @description : 关闭/释放设备* @param - filp : 要关闭的设备文件(文件描述符)* @return : 0 成功;其他 失败*/
static int chrdevbase_release(struct inode *inode, struct file *filp)
{//printk("chrdevbase release!\r\n");return 0;
}/** 设备操作函数结构体*/
static struct file_operations chrdevbase_fops = {.owner = THIS_MODULE, .open = chrdevbase_open,.read = chrdevbase_read,.write = chrdevbase_write,.release = chrdevbase_release,
};
APP文件
#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "fcntl.h"
#include "stdlib.h"
#include "string.h"static char usrdata[] = {"usr data!"};/** @description : main主程序* @param - argc : argv数组元素个数* @param - argv : 具体参数* @return : 0 成功;其他 失败*/
int main(int argc, char *argv[])
{int fd, retvalue;char *filename;char readbuf[100], writebuf[100];if(argc != 3){printf("Error Usage!\r\n");return -1;}filename = argv[1];/* 打开驱动文件 */fd = open(filename, O_RDWR);if(fd < 0){printf("Can't open file %s\r\n", filename);return -1;}if(atoi(argv[2]) == 1){ /* 从驱动文件读取数据 */retvalue = read(fd, readbuf, 50);if(retvalue < 0){printf("read file %s failed!\r\n", filename);}else{/* 读取成功,打印出读取成功的数据 */printf("read data:%s\r\n",readbuf);}}if(atoi(argv[2]) == 2){/* 向设备驱动写数据 */memcpy(writebuf, usrdata, sizeof(usrdata));retvalue = write(fd, writebuf, 50);if(retvalue < 0){printf("write file %s failed!\r\n", filename);}}/* 关闭设备 */retvalue = close(fd);if(retvalue < 0){printf("Can't close file %s\r\n", filename);return -1;}return 0;
}
Makefile
KERNELDIR := /home/lk/rk3588_linux_sdk/kernel
CURRENT_PATH := $(shell pwd)
# obj-m 是内核模块编译规则中的一个特殊变量。
# obj-m 定义了要生成的模块目标文件(即 .ko 文件)。
# obj-m 表示编译时将 chrdevbase.o 作为模块(module)对象,最终会生成 chrdevbase.ko。
# chrdevbase.o# chrdevbase.o 是将 chrdevbase.c 文件编译为目标文件(.o 文件)的名称。
# 生成的目标文件会自动链接成内核模块 chrdevbase.ko。
obj-m := chrdevbase.o
# make 会首先检查 kernel_modules 目标。
# 如果 kernel_modules 目标没有生成或需要更新,make 会执行 kernel_modules 的命令。
# 执行完 kernel_modules 后,build 目标就算完成了。
build : kernel_modules# kernel_modules# 定义一个名为 kernel_modules 的目标。
# 当执行 make kernel_modules 时,会触发后面的命令。# $(MAKE)# $(MAKE) 是一个特殊的变量,表示 make 命令本身。
# 使用 $(MAKE) 而不是直接调用 make 可以在嵌套调用时保持参数一致性。
# -C $(KERNELDIR)# -C 选项表示切换到 $(KERNELDIR) 目录下执行命令。
# $(KERNELDIR) 是一个变量,通常指定为 Linux 内核源码的构建目录。
# 在内核源码目录中调用 make 会使用内核的构建系统。
# M=$(CURRENT_PATH)# M= 选项告诉内核构建系统,当前模块的源代码位于 $(CURRENT_PATH) 目录下。
# modules# modules 是内核构建系统的一个目标,表示要构建模块(.ko 文件)。
# 当传入 modules 目标时,内核会根据 obj-m 定义的模块进行编译。
# 总结 使用make buil 就会检查kernel_modules是否存在或者更新 ,kernel_modules会执行$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules
#也就是 make 内核路径 当前文件路径 生成modules即obj-m 对应的 chrdevbase.o生成chrdevbase.ko文件
kernel_modules :$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules
clean:$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean
Makefile 用法 根据配置
KERNELDIR := /home/lk/rk3588_linux_sdk/kernel
CURRENT_PATH := $(shell pwd)
obj-m := chrdevbase.o
运行build 然后运行kernel_modules 后的
其中:= 是简单赋值 :是目标依赖
M= 是 Make 运行参数,不是 Makefile 自身定义变量的语法
-C:切换目录到内核源码目录
modules:告诉它“我要构建模块”
相关文章:
rk3588 驱动开发(一)字符设备开发
3.字符设备驱动开发 3.1 什么是字符设备驱动 字符设备:就是一个个字节,按照字节流进行读写操作的设备,读写是按照先后顺序的。 举例子:IIC 按键 LED SPI LCD 等 Linux 应用程序调用驱动程序流程: Linux中驱动加载成功…...
【第45节】windows程序的其他反调试手段上篇
目录 引言 一、通过窗口类名和窗口名判断 二、检测调试器进程 三、父进程是否是Explorer 四、RDTSC/GetTickCount时间敏感程序段 五、StartupInfo结构的使用 六、使用BeingDebugged字段 七、 PEB.NtGlobalFlag,Heap.HeapFlags,Heap.ForceFlags 八、DebugPort:CheckRem…...
通过人类和机器人演示进行联合逆向和正向动力学的机器人训练
25年3月来自哥伦比亚大学的论文“Train Robots in a JIF: Joint Inverse and Forward Dynamics with Human and Robot Demonstrations”。 在大型机器人演示数据集上进行预训练是学习各种操作技能的强大技术,但通常受到收集以机器人为中心数据的高成本和复杂性限制…...
云渗透三(对象存储攻防)
对象存储是什么? 对象存储(Cloud Object Storage,COS)是腾讯云提供的⼀种存储海量⽂件的分布式存储服务,⽤户可通过⽹络随时存储和查看数据。腾讯云 COS 使所有⽤户都能使⽤具备⾼扩展性、低成本、可靠和安全的数据存储服务。 COS 通过控制台、API、SDK 和⼯具等多样化⽅…...
ShenNiusModularity项目源码学习(17:ShenNius.Admin.Mvc项目分析-2)
ShenNiusModularity项目的后台管理主页面如下图所示,该页面为ShenNius.Admin.Mvc项目的Views\Home\Index.cshtml,使用的是layuimini后台模板(参考文献2),在layuimini的GitHub主页中提供有不同样式的页面模版链接&#…...
Sentinel源码—2.Context和处理链的初始化一
大纲 1.Sentinel底层的核心概念 2.Sentinel中Context的设计思想与源码实现 3.Java SPI机制的引入 4.Java SPI机制在Sentinel处理链中的应用 5.Sentinel默认处理链ProcessorSlot的构建 1.Sentinel底层的核心概念 (1)资源和规则 (2)Context (3)ProcessorSlot (4)Node (1…...
嵌入式C语言高级编程:OOP封装、TDD测试与防御性编程实践
一、面向对象编程(OOP) 尽管 C 语言并非面向对象编程语言,但借助一些编程技巧,也能实现面向对象编程(OOP)的核心特性,如封装、继承和多态。 1.1 封装 封装是把数据和操作数据的函数捆绑在一起,对外部隐藏…...
C++中unique_lock和lock_guard区别
目录 1.自动锁定与解锁机制 2.灵活性 3.所有权转移 4.可与条件变量配合使用 5.性能开销 在 C 中,std::unique_lock 和 std::lock_guard 都属于标准库 <mutex> 中的互斥锁管理工具,用于简化互斥锁的使用并确保线程安全。但它们存在一些显著区别…...
C# 使用.NET内置的 IObservable<T> 和 IObserver<T>-观察者模式
核心概念 IObservable<T> 表示 可观察的数据源(如事件流、实时数据)。 关键方法:Subscribe(IObserver<T> observer),用于注册观察者。 IObserver<T> 表示 数据的接收者,响应数据变化。 三个核心…...
多模态大模型文字识别 vs OCR识别模型
论文简述 多模态大语言模型(Multimodal Large Language Models,简称多模态LLMs)具有高度通用性,能够处理图像描述、文档分析和自动化内容生成等多种任务。这种广泛的适用性使其在不同工业领域都受到了大量关注。 在OCR方面,多模态LLMs的表现超过了专门为OCR设计的模型。这…...
[区块链] 持久化运行区块链 | 并通过HTTP访问
实验目标 以Web服务的形式持久化运行区块链,并通过HTTP接口的形式实现对区块链的操作。 实验内容 构建区块链的区块对象和区块链对象。使用Flask等Web服务框架运行持久化的进程,实现基于HTTP接口实现新区块的添加功能以及传递区块索引查询区块链中的区…...
批量将不同位置的多个文件复制到一个文件夹
在日常工作中,我们常常需要将多个位置的文件集中到一个文件夹中。手动一个个复制文件既费时又容易出错。使用批量文件复制工具,您可以轻松将不同位置的多个文件快速复制到一个文件夹中,大大提高工作效率。 今天给大家介绍一下批量将不同位置的…...
CentOS 下 Zookeeper 常用命令与完整命令列表
一、服务管理命令 常用服务命令 启动 Zookeeper 服务: systemctl start zookeeper # 使用 systemd (推荐) /usr/local/zookeeper/bin/zkServer.sh start # 直接启动 停止服务: systemctl stop zookeeper /usr/local/zookeeper/bin/zkServer.sh stop 查看服务状态…...
React与Vue:哪个框架更适合入门?
React与Vue:选择哪个框架入门? 一、框架定位与发展趋势 1.1 技术背景对比 React:Meta(原Facebook)2013年推出,采用声明式编程范式,专注构建用户界面Vue:尤雨溪2014年推出…...
突发!GitHub 被曝封禁中国区 IP
昨天,大量国内开发者发现,未登录状态下访问GitHub官网时,页面显示“Access to this site has been restricted.”,中国大陆及香港IP均被限制。尽管GitHub官方尚未发布声明,但多方实测显示: 猪哥亲测在已登…...
向量数据库Qdrant 安装 不使用docker
一、导读 环境:Ubuntu 24.04、Windows 10、WSL 2、Qdrant 1.13.4 背景:换了新工作,使用qdrant作为向量库,需要不使用docker安装 时间:20250415 说明:初入职,不了解,暂且记下 二、…...
基于坐标的神经表示实现零样本学习以用于快速三维多参数定量磁共振成像|文献速递-深度学习医疗AI最新文献
Title 题目 Coordinate-based neural representation enabling zero-shot learning for fast 3D multiparametric quantitative MRI 基于坐标的神经表示实现零样本学习以用于快速三维多参数定量磁共振成像 01 文献速递介绍 定量磁共振成像(qMRI)能…...
每日算法-250415
每日算法 - 2024-04-15: 今天我们来解决两道 LeetCode 上关于在旋转排序数组中寻找最小值的问题。 153. 寻找旋转排序数组中的最小值 题目描述 思路 核心思想是利用 二分查找。 解题过程 一个升序排序的数组(无重复元素)在经过若干次旋转后…...
第16届蓝桥杯省赛JavaB组真题回顾
第16届蓝桥杯省赛已经结束了,第一次参加也是坐牢了4个小时,现在还是来总结一下吧(先声明以下的解法,大家可以当作一种思路来看,解法不一定是正解,只是给大家提供一种能够正常想到的思路吧) 试题…...
[Godot] C#人物移动抖动解决方案
在写一个2D平台跳跃的游戏代码发现,移动的时候会抖动卡顿的厉害,后来研究了一下抖动问题,有了几种解决方案 1.垂直同步和物理插值问题 这是最常见的可能导致画面撕裂和抖动的原因,大家可以根据自己的需要调整项目设置࿰…...
hackmyvm-quick2
收集信息 arp-scan -l nmap 192.168.66.74 dirsearch -u http://192.168.66.74 -e * 访问file.php 尝试查看/etc/passwd 抓包 payload: /file.php?file=/home/andrew/.bashrc /file.php?file=/home/nick/.bashrc...
TDengine 与其他时序数据库对比:InfluxDB/TimescaleDB 选型指南(一)
引言 在当今数字化时代,物联网(IoT)、工业互联网等领域蓬勃发展,产生了海量的时序数据。这些数据记录了设备状态、传感器读数、业务指标等随时间变化的信息,对于企业的运营监控、数据分析和决策制定起着关键作用。为了…...
Jetson agx Orin 适配Xenomai4
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 目录 文章目录 前言 一、Xenomai 4 二、使用步骤 1.获取源码 2.编译源码 3、安装 4、运行效果 5、libevl 总结 前言 例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了…...
Terraform - 理解 Count 和 For_Each 循环
概述 使用 Terraform 时,您可能需要为同一资源创建多个实例。这时 count 和 for_each 循环就派上用场了。这些循环允许您创建具有相同配置但具有不同值的多个资源。本指南将讲解如何在 Terraform 中使用 count 和 for_each 循环。 Terraform 中的 Count Terraform …...
Git本地更新和远端同步操作
1、将远端文件夹拉取到本地 从0—1:克隆 在文件夹空白处点击:Git克隆 输入url,克隆到本地 输入远端文件地址,点击确定,远端文件即可克隆到本地 2、拉取远端更新到本地 文件克隆到本地后,每次更新需…...
激活函数Softmax在不同维度上的应用 | dim参数理解
理解 Softmax 在不同维度上的应用,关键在于明确 Softmax 的作用以及 dim 参数的意义。Softmax 的目标是将输入张量的某些元素转换为概率分布,使得这些元素的和为1。dim 参数决定了沿着哪个维度进行归一化操作。 1. Softmax 的基本原理 Softmax 函数的公…...
地理人工智能中位置编码的综述:方法与应用
以下是对论文 《A Review of Location Encoding for GeoAI: Methods and Applications》 的大纲和摘要整理: A Review of Location Encoding for GeoAI: Methods and Applications 摘要(Summary) 本文系统综述了地理人工智能(G…...
6.DJI-PSDK:psdk订阅无人机高度/速度/GPS/RTK/时间/经纬度等消息及问题解决
DJI-PSDK:psdk订阅无人机高度/速度/GPS/RTK/时间/经纬度等消息 消息订阅可以获取绝大多数无人机的动态信息,包括无人机的姿态、速度、加速度、角速度、高度、GPS 位置、云 台的角度和状态、飞行模式和飞行状态、电机和电池等各类关键信息。 这些信息并不会“一股脑儿地”全部…...
ArrayList的subList的数据仍是集合
ArrayList的subList结果不可强转成ArrayList,否则会抛出 ClassCastException异常 • 级别: 【CRITICAL】 • 规约类型:BUG • 最坏影响: 程序错误,抛出异常 说明:subList 返回的是ArrayList的内部类SubL…...
VS Code怎么换颜色
在 VS Code 中,你可以通过修改主题或自定义编辑器颜色来将界面改为白色。以下是几种方法: 方法 1:切换浅色主题(推荐) VS Code 自带多个浅色主题,可以直接切换: 按快捷键 Ctrl K,…...
jupyter中切换Anaconda虚拟环境
jupyter中切换虚拟环境 查看python路径 import sys sys.executable这个命令会输出当前 Notebook 使用的 Python 可执行文件的路径 2. 查看安装的包和环境信息(前两步都在jupyter notebook中进行) !which python !python --version !pip list将你的虚拟…...
红帽认证 Linux安全 级别
红帽认证体系将安全能力划分为专项技能认证与架构师路径,覆盖从基础加固到企业级安全架构设计。以下是安全相关认证的级别、核心内容及职业定位: 一、红帽安全认证分级与定位 认证名称级别考试代码核心方向考试难度适用人群Red Hat Certif…...
从服务器多线程批量下载文件到本地
1、客户端安装 aria2 下载地址:aria2 解压文件,然后将文件目录添加到系统环境变量Path中,然后打开cmd,输入:aria2c 文件地址,就可以下载文件了 2、服务端配置nginx文件服务器 server {listen 8080…...
WPF 中的元素继承层次结构 ,以下是对图中内容的详细说明:
顶层基类 DispatcherObject:处于继承体系最顶端,是一个抽象类。它为 WPF 元素提供了与 Dispatcher(调度器)交互的能力,Dispatcher 负责管理线程间的消息传递,确保 UI 操作在正确的线程(通常是 …...
ROS IkFast运动学插件
ikFast运动学插件生成 环境安装ROS依赖安装openrave依赖下载依赖代码工具使用urdf转dae设置精度查看模型关节生成代码生成插件 环境 ubuntu 20.04ROS版本:noetic 安装ROS依赖 sudo apt-get install -y ros-noetic-desktop ros-noetic-collada-urdf ros-noetic-mov…...
Flink Hive Catalog最佳实践
Flink Hive Catalog 最佳实践 一、配置与初始化 依赖管理 Hive Connector 版本对齐:需确保 flink-sql-connector-hive 版本与 Hive 版本严格匹配(如 Hive 3.1.3 对应 flink-sql-connector-hive-3.1.3_2.12),同时添加 Hadoop 遮蔽…...
接口测试之postman使用指南
一、为何使用postman postman是一款简单高效的接口测试工具,能够很方便发送接口请求,易于保存接口请求脚本,postman提供接口响应数据比对功能,可以设置预期结果作断言,还能把测试用例放在一个集合中批量执行ÿ…...
小豆包api:支持GPT-4.1全新系列模型api,纯官逆向可用!
今天凌晨,OpenAI正式发布GPT-4.1系列模型,带来标准版GPT-4.1,更轻量快速GPT-4.1 mini和极致性价比的GPT-4.1 nano三款模型,全面超越GPT-4o,更聪明、更便宜。 小豆包api已全面支持GPT-4.1全新系列模型! 与前…...
GPTNet如何革新创意与效率
引言 人工智能正在以前所未有的速度改变我们的工作与生活方式,从智能写作到视觉创作,AI工具已成为不可或缺的伙伴。在众多平台中,GPTNet以其强大的功能整合和直观体验崭露头角。它不仅汇集了GPT系列、Claude、Grok、Gemini等顶级对话模型&am…...
3.3.6 VO-O语法- 流程算子
流程算子是VO语言最重要的一类语法算子。它们是VO语言特有的语法概念。这些算子属于容器算子,用于组织管理各类流程。这样的设计有利于流程的复用。可以将流程视为一个大级别的函数模块,在更大的业务逻辑中复用,从而降低业务开发的复杂度&…...
c++引入nacos,详细步骤
以下是将Nacos引入C项目的详细步骤,包括安装、配置和代码实现: 1. 安装Nacos服务器 下载Nacos服务器安装包,可以从Nacos官网获取最新版本。 解压安装包并启动Nacos服务器: cd nacos/bin sh startup.sh -m standalone 这将启动…...
OpenAI 最新发布的 GPT-4.1 系列在 API 中正式上线
每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领…...
亚远景-自动驾驶时代,ASPICE评估标准将如何演进?
自动驾驶时代,ASPICE评估标准将从以下几个方面演进: 1. 技术领域的扩展 增加硬件工程和机器学习过程组 :ASPICE 4.0版本新增了硬件工程和机器学习过程组,以应对自动驾驶系统中硬件与软件深度融合的需求。自动驾驶功能的实现不仅依…...
Redis 数据类型全解析:从基础到实战应用
精心整理了最新的面试资料和简历模板,有需要的可以自行获取 点击前往百度网盘获取 点击前往夸克网盘获取 Redis 作为高性能的键值对存储系统,其丰富的数据类型是实现复杂业务逻辑的核心优势。本文将深入解析 Redis 六大核心数据类型及扩展类型ÿ…...
基于JSP+MySQL实现用户注册登录及短信发送功能
用户注册信息存入数据库 内容介绍 此项目是前台用户的登录和注册,,这部分包括两个子部分:其中一个为新用户注册,在这里我们可以通过注册浏览更多信息;另一个是用户登录,用户登录系统是一.般 Web 网站都有的子系统,其作用是限制该网站某些资…...
Spark-SQL核心编程2
路径问题 相对路径与绝对路径:建议使用绝对路径,避免复制粘贴导致的错误,必要时将斜杠改为双反斜杠。 数据处理与展示 SQL 风格语法:创建临时视图并使用 SQL 风格语法查询数据。 DSL 风格语法:使用 DSL 风格语法查询…...
Flink SQL SavePoint最佳实践
以下是 Flink SQL Savepoint 最佳实践,涵盖配置、触发、恢复及注意事项,高效管理作业状态: 一、Savepoint 的配置与触发 1. 基础配置 存储路径:在 flink-conf.yaml 中全局设置 Savepoint 存储目录,避免每次手动指定路…...
【无标题】Spark-SQL编程(2)
以下是今天学习的知识点以及代码测试: Spark-SQL核心编程(四) 实验内容: 利用IDEA开发Spark-SQL。 实验步骤: 利用IDEA开发Spark-SQL 创建子模块Spark-SQL,并添加依赖 <dependency> <grou…...
django项目之添加资产信息功能
资产信息功能添加 目录 1.创建表格 2.页面展示 3.新增和修改 4.删除 这篇文章的内容, 就是在前面做的基础上, 新增一个资产管理功能, 其实就和之前的部门信息还有员工信息差不多的, 但是这篇文章里面, 会有些细节的地方, 和之前的不太一样。那下面我们就开始讲述这篇文章…...
macos下 ~/.zshrc~ 和 ~/.zshrc
macos下 ~/.zshrc~ 和 ~/.zshrc ~/.zshrc通常是备份文件或临时文件,可能由编辑器(如vim)创建,通常可以安全删除,不会影响系统运行。 在Mac下,这种带~后缀的备份文件通常是由以下情况产生: 常…...