Linux第73步_学习Linux设备树和“OF函数”

掌握设备树是 Linux驱动开发人员必备的技能

1、了解设备树文件

在3.x版本以前的Linux内核源码中,存在大量的“arc/arm/mach-xxx”和“arc/arm/plat-xxx”文件夹,里面很多个“.c”和“.h”文件,它们用来描述设备信息。而现在的ARM架构是采用“设备树”来描述设备信息。“设备树”英文名字叫“Device Tree”。描述设备树的文件叫做“DTS”,是Device Tree Source的缩写。它主要用来描述板子上有哪些设备构成,如:I2C控制器、GPIO控制器、SPI控制器、UART控制器等。

设备树源文件扩展名为“.dts”,设备树头文件扩展名为“.dtsi”,它们经过DTC工具编译后生成的二进制文件,就是“.dtb”文件。

“.dts”设备树文件可以通过“#include”来引用“.h”、“.dtsi”和“.dts”文件。在编写设备树头文件时,我们最好选择“.dtsi”作为后缀。

一般“.dtsi”文件用于描述芯片的“内部外设信息”,比如CPU架构、主频、外设寄存器地址范围,如:UART、IIC、SPI、TIMER等等。

2、了解节点

设备树是描述板子上的“设备信息”的文件,均采用“树形结构”。每个设备树文件只有一个“根节点”,而“不同设备树文件的根节点”会合在一起形成一个根节点。每个设备都是一个节点,称之为“设备节点”,每个节点都采用“属性信息”来描述其“节点信息”。

认识“标准属性”、“节点”和“节点标签”,见下图:

标准属性

1)、compatiable属性,也叫兼容性属性。

如:compatible = "cirrus,cs42l51";

这个compatible只有一个属性值,就是“cirrus,cs42l51”,其中“cirrus”表示厂商,“cs42l51”表示驱动模块。

再如:compatible = "cirrus,cs42l51","cirrus,My_cs42l51";

这个compatible就有两个属性值,就是“cirrus,cs42l51”和"cirrus,My_cs42l51",其中“cirrus”表示厂商,“cs42l51”表示驱动模块,“My_cs42l51”表示驱动模块。

驱动文件的“OF匹配表”

const struct of_device_id cs42l51_of_match[] = { { .compatible = "cirrus,cs42l51", },{ }};

设备首先会使用第一个兼容值在Limux内核里面查找。看看能不能找到与之匹配的驱动文件,如果没有找到,就使用第二个兼容值查,以此类推,直到查找完 commpatible属性中的所有值。

compatible属性用于将设备和驱动绑定起来。驱动程序文件有一个“OF匹配表”,这个“OF匹配表”保存着一些compatible的值,如果设备节点的compatible属性值和“OF匹配表”中的任何一个值相等,那么这个设备就可以使用这个驱动。

2)、model属性

用于描述开发板的名字或设备模块的信息。

比如:model = "STMicroelectronics STM32MP157C-DK2 Discovery Board";

3)、status属性

status属性值

描述

okay

表明设备是可操作的

disabled

表明设备当前是不可操作的,但是在未来可以变为可操作的,比如:热插拔设备插入以后。至于disabled的具体含义还要看设备的绑定文档。

fail

表明设备不可操作,设备检测到了一系列的错误,而且设备也不大可能变得可操作。

fail-sss

含义和“fai1”相同,后面的“sss部分”是检测到的错误内容。

4)、reg属性

reg属性的值一般是(address,length)对。

reg 属性一般用于描述“设备地址空间资源信息”或者“设备地址信息”,比如某个外设的“寄存器地址范围信息”,或者I2C器件的设备地址等。

5)、ranges属性

ranges = <child-bus-address,parent-bus-address,length>;

child-bus-address表示“子总线地址空间的物理地址”;

parent-bus-address表示“父总线地址空间的物理地址”;

length表示“子总线地址空间的长度”;

若ranges属性值为空,则说明子地址空间和父地址空间完全相同;

6)、“#address-cells”和“#size-cells”属性

#address-cells的属性值为无符号32位整型,用于描述子节点的“reg和ranges”中的address所占的位数,1表示32位,2表示64位;

#size-cells的属性值为无符号32位整型,用于描述子节点的“reg和ranges”中的length所占的位数,0表示没有位数,1表示32位,2表示64位;

举例说明“reg、 #address-cells和#size-cells”属性:

cpus {   #address-cells = <1>;//表示子节点cpureg和rangesaddress占32个位

   #size-cells = <0>;   //表示子节点cpureg和rangeslength占0个位   cpu0: cpu@0 {      compatible = "arm,cortex-a7";      device_type = "cpu";      reg = <0>;        //表示addres=0, 没有length,和前面定义一致

      clocks = <&scmi0_clk CK_SCMI0_MPU>;      clock-names = "cpu";      operating-points-v2 = <&cpu0_opp_table>;      nvmem-cells = <&part_number_otp>;       nvmem-cell-names = "part_number";       #cooling-cells = <2>;    }; };

scmi_sram: sram@2ffff000 {   compatible = "mmio-sram";   reg = <0x2ffff000 0x1000>//表示address=0x2ffff000,length=0x1000

   #address-cells = <1>;//表示scmi_shmreg和rangesaddress占32个位

   #size-cells = <1>;   //表示scmi_shmreg和rangeslength占32个位

   ranges = <0 0x2ffff000 0x1000>;  //分别为32位,和前面定义一致

   scmi0_shm: scmi_shm@0 {      reg = <0 0x80>;    //reg的address和length分别为32位,和前面定义一致

   };

};

soc {

   compatible = "simple-bus";   #address-cells = <1>; //表示sramreg和rangesaddres长度为32个位   #size-cells = <1>;    //表示sramreg和rangeslength长度为32个位

   interrupt-parent = <&intc>;   ranges = <0 0x10000000 0x100000>;

   sram: sram@10000000 {      compatible = "mmio-sram";      reg = <0x0 0x60000>;//reg的address和length均为32位,和前面定义一致

      #address-cells = <1>;      #size-cells = <1>;      ranges = <0 0x10000000 0x60000>;  //均为32位,和前面定义一致

   };};

以STM32MP157为例,创建设备树文件myfrst.dts ,要求在设备树里面的内容如下:

1)、芯片是由两个Cortex-A7 架构的32位CPU和Cortex-M4组成。

2)、STM32MP157内部sram,起始地址为 0x10000000,大小为384KB(0x60000)。

先搭建 “根节点框架”,如下:

/{   compatible = "st,stm32mp157d-atk", "st,stm32mp157"; };

接着添加cpus节点,如下:

/{   compatible = "st,stm32mp157d-atk", "st,stm32mp157";   cpus{

     #address-cells = <1>;//表示子节点cpureg和rangesaddress占32个位

     #size-cells = <0>;   //表示子节点cpureg和rangeslength占0个位

   };

 };

接着添加cpu0节点,如下:

/{   compatible = "st,stm32mp157d-atk", "st,stm32mp157";   cpus{

     #address-cells = <1>;//表示子节点cpureg和rangesaddress占32个位

     #size-cells = <0>;   //表示子节点cpureg和rangeslength占0个位

      cpu0: cpu@0 {        compatible = "arm,cortex-a7";        device_type = "cpu";        reg = <0>;        //表示addres=0, 没有length,和前面定义一致

     };

   };

 };

接着添加cpu1节点,如下:

/{   compatible = "st,stm32mp157d-atk", "st,stm32mp157";   cpus{

     #address-cells = <1>;//表示子节点cpu的reg和ranges的address占32个位

     #size-cells = <0>;   //表示子节点cpureg和rangeslength占0个位

      cpu0: cpu@0 {        compatible = "arm,cortex-a7";        device_type = "cpu";        reg = <0>;        //表示addres=0, 没有length,和前面定义一致

     };

      cpu1: cpu@1 {        compatible = "arm,cortex-m4";        device_type = "cpu";        reg = <1>;        //表示addres=1, 没有length,和前面定义一致

     };

   };

 };

接着添加soc节点,如下:

/{   compatible = "st,stm32mp157d-atk", "st,stm32mp157";   cpus{

     #address-cells = <1>;//表示子节点cpureg和rangesaddress占32个位

     #size-cells = <0>;   //表示子节点cpureg和rangeslength占0个位

      cpu0: cpu@0 {        compatible = "arm,cortex-a7";        device_type = "cpu";        reg = <0>;        //表示addres=0, 没有length,和前面定义一致

     };

      cpu1: cpu@1 {        compatible = "arm,cortex-m4";        device_type = "cpu";        reg = <1>;        //表示addres=1, 没有length,和前面定义一致

     };

   };

   soc {

      compatible = "simple-bus";      #address-cells = <1>; //表示sramreg和rangesaddres长度为32个位      #size-cells = <1>;    //表示sramreg和rangeslength长度为32个位

      ranges; //说明子地址空间和父地址空间完全相同;

   };

 };

接着添加sram节点,如下:

/{   compatible = "st,stm32mp157d-atk", "st,stm32mp157";   cpus{

     #address-cells = <1>;//表示子节点cpureg和rangesaddress占32个位

     #size-cells = <0>;   //表示子节点cpureg和rangeslength占0个位

      cpu0: cpu@0 {        compatible = "arm,cortex-a7";        device_type = "cpu";        reg = <0>;        //表示addres=0, 没有length,和前面定义一致

     };

      cpu1: cpu@1 {        compatible = "arm,cortex-m4";        device_type = "cpu";        reg = <1>;        //表示addres=1, 没有length,和前面定义一致

     };

   };

   soc {

      compatible = "simple-bus";      #address-cells = <1>; //表示sramreg和rangesaddres长度为32个位      #size-cells = <1>;    //表示sramreg和rangeslength长度为32个位

      ranges; //说明子地址空间和父地址空间完全相同;

      

      sram: sram@10000000 {        compatible = "mmio-sram";        reg = <0x0 0x60000>;//address和length均为32位,和前面定义一致

        ranges = <0 0x10000000 0x60000>;  //均为32位,和前面定义一致

     };

   };

 };

3、了解特殊节点

1)、aliases子节点

aliases {

   serial0 = &uart4;  //给&uart4起个别名叫“serial0”

};

2)、chosen子节点

chosen不是一个真实的设备,chosen节点主要是为了uboot向 Linux内核传递数据。

chosen {

   stdout-path = "serial0:115200n8";

//设置“stdout-path”属性,表示标准输出使用“serial0

};

4、学习“OF函数”

“OF函数原型”都定义在“include/linux/of.h”文件中。

1)、了解相关结构体

Linux内核使用device_node结构体来描述一个节点。

struct device_node {

const char *name;  /*节点名字*/

phandle phandle;

const char *full_name;  /*节点全名*/

struct fwnode_handle fwnode;

struct property *properties; /*属性*/

struct property *deadprops; /* removed properties */

struct device_node *parent; /*父节点*/

struct device_node *child;  /*子节点*/

struct device_node *sibling;

#if defined(CONFIG_OF_KOBJ)

struct kobject kobj;

#endif

unsigned long _flags;

void *data;

#if defined(CONFIG_SPARC)

unsigned int unique_id;

struct of_irq_controller *irq_trans;

#endif

};

Linux内核中使用结构体property表示属性

struct property {

char *name;           /*属性名字*/

int length;              /*属性长度*/

void *value;          /*属性值*/

struct property *next;  /*下一个属性*/

#if defined(CONFIG_OF_DYNAMIC) || defined(CONFIG_SPARC)

unsigned long _flags;

#endif

#if defined(CONFIG_OF_PROMTREE)

unsigned int unique_id;

#endif

#if defined(CONFIG_OF_KOBJ)

struct bin_attribute attr;

#endif

}

resource结构体定义在文件 include/linux/ioport.h中。

struct resource {

resource_size_t start;   /*开始地址,占32位*/

resource_size_t end;     /*结束地址,占32位*/

const char *name;        /*资源的名字*/

unsigned long flags;     /*资源标志或资源类型*/

unsigned long desc;

struct resource *parent, *sibling, *child;

};

2)、通过节点的名字查找指定的节点:

struct device_node *of_find_node_by_name(struct device_node *from, const char *name)

from:开始查找的节点,如果为NULL,表示从根节点开始查找整个设备树。
name:要查找的节点名字。
返回值:返回找到的节点,如果为NULL,表示查找失败。

3)、通过device_type属性查找指定的节点

struct device_node *of_find_node_by_type(struct device_node *from, const char *type)

from:开始查找的节点,如果为NULL,表示从根节点开始查找整个设备树;

type:要查找的节点对应的type字符串,也就是 device_type属性值。

返回值:返回找到的节点,如果为NULL,表示查找失败。

4)、根据device_type属性和compatible属性查找指定的节点

struct device_node *of_find_compatible_node(struct device_node *from, const char *type, const char *compatible)

from:开始查找的节点,如果为NULL,表示从根节点开始查找整个设备树;

type:要查找的节点对应的type字符串,也就是device_type属性值。若为NULL,则可忽略掉device_type属性值;

compatible:要查找的节点所对应的compatible 属性列表;

返回值:返回找到的节点,如果为NULL,表示查找失败。

5)、通过of_device_id匹配表来查找指定的节点

struct device_node *of_find_matching_node_and_match(struct device_node *from, const struct of_device_id *matches, const struct of_device_id **match)

from:开始查找的节点,如果为NULL,表示从根节点开始查找整个设备树。matches: of_device_id匹配表,也就是在此匹配表里面查找节点。

match:找到的匹配的of_device_id

返回值:返回找到的节点,如果为NULL,表示查找失败。

6)、通过路径来查找指定的节点

inline struct device_node *of_find_node_by_path(const char *path)

path:带有全路径的节点名,可以使用节点的别名,比如“/backlight”就是 backlight 这个节点的全路径。

返回值:返回找到的节点,如果为NULL,表示查找失败。

7)、获取指定节点的父节点

struct device_node *of_get_parent(const struct device_node *node)

node:要查找的父节点的节点名称。返回值: 返回找到的父节点。

8)、采用迭代方式查找子节点,即查找“prev”的下一个节点。

struct device_node *of_get_next_child(const struct device_node *node, struct device_node *prev)

node:父节点。

prev:前一个子节点,也就是从哪一个子节点开始迭代的查找下一个子节点。若设置为NULL,则表示从第一个子节点开始。

返回值: 返回找到的下一个子节点。

9)、查找指定的属性

property *of_find_property(const struct device_node *np, const char *name, int *lenp)

np:设备节点。

name:属性名字。

lenp:属性值的字节数

返回值:返回找到的属性。

10)、获取属性中元素的数量

int of_property_count_elems_of_size(const struct device_node *np, const char *propname, int elem_size)

np:设备节点。

proname:需要统计元素数量的属性名字。

elem_size:元素长度。

返回值: 返回得到的属性元素数量。

11)、从属性中获取指定标号的数据值

int of_property_read_u32_index(const struct device_node *np, const char *propname, u32 index, u32 *out_value)

np:设备节点。

proname:要读取的属性名字。index:要读取的值标号;

out_value:读取到的值返回值:0读取成功,负值,读取失败,-EINVAL表示属性不存在,-ENODATA 表示没有要读取的数据,-EOVERFLOW 表示属性值列表太小。

12)、读取属性中u8类型的数组数据

int of_property_read_u8_array(const struct device_node *np, const char *propname, u8 *out_values, size_t sz)

np:设备节点。proname:要读取的属性名字。out_value:读取到的数组值,数据类型为u8。

sz:要读取的数组元素数量。返回值:0,读取成功,负值,读取失败,-EINVAL 表示属性不存在,-ENODATA 表示没有要读取的数据,-EOVERFLOW 表示属性值列表太小。

13)、读取属性中u16类型的数组数据

int of_property_read_u16_array(const struct device_node *np, const char *propname, u16 *out_values, size_t sz)

np:设备节点。proname:要读取的属性名字。out_value:读取到的数组值,数据类型为u16。sz:要读取的数组元素数量。返回值:0,读取成功,负值,读取失败,-EINVAL 表示属性不存在,-ENODATA 表示没有要读取的数据,-EOVERFLOW 表示属性值列表太小。

14)、读取属性中u32类型的数组数据

int of_property_read_u32_array(const struct device_node *np, const char *propname, u32 *out_values, size_t sz)

np:设备节点。proname:要读取的属性名字。out_value:读取到的数组值,数据类型为u32。sz:要读取的数组元素数量。返回值:0,读取成功,负值,读取失败,-EINVAL 表示属性不存在,-ENODATA 表示没有要读取的数据,-EOVERFLOW 表示属性值列表太小。

15)、读取属性中u64类型的数组数据

int of_property_read_u64_array(const struct device_node *np, const char *propname, u64 *out_values, size_t sz)

np:设备节点。proname:要读取的属性名字。out_value:读取到的数组值,数据类型为u64。sz:要读取的数组元素数量。返回值:0,读取成功,负值,读取失败,-EINVAL 表示属性不存在,-ENODATA 表示没有要读取的数据,-EOVERFLOW 表示属性值列表太小。

16)、读取属性中只有一个u8类型的数据

int of_property_read_u8(const struct device_node *np, const char *propname, u8 *out_value)

np:设备节点。proname:要读取的属性名字。out_value:读取到的u8类型的数据值。返回值:0,读取成功,负值,读取失败,-EINVAL 表示属性不存在,-ENODATA 表示没有要读取的数据,-EOVERFLOW 表示属性值列表太小。

17)、读取属性中只有一个u16类型的数据

int of_property_read_u16(const struct device_node *np, const char *propname, u16 *out_value)

np:设备节点。proname:要读取的属性名字。out_value:读取到的u16类型的数据值。返回值:0,读取成功,负值,读取失败,-EINVAL 表示属性不存在,-ENODATA 表示没有要读取的数据,-EOVERFLOW 表示属性值列表太小。

18)、读取属性中只有一个u32类型的数据

int of_property_read_u16(const struct device_node *np, const char *propname, u32 *out_value)

np:设备节点。proname:要读取的属性名字。out_value:读取到的u32类型的数据值。返回值:0,读取成功,负值,读取失败,-EINVAL 表示属性不存在,-ENODATA 表示没有要读取的数据,-EOVERFLOW 表示属性值列表太小。

19)、读取属性中只有一个u64类型的数据

int of_property_read_u16(const struct device_node *np, const char *propname, u64 *out_value)

np:设备节点。proname:要读取的属性名字。out_value:读取到的u64类型的数据值。返回值:0,读取成功,负值,读取失败,-EINVAL 表示属性不存在,-ENODATA 表示没有要读取的数据,-EOVERFLOW 表示属性值列表太小。

20)、读取属性中的字符串值

int of_property_read_string(struct device_node *np, const char *propname, const char **out_string)

np:设备节点。proname:要读取的属性名字。out_string:读取到的字符串值。返回值:0,读取成功,负值,读取失败。

21)、获取“#address-cells”属性值

int of_n_addr_cells(struct device_node *np)

np:设备节点。返回值:返回“#address-cells”的属性值。

22)、获取“#size-cells”属性值

int of_n_size_cells(struct device_node *np)

np:设备节点。返回值:返回“#size-cells”的属性值。

23)、査看“节点的compatible属性”是否有包含“compat指定的字符串”,也就是检查设备节点的兼容性

int of_device_is_compatible(const struct device_node *device, const char *compat)

device:设备节点;

compat:要查看的字符串。返回值:0,表示“节点的compatible属性”中不包含“compat指定的字符串”;正数,表示“节点的compatible属性”中包含“compat指定的字符串”。

24)、读取“reg”或者“assigned-addresses”属性值

const __be32 *of_get_address(struct device_node *dev, int index, u64 *size, unsigned int *flags)

dev:设备节点。

index:要读取的地址标号。

size:地址长度。flags:参数,比如“IORESOURCE_IO”、“IORESOURCE_MEM”等返回值:返回读取到的地址数据首地址,若返回值为NUIL,则表示读取失败。

25)、将从设备树读取到的地址addr转换为物理地址

u64 of_translate_address(struct device_node *dev, const __be32 *addr)

dev:设备节点。

addr:要转换的地址。

返回值:返回得到的物理地址,如果为 OF_BAD_ADDR,则表示转换失败。

26)、将reg属性值转换为resource结构体类型

int of_address_to_resource(struct device_node *dev, int index, struct resource *r)

dev:设备节点。

index:地址资源标号

r:得到的resource 类型的资源值。

返回值:0,成功:负值,失败。

27)、将“reg属性中地址信息”转换为“虚拟地址”,如果reg属性有多段的话,可以通过index参数指定要完成内存映射的是哪一段

void __iomem *of_iomap(struct device_node *np, int index)

np:设备节点。

index:reg属性中要完成内存映射的段,如果reg属性只有一段的话,则index=0。

返回值:经过内存映射后的虚拟内存首地址,如果为NULL的话,则表示内存映射失败。

注意:也可以使用ioremap()函数来完成物理地址到虚拟地址的内存映射。在采用设备树以后,大部分的驱动都使用of_iomap()函数来获取内存地址所对应的虚拟地址。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

深度学习与人类的智能交互:迈向自然与高效的人机新纪元

引言 随着科技的飞速发展&#xff0c;深度学习作为人工智能领域的一颗璀璨明珠&#xff0c;正日益展现出其在模拟人类认知和感知过程中的强大能力。本文旨在探讨深度学习如何日益逼近人类智能的边界&#xff0c;并通过模拟人类的感知系统&#xff0c;使机器能更深入地理解和解…

深空通信DTN总结

这里写自定义目录标题 A novel Federated Computation approach for Artificial Intelligence applications in Delay and Disruption Tolerant NetworksabstractintroductionDELAY AND DISRUPTION TOLERANT NETWORKS联邦计算用于容忍延迟和干扰的网络的联合学习框架DTN-ML Orc…

【视频图像取证篇】Impress模糊图像增强技术之颜色滤波器场景实例教程(蘇小沐)

【视频图像取证篇】Impress模糊图像增强技术之颜色滤波器场景实例教程&#xff08;蘇小沐&#xff09; Impress模糊图像增强技术之颜色滤波器场景实例教程—【蘇小沐】 1、实验环境 系统环境Impress&#xff0c;[v8.2.02]Windows 11 专业版&#xff0c;[23H2&#xff08;226…

犀牛7-软件基础设置

一、刚打开页面时&#xff0c;会弹出模板文件&#xff0c;一般我们选择小模型-毫米&#xff0c; 我们点击小模型-毫米之后&#xff0c;界面是这样的。 菜单栏&#xff1a;我们比较少使用&#xff0c;一般就用到创建文件。 命令栏(非常重要)&#xff1a;1、记录我们使用过的工…

httprunner参数化

1. 示例 引入对应的Parameters 1.1. CSV参数 from httprunner import HttpRunner, Config, Step, RunRequest, Parameters pytest.mark.parametrize("param", Parameters({"mobile_phone-pwd": "${P(csv_data/mobile_phone-pwd.csv)}"}))def …

项目解决方案:多地5G蓄能电站的视频监控联网系统设计方案

目 录 一、前言 二、系统架构设计 1、系统架构设计说明 2、系统拓扑图 三、关键技术 1. 5G支持技术 2. 视频图像处理技术 3. 数据融合与分析技术 四、功能特点 1. 高效可靠 2. 实时监测 3. 远程控制 4. 故障预测 五、应用前景 一、前言 随着能源…

讲讲 SaaS 平台的多租户设计

本篇就来讲讲 SaaS 平台的多租户设计。 以“钉钉”为例看实际的多租户场景 在讲设计之前&#xff0c;我们先以“钉钉”为例&#xff0c;来看看一个 SaaS 平台是如何运作的。相信大部分B 端产品经理都体验过钉钉&#xff0c;我们分两个维度来讲钉钉的租户注册到使用的流程。一…

w022郑州大学招新赛选拔赛

A-SW的与众不同数组_2022学年第一学期郑州大学ACM招新赛&选拔赛 (nowcoder.com) #include <bits/stdc.h> #define int long long using namespace std;void solve(){int n;cin >> n;vector<int> v;for(int i 1; i < n; i){int x;cin >> x;v.p…

导出谷歌gemma模型为ONNX

参考代码如下&#xff08;从GitHub - luchangli03/export_llama_to_onnx: export llama to onnx修改而来&#xff0c;后面会合入进去&#xff09; 模型权重链接参考&#xff1a; https://huggingface.co/google/gemma-2b-it 可以对modeling_gemma.py进行一些修改(transforme…

docker搭建dashdot

Dashdot 是一个指标收集工具&#xff0c;用于报告 Kubernetes 集群中的资源使用情况。假设你想要使用 Docker 来搭建 Dashdot&#xff0c;你需要制作或获取一个 Dashdot 的 Docker 镜像&#xff0c;然后可以通过 Docker CLI 命令或者使用 Docker Compose 来配置和运行这个容器。…

TinTin DESTINATION MOON|开发者不容错过的 Web3 线下活动来啦!

还记得去年 9 月 17 日的上海吗&#xff1f;「DESTINATION MOON: Web3 Dev Summit Shanghai 2023」迎来了数百名 Web3 行业爱好者的关注和参与。4 场主题演讲、3 场圆桌讨论&#xff0c;近 20 名创新者、开发者、投资人和研究员围绕公链生态、Layer2 竞争、DID、ZKP、安全等热点…

人工智能聊天机器人完整指南 - 推荐10家国外聊天机器人公司

人工智能&#xff08;AI&#xff09;聊天机器人革命正在向我们袭来。由对话式AI驱动的AI聊天机器正在改变企业世界&#xff0c;为公司提供更高效的方式与客户和员工互动。本综合指南将介绍AI聊天机器人&#xff0c;解释其主要功能和优势&#xff0c;并探讨它们如何改变您的业务…

3.8 动态规划 背包问题

一.01背包 46. 携带研究材料&#xff08;第六期模拟笔试&#xff09; (kamacoder.com) 代码随想录 (programmercarl.com) 携带研究材料: 时间限制&#xff1a;5.000S 空间限制&#xff1a;128MB 题目描述: 小明是一位科学家&#xff0c;他需要参加一场重要的国际科学大会…

使用docker安装运行rabbitmq---阿里云服务器

目录 0、阿里云没开端口的得要去安全组规则去添加&#xff1a; 1、下载RabbitMQ镜像&#xff1a; 2、查看镜像是否下载成功&#xff0c;得到docker镜像id&#xff1a; 3、运行RabbitMQ: 4、查看RabbbitMQ容器是否启动成功&#xff1a; 5、启动RabbitMQ中的插件管理 6、访…

RabbitMQ的web控制端介绍

2.1 web管理界面介绍 connections&#xff1a;无论生产者还是消费者&#xff0c;都需要与RabbitMQ建立连接后才可以完成消息的生产和消费&#xff0c;在这里可以查看连接情况channels&#xff1a;通道&#xff0c;建立连接后&#xff0c;会形成通道&#xff0c;消息的投递、获取…

Z Potentials | 星爵,他的征途不止向量数据库

纵观过去几十年的科技发展史&#xff0c;每一代新的技术架构的出现往往都伴随着新的数据范式的出现&#xff0c;也催生了多家百亿到千亿美金数据平台的诞生。如果说 2023 年科技领域的关键词是 LLM&#xff0c;那么数据库领域的关键词一定非向量数据库莫属。向量数据库是一种专…

C++面向对象程序设计-北京大学-郭炜【课程笔记(五)】

C面向对象程序设计-北京大学-郭炜【课程笔记&#xff08;五&#xff09;】 1、常量对象、常量成员函数1.1、常量对象1.2、常量成员函数1.3、常引用 2、友元&#xff08;friends&#xff09;2.1、友元函数2.2、友元类 3、运算符重载的基本概念3.1、运算符重载 4、赋值运算符的重…

红黑树的学习

红黑树 红黑树出自一种平衡的二叉查找树&#xff0c;是计算机科学中中用到的一种数据结构 1972年出现&#xff0c;当时被称之为平衡二叉B树。后来&#xff0c;1978年被修改为如今的红黑树 他是一种特殊的二叉查找树&#xff0c;红黑树的每一个节点上都有存储表示节点的颜色 …

HarmonyOS NEXT应用开发案例——自定义TabBar

介绍 本示例主要介绍了TabBar中间页面如何实现有一圈圆弧外轮廓以及TabBar页签被点击之后会改变图标显示&#xff0c;并有一小段动画效果。 效果图预览 使用说明&#xff1a; 依次点击tabBar页面&#xff0c;除了社区图标之外&#xff0c;其它图标往上移动一小段距离。 实现…

软件测试【测试用例设计】面试题详解

前言 今天笔者想和大家来聊聊测试用例&#xff0c;这篇文章主要是想要写给测试小伙伴们的&#xff0c;因为我发现还是有很多小伙伴在遇到写测试用例的时候无从下手&#xff0c;我就想和大家简单的聊聊&#xff0c;这篇文章主要是针对功能测试的。 一、微信功能测试 1.点击点…