ESP32_H2(IDF)学习系列-蓝牙基础学习(上)
一、简介
参考:[乐鑫-蓝牙]
Bluetooth LE 的分层架构
Bluetooth LE 协议定义了三层软件结构,自上而下分别是
应用层 (Application Layer) 应用层(Application Layer)
主机层 (Host Layer)
控制器层 (Controller Layer)
应用层即以 Bluetooth LE 为底层通信技术所构建的应用,依赖于主机层向上提供的 API 接口。
主机层负责实现 L2CAP、GATT/ATT、SMP、GAP 等底层蓝牙协议,向上对应用层提供 API 接口,向下通过主机控制器接口 (Host Controller Interface, HCI) 与控制器层通信。
控制器层包括物理层 (Physical Layer, PHY) 和链路层 (Link Layer, LL) 两层,向下直接与控制器硬件进行交互,向上通过 HCI 与主机层进行通信。
值得一提的是,蓝牙核心规范 (Core Specification) 允许主机层和控制器层在物理上分离,此时 HCI 体现为物理接口,包括 SDIO、USB 以及 UART 等;当然,主机层和控制器层可以共存于同一芯片,以实现更高的集成度,此时 HCI 体现为逻辑接口,常被称为虚拟主机控制器接口 (Virtual Host Controller Interface, VHCI)。一般认为,主机层和控制器层组成了 Bluetooth LE 协议栈 (Bluetooth LE Stack)。
下图展示了 Bluetooth LE 的分层结构。
Bluetooth LE 分层结构
Bluetooth LE 分层结构
作为应用开发者,在开发过程中我们主要与主机层提供的 API 接口打交道,这要求我们对主机层中的蓝牙协议有一定的了解。接下来,我们会从连接和数据交换两个角度,对 GAP 和 GATT/ATT 层的基本概念进行介绍。
GAP 层 - 定义设备的连接
GAP 层的全称为通用访问规范 (Generic Access Profile, GAP),定义了 Bluetooth LE 设备之间的连接行为以及设备在连接中所扮演的角色。
GAP 状态与角色
GAP 中共定义了三种设备的连接状态以及五种不同的设备角色,如下
空闲 (Idle)
此时设备无角色,处于就绪状态 (Standby)
设备发现 (Device Discovery)
广播者 (Advertiser)
扫描者 (Scanner)
连接发起者 (Initiator)
连接 (Connection) 连接(Connection)
外围设备 (Peripheral)
中央设备 (Central)
广播者向外广播的数据中包含设备地址等信息,用于向外界设备表明广播者的存在,并告知其他设备是否可以连接。扫描者则持续接收环境中的广播数据包。若某一个扫描者发现了一个可连接的广播者,并希望与之建立连接,可以将角色切换为连接发起者。当连接发起者再次收到该广播者的广播数据,会立即发起连接请求 (Connection Request);在广播者未开启白名单 (Filter Accept List, 又称 White List) 或连接发起者在广播者的白名单之中时,连接将被成功建立。
进入连接以后,原广播者转变为外围设备(旧称从设备 Slave ),原扫描者或连接初始化者转变为中央设备(旧称主设备 Master )。
GAP 角色之间的转换关系如下图所示
Bluetooth LE 网络拓扑
Bluetooth LE 设备可以同时与多个 Bluetooth LE 设备建立连接,扮演多个外围设备或中央设备角色,或同时作为外围设备和中央设备。以 Bluetooth LE 网关为例,这种设备可以作为中央设备,与智能开关等外围设备连接,同时作为外围设备,与形如手机等中央设备连接,实现数据中转。
在一个 Bluetooth LE 网络中,若所有设备都在至少一个连接中,且仅扮演一种类型的角色,则称这种网络为连接拓扑 (Connected Topology);若存在至少一个设备同时扮演外围设备和中央设备,则称这种网络为多角色拓扑 (Multi-role Topology)。
Bluetooth LE 同时也支持无连接的网络拓扑,即广播拓扑 (Broadcast Topology)。在这种网络中,存在两种角色,其中发送数据的被称为广播者 (Broadcaster),接收数据的被称为观察者 (Observer)。广播者只广播数据,不接受连接;观察者仅接受广播数据,不发起连接。例如,某个智能传感器的数据可能在一个网络中被多个设备共用,此时维护多个连接的成本相对较高,直接向网络中的所有设备广播传感器数据更加合适。
了解更多
如果你想了解更多设备发现与连接的相关信息,请参考 设备发现 与 连接 。
GATT/ATT 层 - 数据表示与交换
GATT/ATT 层定义了进入连接状态后,设备之间的数据交换方式,包括数据的表示与交换过程。
ATT 层 ATT 层间
ATT 的全称是属性协议 (Attribute Protocol, ATT),定义了一种称为属性 (Attribute) 的基本数据结构,以及基于服务器/客户端架构的数据访问方式。
简单来说,数据以属性的形式存储在服务器上,等待客户端的访问。以智能开关为例,开关量作为数据,以属性的形式存储在智能开关内的蓝牙芯片(服务器)中,此时用户可以通过手机(客户端)访问智能开关蓝牙芯片(服务器)上存放的开关量属性,获取当前的开关状态(读访问),或控制开关的闭合与断开(写访问)。
属性这一数据结构一般由以下三部分构成
句柄 (Handle)
类型 (Type)
值 (Value) 价值(Value)
访问权限 (Permissions)
在协议栈实现中,属性一般被放在称为属性表 (Attribute Table) 的结构体数组中管理。一个属性在这张表中的索引,就是属性的句柄,常为一无符号整型。
属性的类型由 UUID 表示,可以分为 16 位、32 位与 128 位 UUID 三类。 16 位 UUID 由蓝牙技术联盟 (Bluetooth Special Interest Group, Bluetooth SIG) 统一定义,可以在其公开发布的 Assigned Numbers 文件中查询;其他两种长度的 UUID 用于表示厂商自定义的属性类型,其中 128 位 UUID 较为常用。
GATT 层 GATT 层间协议
GATT 的全称是通用属性规范 (Generic Attribute Profile),在 ATT 的基础上,定义了以下三个概念
特征数据 (Characteristic)
服务 (Service)
规范 (Profile)
这三个概念之间的层次关系如下图所示
GATT 中的层次关系
GATT 中的层次关系
特征数据和服务都是以属性为基本数据结构的复合数据结构。一个特征数据往往由两个以上的属性描述,包括
特征数据声明属性 (Characteristic Declaration Attribute)
特征数据声明属性(Characteristic Declaration Attribute)
特征数据值属性 (Characteristic Value Attribute)
特征数据值属性(Characteristic Value Attribute)
除此以外,特征数据中还可能包含若干可选的描述符属性 (Characteristic Descriptor Attribute)。
一个服务本身也由一个属性进行描述,称为服务声明属性 (Service Declaration Attribute)。一个服务中可以存在一个或多个特征数据,它们之间体现为从属关系。另外,一个服务可以通过 Include 机制引用另一个服务,复用其特性定义,避免如设备名称、制造商信息等相同特性的重复定义。
规范是一个预定义的服务集合,实现了某规范中所定义的所有服务的设备即满足该规范。例如 Heart Rate Profile 规范由 Heart Rate Service 和 Device Information Service 两个服务组成,那么可以称实现了 Heart Rate Service 和 Device Information Service 服务的设备符合 Heart Rate Profile 规范。
广义上,我们可以称所有存储并管理特征数据的设备为 GATT 服务器,称所有访问 GATT 服务器以访问特征数据的设备为 GATT 客户端。
二、参考例程解析学习
参考官方API解析:
乐鑫-蓝牙API
一个GATT 服务器应用程序架构(由Application Profiles组织起来)如下:
参考该播主:
程序解析
部分重点解析
GATT回调函数
esp_gatts_cb_event_t结构体
GAP回调函数
esp_gap_cb_event_t
uuid相关介绍
参考博客:UUID
BLE 服务源文件是 ESP-AT 工程创建低功耗蓝牙服务所依据的文件,文件位于 ble_data/example.csv ,可以通过自定义该文件实现 BLE 服务的自定义。
默认的 BLE 服务源文件定义如下:
以下内容是对上表的说明:
uuid_len:UUID 的长度,上表中 uuid_len 值为 16,代表 16-bit UUID
uuid:表明属性类型,其中,0x2800 为主服务声明,0x2803 为特征声明,0x2901 为特征用户描述描述符,0x2902 为客户端特征配置描述符(CCCD),可以参考下表:
perm:权限,用于描述属性是否可读或者可写。
定义如下:
#define ESP_GATT_PERM_READ (1 << 0) /* bit 0 - 0x0001 */ /* relate to BTA_GATT_PERM_READ in bta/bta_gatt_api.h */
#define ESP_GATT_PERM_READ_ENCRYPTED (1 << 1) /* bit 1 - 0x0002 */ /* relate to BTA_GATT_PERM_READ_ENCRYPTED in bta/bta_gatt_api.h */
#define ESP_GATT_PERM_READ_ENC_MITM (1 << 2) /* bit 2 - 0x0004 */ /* relate to BTA_GATT_PERM_READ_ENC_MITM in bta/bta_gatt_api.h */
#define ESP_GATT_PERM_WRITE (1 << 4) /* bit 4 - 0x0010 */ /* relate to BTA_GATT_PERM_WRITE in bta/bta_gatt_api.h */
#define ESP_GATT_PERM_WRITE_ENCRYPTED (1 << 5) /* bit 5 - 0x0020 */ /* relate to BTA_GATT_PERM_WRITE_ENCRYPTED in bta/bta_gatt_api.h */
#define ESP_GATT_PERM_WRITE_ENC_MITM (1 << 6) /* bit 6 - 0x0040 */ /* relate to BTA_GATT_PERM_WRITE_ENC_MITM in bta/bta_gatt_api.h */
#define ESP_GATT_PERM_WRITE_SIGNED (1 << 7) /* bit 7 - 0x0080 */ /* relate to BTA_GATT_PERM_WRITE_SIGNED in bta/bta_gatt_api.h */
#define ESP_GATT_PERM_WRITE_SIGNED_MITM (1 << 8) /* bit 8 - 0x0100 */ /* relate to BTA_GATT_PERM_WRITE_SIGNED_MITM in bta/bta_gatt_api.h */
#define ESP_GATT_PERM_READ_AUTHORIZATION (1 << 9) /* bit 9 - 0x0200 */
#define ESP_GATT_PERM_WRITE_AUTHORIZATION (1 << 10) /* bit 10 - 0x0400 */
val_max_len:数值的最大长度。
val_cur_len:数值的当前长度。
value:对应的数值。
如果 UUID 为 0x2800,那么该行为服务声明,对应的值应该为自定义的 UUID,以 index 0 所在的行为例,对应的值为 A002。
如果 UUID 为 0x2803,那么该行为特征声明,对应的值为特征的属性(property),以 index 1 所在的行为例,对应的值为 02,代表该特征具有读属性。
属性的定义如下:
#define ESP_GATT_CHAR_PROP_BIT_BROADCAST (1 << 0) /* 0x01 */ /* relate to BTA_GATT_CHAR_PROP_BIT_BROADCAST in bta/bta_gatt_api.h */
#define ESP_GATT_CHAR_PROP_BIT_READ (1 << 1) /* 0x02 */ /* relate to BTA_GATT_CHAR_PROP_BIT_READ in bta/bta_gatt_api.h */
#define ESP_GATT_CHAR_PROP_BIT_WRITE_NR (1 << 2) /* 0x04 */ /* relate to BTA_GATT_CHAR_PROP_BIT_WRITE_NR in bta/bta_gatt_api.h */
#define ESP_GATT_CHAR_PROP_BIT_WRITE (1 << 3) /* 0x08 */ /* relate to BTA_GATT_CHAR_PROP_BIT_WRITE in bta/bta_gatt_api.h */
#define ESP_GATT_CHAR_PROP_BIT_NOTIFY (1 << 4) /* 0x10 */ /* relate to BTA_GATT_CHAR_PROP_BIT_NOTIFY in bta/bta_gatt_api.h */
#define ESP_GATT_CHAR_PROP_BIT_INDICATE (1 << 5) /* 0x20 */ /* relate to BTA_GATT_CHAR_PROP_BIT_INDICATE in bta/bta_gatt_api.h */
#define ESP_GATT_CHAR_PROP_BIT_AUTH (1 << 6) /* 0x40 */ /* relate to BTA_GATT_CHAR_PROP_BIT_AUTH in bta/bta_gatt_api.h */
#define ESP_GATT_CHAR_PROP_BIT_EXT_PROP (1 << 7) /* 0x80 */ /* relate to BTA_GATT_CHAR_PROP_BIT_EXT_PROP in bta/bta_gatt_api.h */
特征声明接下来的一行为特征值定义,以 index 2 所在的行为例,0xC300为自定义特征的 UUID ,对应的数值长度只有一个字节,对应数值为 30。
0x2902为客户端配置描述符(CCCD),可以看到,特征 0xC305(index 16) 具有 CCCD,其值占用两个字节,初始值为 0000,表示通知 (notification) 和指示 (indication) 被禁用。
上表中,自定义了两个 BLE 服务,分别为 A002 和 A003。
其中,服务 A002 有 8 个特征,服务 A003 有 2 个特征,简单总结见下表:
参考博客:
UUID
UUID的种类分为两种:
一种是 SIG 定义的公共服务 UUID,所有的公共服务共用一个 128bit 的基础 UUID,不同的服务采用一个 16bit UUID 进行定义。基础UUID:0x0000xxxx-0000-1000-8000-00805F9B34FB
另一种就是私有服务的 UUID,这是一个自定义的 128bit UUID。
注意:广播包里的 UUID 不影响服务特征值中 UUID 的值,仅仅是让广播把 UUID 的值广播给扫描设备,方便观察。
这里广播了两个 16bite UUID:0x00EE、0x00FF
static uint8_t adv_service_uuid128[32] = {/* LSB <--------------------------------------------------------------------------------> MSB *///first uuid, 16bit, [12],[13] is the value0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0xEE, 0x00, 0x00, 0x00,//second uuid, 32bit, [12], [13], [14], [15] is the value0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
};static esp_ble_adv_params_t ble_adv_params = {.adv_int_min = 0x20,.adv_int_max = 0x40,.adv_type = ADV_TYPE_IND,.own_addr_type = BLE_ADDR_TYPE_PUBLIC,.channel_map = ADV_CHNL_ALL,.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
};static esp_ble_adv_data_t adv_data = {.service_uuid_len = sizeof(adv_service_uuid128),.p_service_uuid = adv_service_uuid128,.flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT),
};esp_ble_gap_config_adv_data(&adv_data); // 配置广播内容
esp_ble_gap_start_advertising(&ble_adv_params); // 开启广播
广播的从机连接间隔数:
从机与主机之间的连接间隔,是由从机提出与主机进行协商,然后再由主机决定的参数。
先设置 min_interval 和 max_interval 的值,然后调用 esp_ble_gap_config_adv_data(),再调用 esp_ble_gap_start_advertising()
static esp_ble_adv_params_t ble_adv_params = {.adv_int_min = 0x20,.adv_int_max = 0x40,.adv_type = ADV_TYPE_IND,.own_addr_type = BLE_ADDR_TYPE_PUBLIC,.channel_map = ADV_CHNL_ALL,.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
};static esp_ble_adv_data_t adv_data = {.min_interval = 0x000A, //slave connection min interval, Time = min_interval * 1.25 msec=7.5ms.max_interval = 0x0014, //slave connection max interval, Time = max_interval * 1.25 msec=20ms.flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT),
};esp_ble_gap_config_adv_data(&adv_data); // 配置广播内容
esp_ble_gap_start_advertising(&ble_adv_params); // 开启广播
广播自定义数据
p_manufacturer_data:制造商自定义的数据,这个参数可以自由的设置,只要广播包的空间足够。假设自定义数据为 0x11,0x22,0x33,0x44,0x55。
static uint8_t user_data[5] = {0x11, 0x22, 0x33, 0x44, 0x55};static esp_ble_adv_params_t ble_adv_params = {.adv_int_min = 0x20,.adv_int_max = 0x40,.adv_type = ADV_TYPE_IND,.own_addr_type = BLE_ADDR_TYPE_PUBLIC,.channel_map = ADV_CHNL_ALL,.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
};static esp_ble_adv_data_t adv_data = {.manufacturer_len = sizeof(user_data),.p_manufacturer_data = user_data,.flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT),
};esp_ble_gap_config_adv_data(&adv_data); // 配置广播内容
esp_ble_gap_start_advertising(&ble_adv_params); // 开启广播
原文链接:https://blog.csdn.net/qq_36347513/article/details/118495466
BLE广播类型
参考博客:BLE 广播
typedef enum {ADV_TYPE_IND = 0x00,ADV_TYPE_DIRECT_IND_HIGH = 0x01,ADV_TYPE_SCAN_IND = 0x02,ADV_TYPE_NONCONN_IND = 0x03,ADV_TYPE_DIRECT_IND_LOW = 0x04,
} esp_ble_adv_type_t;
下面是对这几种广播类型的说明:
ADV_TYPE_IND(可连接的非定向广播):
这是一种用途最广,最常见的广播类型,包括广播数据和扫描响应数据,它表示当前设备可以接受任何设备的连接请求。
进行通用广播的设备能够被扫描设备扫描到,或者在接收到连接请求时作为从设备进入一个连接。
ADV_TYPE_DIRECT_IND_HIGH ADV_TYPE_DIRECT_IND_LOW(可连接的定向广播):
定向广播类型是为了尽可能快地连接,俗称回连包,这种报文包含两个地址:广播者的地址和发起者的地址。发起者收到发给自己的定向广播报文之后,可以立即发送连接请求作为回应。
当使用定向广播时,设备不能被主动扫描。此外,定向广播报文的有效载荷中也不能带有其他附加数据。该有效载荷只能包含两个必须的地址。
ADV_TYPE_DIRECT_IND_HIGH 为可连接高占空比定向广播,在该模式下,发送在相同广播信道索引上的两个连续 ADV_DIRECT_IND PDU 之间的时间间隔应小于或等于 3.75 毫秒。
ADV_TYPE_DIRECT_IND_LOW 为可连接低占空比定向广播,在该模式下,两个连续的ADV_DIRECT_IND PDU 之间的时间间隔在一个广播事件内应小于或等于 10 毫秒。广播事件应在广播间隔内结束。
ADV_TYPE_SCAN_IND(可扫描的非定向广播):
又称可发现广播,这种广播不能用于发起连接,但允许其他设备扫描该广播设备。这意味着该设备可以被发现,既可以发送广播数据,也可以响应扫描发送扫描响应数据,但不能建立连接。这是一种适用于广播数据的广播形式,动态数据可以包含于广播数据之中,而静态数据可以包含于扫描响应数据之中。
ADV_TYPE_NONCONN_IND(不可连接的非定向广播):
仅仅发送广播数据,而不能被扫描或者连接。这也是唯一可用于只有发射机而没有接收机设备的广播类型。不可连接设备不会进入连接态,因此,它只能根据主机的要求在广播态和就绪态之间切换。常用于 Beacon 项目。
配置蓝牙的广播设备地址类型:
参考博客:蓝牙广播设备地址类型
1、这个是蓝牙的公共地址,它可以使用 自带的,也可以使用自己设置,这个地址设置好了之后就是一直不变的。
2、BLE_ADDR_TYPE_RANDOM 表示随机静态地址(Random Static Address),是一种固定的、不变的地址类型。虽然它也是随机生成的,但在设备生命周期内不会更改(每次电源重启后设备可选择将其静态设备地址初始化并赋予新的静态地址值。设备完成初始化后在下一次电源重启前不得再修改其静态地址值。备注: 设备的静态地址修改后存储其原来地址的对等设备将无法与其自动重连。)
3、
将 BLE 设备的地址类型设置为 “ble_addr_type_rpa_public”。
在设备启动时,生成一个随机数作为低 24 位,并将上 24 位设置为公共设备 ID。
将生成的地址广播出去,以供其他设备扫描和连接。
4、不可解析私有地址配置
不可解析私有地址随机部分和随机静态地址的随机部分是一样的,个人理解这两个地址的不同就在于,随机静态地址在电源重启之前都不能改变其地址。而不可解析私有地址可以在每次广播之前都可以改变自己的地址。
相关文章:
ESP32_H2(IDF)学习系列-蓝牙基础学习(上)
一、简介 参考:[乐鑫-蓝牙] Bluetooth LE 的分层架构 Bluetooth LE 协议定义了三层软件结构,自上而下分别是 应用层 (Application Layer) 应用层(Application Layer) 主机层 (Host Layer) 控制器层 (Controller Layer) 应用…...
防御综合实验
需求一 配置vlan [SW2]int g 0/0/2 [SW2-GigabitEthernet0/0/2]port link-type access [SW2-GigabitEthernet0/0/2]port default vlan 10 [SW2-GigabitEthernet0/0/2]int g0/0/3 [SW2-GigabitEthernet0/0/3]port link-type access [SW2-GigabitEthernet0/0/3]port default vl…...
Blazor-<select>
今天我们来说说<select>标签的用法,我们还是从一个示例代码开始 page "/demoPage" rendermode InteractiveAuto inject ILogger<InjectPage> logger; <h3>demoPage</h3> <select multiple>foreach (var item in list){<…...
zy.21
PHP(续) PHP代码执行漏洞 1.PHP中代码漏洞的概念 代码执行漏洞就是在代码中若存在eval、assert等能将所接收的参数作为代码去执行,并且拼接的内容可被访问者控制,也就是把传入的参数给拼接进去了,造成了额外的代码执行,也就造成了代码执行漏洞。(大概原理&#x…...
【c++】四种类型转换形式
【c】四种类型转换形式 编译时: static_cast(静态转换) const_cast(去常性转换) reinterpret_cast(重新解释转换,直接转换地址) 运行时: dynamic_cast(动态转换,运行时类…...
在npm上传属于自己的包
最近在整理代码,上传到npm方便使用,所以学习了如何在npm发布一个包,整理写成一篇文章和大家一起交流。 1、注册npm账号 npm | Home 2、确保是登录状态 (在包目录下,终端执行 npm login) 按enter键自动打开页面&…...
关系型数据库主备高可用方案对比笔记
目录标题 数据库高可用性解决方案对比Oracle Data GuardMySQL 主从复制SQL Server AlwaysOnPG Patroni 流复制达梦 DMDataWatch人大金仓 repmgr 备库故障是否影响主库?表格关系型数据库主备高可用方案对比笔记 数据库高可用性解决方案对比 Oracle Data Guard Orac…...
怎么查看电脑显存大小(查看电脑配置)
这里提供一个简单的方法查看 winr打开cmd 终端输入dxdiag进入DirectX 点击显示查看设备的显示内存(VRAM) 用这个方法查看电脑配置和显存是比较方便的 dxdiag功能 Dxdiag是Windows的DirectX诊断工具,其主要作用包括但不限于以下几点&#…...
深入理解指针(二)
深入理解指针(二) 前言:一、const修饰指针1.const修饰变量2.const修饰的指针变量 二、野指针1.野指针的成因(1).指针的未初始化(2).指针的越界访问(3).指针的空间释放 2.如何规避野指针(1).指针初始化(2).小心访问越界(3)指针不再使用的时候&…...
非华为电脑制作一碰传NFC贴纸
前提: 在笔记本上安装好华为电脑管家,可以在 github 上下载,并测试可以正常和手机或平板连接步骤: 1、打开电脑华为电脑管家,点【快捷服务】,记录下序列号,一般安装后会生成16位的序列号 2、…...
Wpf美化按钮,输入框,下拉框,dataGrid
Wpf美化按钮,输入框,下拉框,dataGrid 引用代码后 引用资源 <ControlTemplate x:Key"CustomProgressBarTemplate" TargetType"ProgressBar"><Grid><Border x:Name"PART_Track" CornerRadius&q…...
Office/WPS接入DeepSeek等多个AI工具,开启办公新模式!
在现代职场中,Office办公套件已成为工作和学习的必备工具,其功能强大但复杂,熟练掌握需要系统的学习。为了简化操作,使每个人都能轻松使用各种功能,市场上涌现出各类办公插件。这些插件不仅提升了用户体验,…...
【深度学习】多目标融合算法(四):多门混合专家网络MMOE(Multi-gate Mixture-of-Experts)
目录 一、引言 二、MMoE(Multi-gate Mixture-of-Experts,多门混合专家网络) 2.1 技术原理 2.2 技术优缺点 2.3 业务代码实践 2.3.1 业务场景与建模 2.3.2 模型代码实现 2.3.3 模型训练与推理测试 2.3.4 打印模型结构 三、总结 一、…...
git submodule使用
git submodule 用于关联其他独立的仓库。 它有着几点好处: 代码复用:可以将工具代码放到单独的仓库,再通过 submodule 关联。模块化开发:可以将项目拆分成多个模块,每个模块设置单独仓库独立开发,再通过 su…...
朝天椒USB服务器:解决加密狗远程连接
本文探讨朝天椒USB服务器用Usb Over Network技术,解决加密狗在虚拟机、云主机甚至异地的远程连接问题。 在企业数字化转型的浪潮中,加密狗作为防止软件盗版的重要手段,广泛应用于各类软件授权场景。然而,随着企业超融合进程不断加…...
[笔记.AI]deepseek-r1的不同版本(满血版、蒸馏版、量化)
满血版:是原始的高性能模型; 蒸馏版(Distill):是指将大型模型(教师模型)的知识转移到较小的模型(学生模型)中,以保持性能的同时减少计算资源的需求࿱…...
Kokoro 开源文本转语音引擎上线!多语言支持,无需联网,浏览器内极速运行
Kokoro 是一款轻量级的开源文本转语音(TTS)引擎,凭借其高效能和轻量化设计,迅速在技术社区中引起关注。本文将详细介绍 Kokoro 的主要特点,并提供在浏览器和 Python 环境中的代码示例,帮助您快速上手。 1. Kokoro:可在浏览器中运行的 TTS 引擎 1.1 简介 Kokoro 是一个…...
Unity 基础编程
在这个练习中将新建unity脚本,控制player的运动与转动,实现用代码检测碰撞与删除物体。 该练习将应用附件中的项目文件,该文件与Unity快速练习的文件是同一个项目文件。 一、构建Player运动脚本 该部分将构建一个在场景中由玩家控制游戏物…...
CTFHub-RCE系列wp
目录标题 引言什么是RCE漏洞 eval执行文件包含文件包含php://input读取源代码远程包含 命令注入无过滤过滤cat过滤空格过滤目录分隔符过滤运算符综合过滤练习 引言 题目共有如下类型 什么是RCE漏洞 RCE漏洞,全称是Remote Code Execution漏洞,翻译成中文…...
基于YoloV11和驱动级鼠标模拟实现Ai自瞄
本文将围绕基于 YoloV11 和驱动级鼠标实现 FPS 游戏 AI 自瞄展开阐述。 需要着重强调的是,本文内容仅用于学术研究和技术学习目的。严禁任何个人或组织将文中所提及的技术、方法及思路应用于违法行为,包括但不限于在各类游戏中实施作弊等违规操作。若因违…...
基于微信小程序的博物馆预约系统的设计与实现
hello hello~ ,这里是 code袁~💖💖 ,欢迎大家点赞🥳🥳关注💥💥收藏🌹🌹🌹 🦁作者简介:一名喜欢分享和记录学习的在校大学生…...
R语言LCMM多维度潜在类别模型流行病学研究:LCA、MM方法分析纵向数据
全文代码数据:https://tecdat.cn/?p39710 在数据分析领域,当我们面对一组数据时,通常会有已知的分组情况,比如不同的治疗组、性别组或种族组等(点击文末“阅读原文”获取完整代码数据)。 然而,…...
python卷积神经网络人脸识别示例实现详解
目录 一、准备 1)使用pytorch 2)安装pytorch 3)准备训练和测试资源 二、卷积神经网络的基本结构 三、代码实现 1)导入库 2)数据预处理 3)加载数据 4)构建一个卷积神经网络 5࿰…...
如何把邮件批量导出到本地
最近遇到邮箱满了的问题,需要把邮件批量导出到本地,然后清空邮箱。 问题是这个邮箱的官网,没有批量导出按钮,比较麻烦;总不能一封一封下载到本地,上万的。 找到了一个好用的工具,Mozilla Thun…...
C++智能指针的使用
文章目录 智能指针的使用和原理智能指针的使用场景RAII和智能指针C标准库智能指针的使用 智能指针的使用和原理 智能指针的使用场景 1. 下面的程序中,new了以后,我们也delete了,但是因为抛异常导致后面的delete没有得到执行,所以…...
Docker安装Redis
一、保证Docker提起来了 systemctl status docker想这没有启动要先启动一下 systemctl status docke二、拉取Redis(默认拉最新版) sudo docker pull redis检查一下拉成功没有 docker images三、创建相关目录 mkdir -p /home/redis/{conf,data}四、…...
深入理解MySQL索引底层数据结构
文章目录 前言一、MySQL索引是什么?二、索引的核心需求三、MySQL为什么选择BTree做为数据结构1.如果使用的是Hash 做为数据结构2.如果使用二叉树做为数据结构3.使用红黑树做为数据结构4.使用B-Tree做为数据结构5.BTree做为数据结构 4.BTree深度剖析结构特性与 B-Tre…...
udp和tcp的区别
目录 UDP 和 TCP 的区别 1. 连接性 2. 可靠性 3. 数据传输顺序 4. 流量控制和拥塞控制 5. 效率 6. 应用场景 UDP 和 TCP 的 C/C 代码实现区别 1. TCP 服务器端和客户端 TCP 服务器端(Server) TCP 客户端(Client) 2. U…...
VMware 虚拟机 ubuntu 20.04 扩容工作硬盘
一、关闭虚拟机 关闭虚拟机参考下图,在vmware 调整磁盘容量 二、借助工具fdisk testubuntu ~ $ df -h Filesystem Size Used Avail Use% Mounted on udev 1.9G 0 1.9G 0% /dev tmpfs 388M 3.1M 385M 1% /run /dev/sda5 …...
MapReduce是什么?
MapReduce 是一种编程模型,最初由 Google 提出,旨在处理大规模数据集。它是分布式计算的一个重要概念,通常用于处理海量数据并进行并行计算。MapReduce的基本思想是将计算任务分解为两个阶段:Map 阶段和 Reduce 阶段。 Map 阶段&a…...
跨越边界,大模型如何助推科技与社会的完美结合?
点击蓝字 关注我们 AI TIME欢迎每一位AI爱好者的加入! 概述 2024年,大模型技术已成为人工智能领域的焦点。这不仅仅是一项技术进步,更是一次可能深刻影响社会发展方方面面的变革。大模型的交叉能否推动技术与社会的真正融合?2025年…...
计算机毕业设计SpringBoot校园二手交易小程序 校园二手交易平台(websocket消息推送+云存储+双端+数据统计)(源码+文档+运行视频+讲解视频)
温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 作者简介:Java领…...
RK3568平台开发系列讲解(ConfigFS篇)ConfigFS核心数据结构
🚀返回专栏总目录 文章目录 一、数据结构二、结构体关系三、案例3.1、configfs_subsystem 实例3.2、config_group 实例化四、属性和方法五、config_item实例化沉淀、分享、成长,让自己和他人都能有所收获!😄 理解 ConfigFS 的核心数据结构对于深入使用和定制 ConfigFS 非…...
【04】RUST特性
文章目录 隐藏shadowing所有权ownership堆区&栈区所有权规则变量&数据Copy Trait与Drop TraitCopy TraitDrop Trait移动克隆函数参数与返回值的所有权参数引用可变引用悬垂引用slice生命周期隐藏shadowing 有点像同名覆盖 let mut guess = String::new();let guess: u3…...
c语言函数学习
C语言函数学习笔记:从入门到实践 一、什么是函数? 函数是C语言中用于封装特定功能的代码块,是模块化编程的核心。通过函数可以实现: 代码复用:避免重复编写相同逻辑 逻辑清晰:将复杂程序分解为多个小模块…...
LSTM的介绍
网上一些描述LSTM文章看的云里雾里,只是介绍LSTM 的结构,并没有说明原理。我这里用通俗易懂的话来描述一下。 我们先来复习一些RNN的核心公式: h t t a n h ( W h h t − 1 W x x t b h ) h_t tanh(W_h h_{t-1} W_x x_t b_h) httan…...
XML DOM
XML DOM XML DOM(Document Object Model)是一种用于访问和操作XML文档的标准方式。它提供了一种树形结构来表示XML文档,使得开发者能够方便地对XML数据进行读取、修改和操作。本文将详细介绍XML DOM的基本概念、结构、操作方法以及应用场景。 一、XML DOM的基本概念 XML …...
认识网络安全
一 网络攻击链 踩点-工具准备-载荷投递-漏洞利用-释放载荷-建立通道-目标达成 简化下: 目标侦察:准确识别目标,收集目标详细信息,比如 网络、 邮箱、员工、社会关系、对外提供服务、漏洞 信息等,为 后续攻击做准备。…...
华为支付-免密支付接入签约代扣场景开发步骤
一、预签约(服务器开发) 1.开发者按照商户模型调用预直连商户预签约或服务商预签约接口获取preSignNo构建签约信息参数contractStr。 为保证支付订单的安全性和可靠性需要对请求body和请求头PayMercAuth对象内的入参排序拼接进行签名。请参考排序拼接和…...
9.JVM-方法区
前言 这次所讲述的是运行时数据区的最后一个部分 从线程共享与否的角度来看 ThreadLocal:如何保证多个线程在并发环境下的安全性?典型应用就是数据库连接管理,以及会话管理 栈、堆、方法区的交互关系 下面就涉及了对象的访问定位 Person&a…...
【Linux Oracle】杂货铺 日常实用2024
1.跨服务器移动文件 passwd=^T^bxxxx `/usr/bin/expect <<-EOF set timeout -1 spawn scp -r ${BATCH_TIME} sxnhtc@192.168.3.x:${EXP_MCRO_DIR}/ expect "*password:" send "$passwd\r" interact expect eof EOF` curl -k -X GET https://192.16…...
深入理解指针初阶:从概念到实践
一、引言 在 C 语言的学习旅程中,指针无疑是一座必须翻越的高峰。它强大而灵活,掌握指针,能让我们更高效地操作内存,编写出更优化的代码。但指针也常常让初学者望而生畏,觉得它复杂难懂。别担心,本文将用通…...
Git 与 Git常用命令
Git 是一个开源的分布式版本控制系统,广泛用于源代码管理。与传统的集中式版本控制系统不同,Git 允许每个开发者在本地拥有完整的代码库副本,支持离线工作和高效的分支管理。每次提交时,Git 会对当前项目的所有文件创建一个快照&a…...
jupyterLab插件开发
jupyter lab安装、配置: jupyter lab安装、配置教程_容器里装jupyterlab-CSDN博客 『Linux笔记』服务器搭建神器JupyterLab_linux_布衣小张-腾讯云开发者社区 Jupyter Lab | 安装、配置、插件推荐、多用户使用教程-腾讯云开发者社区-腾讯云 jupyterLab插件开发教…...
IDEA+DeepSeek让Java开发起飞
1.获取DeepSeek秘钥 登录DeepSeek官网 : https://www.deepseek.com/ 进入API开放平台,第一次需要注册一个账号 进去之后需要创建一个API KEY,然后把APIkey记录保存下来 接着我们获取DeepSeek的API对话接口地址,点击左边的:接口…...
机器学习数学基础:19.线性相关与线性无关
一、线性相关与线性无关的定义 (一)线性相关 想象我们有一组向量,就好比是一群有着不同“力量”和“方向”的小伙伴。给定的向量组 α ⃗ 1 , α ⃗ 2 , ⋯ , α ⃗ m \vec{\alpha}_1, \vec{\alpha}_2, \cdots, \vec{\alpha}_m α 1,α 2…...
快速集成DeepSeek到项目
DeepSeek API-KEY 获取 登录DeekSeek 官网,进入API 开放平台 2. 创建API-KEY 复制API-KEY进行保存,后期API调用使用 项目中集成DeepSeek 这里只展示部分核心代码,具体请查看源码orange-ai-deepseek-biz-starter Slf4j AllArgsConstructo…...
Rocketmq 和 Rabbitmq ,在多消费者的情况下,可以实现顺序消费吗
在多消费者的情况下,RocketMQ 和 RabbitMQ 都可以实现顺序消费,但它们的实现机制和适用场景有所不同。以下是对两者的详细分析和对比: 1. RocketMQ 的顺序消费 1.1 实现机制 顺序消息:RocketMQ 支持顺序消息(Orderly …...
linux下安装【流媒体】SRS之安装与使用
一、 安装srs 这个是一个流媒体服务器。 1.1 github 获取源码 git clone https://github.com/ossrs/srs.git 或者下载国内的 git clone https://gitee.com/ossrs/srs 进去之后下载zip的 #直接使用当前最新的6.0release版本 ,我下载的是zip的 下载了之后上传到…...
Qt QSettings用法
一、概述 QSettings类是Qt框架中的一个重要类,它主要用于存储和访问应用程序的设置和配置。 二、QSettings的构造方式 1、基于组织名和程序名的构造方式(主要用于Windows注册表) 1、explicit QSettings(const QString &organization,c…...