USB主机枚举设备

这篇具有很好参考价值的文章主要介绍了USB主机枚举设备。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

https://space.bilibili.com/489340606/channel/collectiondetail?sid=896957
以下图片来自于沁恒微电子蔡亮工程师的讲课,对USB开发入门很有好处。

1. USB设备的组成结构

一个设备可以有多个配置,但同一时刻只能有一个生效。一个配置可以有多个接口,一个接口可以有多个端点。
USB主机枚举设备

1. 主机枚举设备----获取设备描述符

//主机请求-获取设备描述符
0x80,0x06,0x00,0x01,0x00,0x00,0x12,0x00	

//设备描述符
0x12,			// bLength,设备描述符长度,固定为18字节	
0x01,			//bDescriptorType,描述符类型为设备描述符
0x10,0x01,		//bcdUSB,USB协议的版本号,小端格式,BCD形式,0x0110,即V1.1版本
0x00,			//bDeviceClass,设备类,如果值为0,是告知主机设备类在接口描述符中
0x00,			//bDeviceSubClass,设备子类,取决于bDeviceClass,bDeviceClass为0时bDeviceSubClass必须为0
0x00,			//bDeviceProtocol,设备用的协议,取决于bDeviceSubClass,bDeviceSubClass为0时必须为0
0x08,			//bMaxPacketSize0,默认控制传输端点0的单次传输数据包净大小,单位是byte;低速设备只能是8,全速可以是8,16,32,64
0x86,0x1a,		//idVendor,制造商的ID号,向USB联盟申请
0xe1,0xe6,		//idProduct,产品ID号,制造商自己定
0x00,0x01,		//bcdDevice,该USB设备的固件版本号,制造商自己定
0x01,			//iManufacturer,制造商信息在字符串描述符中的序号;当非0值时,主机才会去请求。如果没有字符串描述符,该值直接填0即可
0x02,			//iProduct,制造商信息在字符串描述符中的序号;当非0值时,主机才会去请求。如果没有字符串描述符,该值直接填0即可
0x00,			//iSerialNumber,产品序列号在字符串描述符中的序号;当非0值时,主机才会去请求。如果没有字符串描述符,该值直接填0即可
0x01			// bNumConfi gurations,本设备支持的配置数量。最小为1,为1时说明只支持一种配置。

2. 主机枚举设备----设置设备地址

USB主机枚举设备

//主机请求----设置设备地址
0x00.0x05.0x02.0x00.0x00,0x00.0x00.0x00

USB设备插入主机后,默认地址都是0,主机给设备设置地址的范围是 1~127。
在设置新地址后,通讯均使用新地址进行。
当发生USB总线复位或者设备拔出再插入,地址自动回到默认地址0。

3. 主机枚举设备----获取配置描述符

配置描述符(Configuration Descriptor)规定了设备的特征和能力。一般单个配置已经足够了,但在驱动程序的支持下,带有多应用或多电源选择的设备可支持多重配置。且每次只有一个配置被激活。每个配置需要一个配置描述符,其中含有关于设备电源使用及所支持接口数的信息。

主机通过发送Get Descriptor请求,取得配置描述符及其附属描述符。
USB主机枚举设备USB主机枚举设备

  • bLength 以字节为单位的描述符大小(0x09)。
  • bDescriptorType 配置描述符类型,为CONFIGURATION (0x02)。
  • wTotalLength 配置返回的数据总长度。包括该配置返回的所有描述符(配置、接口、端点、和专用的类型或者专用的厂商描述符)的总长度。
  • bNumInterfaces 这个配置支持的接口数量,最小值为0x01。
  • bConfigurationValue 确认Get Configuration 和Set Configuration请求的配置,且必须为0x01或者更高值。取值为0的Set Configuration请求会使设备进入未配置状态(Not Configured state)
  • iConfiguration 描述这个配置的字符串描述符索引。若没有字符串描述符,这个字段的值为0。
  • bmAttributes 配置特性。

Bit 7:USB1.0协议中表示总线供电(Bus Powered),设置Bit 7 = 1表示由总线供电(Bus Powered)。其他协议该位保留(Reserved),必须设置为1。

Bit 6:自供电(Self-powered)。如果Bits 6 = 1,设备是自供电(Self-powered)的。

Bit 5 :远程唤醒(Remote Wakeup)。如果Bit 5 = 1,设备支持远程唤醒。

Bits 4…0:未使用,保留,必须为0。

  • bMaxPower当设备完全运行时,特定配置的USB设备从总线取得的最大功耗。

对于usb2.0,bMaxPower 以2mA为单位。如果设备要求200ma,则bMaxPower = 100 (0x64)。设备可请求的最大总线电流500mA。

对于增强型超高速(Enhanced SuperSpeed)设备,bMaxPower以8mA为单位。如果设备要求200ma,则bMaxPower = 25(0x19)。设备可请求的最大总线电流900mA。

当设备和主机支持USB Power Delivery Rev. 2.0,主机可以从PD Class Specific Descriptors检索设备的电源需求。

//主机请求一获取配置描述符
0x80,0x06,0x00,0x02,0x00,0x00,0x09,0x00

//配置描述符实例
0x09,		// bLength,,描述符长度
0x04,		// bDescriptorType,描述符类型为配置描述符
0x22,0x00,	// wTotalLength,包含配置描述符、接口描述符、hid类描述符、端点描述符的集合的总长度。主机获取该值后会再次发起请求,重新获取完整的配置描述符。主机第一次请求都是只请求9个字节的配置描述符,第二次请求才是包含配置描述符、接口描述符、hid类描述符、端点描述符的集合。两次请求命令相同,只是要请求的字节数不同。
0x01,		// bNuInterfaces,该配置支持的接口数量
0x01,		// bConfigurationvalue,配置值。在一个设备有多个配置时,主机使用该值以区分某一个配置。
0x00,		// iConfiguration,字符串描述符索引
0xA0		// bmittributes,位图信息,每个位有自己的含义。如是否支持唤醒、是否支持BUS供电等。0xA0表示Bus Powered,且Remote Wakeup。
0x32// MaxPower,设备要消耗的电流值,以2mA为单位。0x32=50,即50*2=100mA。

主机获取配置描述符后,解析到wTotalLength值,即配置描述符集合总长度,会再次向设备请求该长度的配置描述符。

//主机请求----获取配置描述符集合
0x80,0x06,0x00,0x02,0x00,0x00,0x22,0x00//注意,这里请求的长度是整个集合的长度,不是仅限于配置描述符的9bytes

//配置描述符集合
//***************************************配置描述符*************************************//
	0x09,		// bLength,,描述符长度
	0x04,		// bDescriptorType,描述符类型为配置描述符
	0x22,0x00,	// wTotalLength,包含配置描述符、接口描述符、hid类描述符、端点描述符的集合的总长度。主机获取该值后会再次发起请求,重新获取完整的配置描述符。主机第一次请求都是只请求9个字节的配置描述符,第二次请求才是包含配置描述符、接口描述符、hid类描述符、端点描述符的集合。两次请求命令相同,只是要请求的字节数不同。
	0x01,		// bNuInterfaces,该配置支持的接口数量
	0x01,		// bConfigurationvalue,配置值。在一个设备有多个配置时,主机使用该值以区分某一个配置。
	0x00,		// iConfiguration,字符串描述符索引
	0xA0		// bmittributes,位图信息,每个位有自己的含义。如是否支持唤醒、是否支持BUS供电等。0xA0表示Bus Powered,且Remote Wakeup。
	0x32// MaxPower,设备要消耗的电流值,以2mA为单位。0x32=50,即50*2=100mA。


//**********************************接口描述符,键盘功能**********************************//
    0x09,	                                 //bLenght,描述符长度
    0x04,                                   //bDescriptorType,描述符类型,0x04为接口描述符
    0x00,                                   //bInterfaceNumber,接口数量
    0x00,                                   //bAlternateSetting,可选设置
    0x01,                                   //bNumbEndpoints,本接口下的端点数量
    0x03,                                   //bInterfaceClass,接口类型,0x03为hid类
    0x01,                                   //bInterfaceSubClass,接口子类,是否支持BIOS,1支持,0不支持
    0x01,                                   //bInterfaceProtocol,接口协议,00其他,01键盘,02鼠标
    0x00,                                   //iInterface,接口描述在字符串描述符的索引,0为无该项    
    
//************************************HID类描述符************************************//
    0x09,                                   //bLenght,描述符长度
    0x21,                                   //bDescriptorType,描述符类型,0x21为HID描述符
    0x11,0x01,                              //bcdHID,HID协议版本号,0x0111,BCD格式,表示V1.11
    0x00,                                   //bCountryCode,硬件设备所在国家的国家代码​,如果不限制,该字段为0
    0x01,                                   //bNumDescriptors,下级描述符的数量。可以是报告描述符,也可以说是物理描述符。该值至少为1,表示至少有一个报告描述符。
    0x22,                                   //bDescriptorType,下级描述符的类型。0x22是报告描述符。
    0x3f,0x00,                              //wDescriptorLength,下级描述符的长度,0x3f是63bytes
    
    
    //************************************端点描述符************************************//
    0x07,                                   //bLenght,描述符的长度,7bytes
    0x05,                                   //bDescriptorType,描述符的类型,0x05是端点描述符
    0x81,                                   //bEndpointAddress,端点的地址,Bit7决定该端点的方向,1是IN,0是OUT(对于控制端点可以忽略);Bit6-4,保留;BIt3-0:端点号;该处设置为0x81,即IN(设备上传主机)的1号端点
    0x03,                                   //bmAttributes,端点属性.Bit7-2保留(同步有定义)BIt1-0:00控制,01同步,02批量,03中断。
    EPI_IN_SIZE,0x00,                       //wMaxPacketSize,端点收发信息包的最大长度,单位是字节。#define EPI_IN_SIZE 0x08
    0x0A                                    //bInterval,传输间隔   1:每1个帧    2:每2个帧    4:每4个帧    8:每8个帧。对于全速USB,总线间隔是一帧,一帧的长度是 1 毫秒。0x0A设置为10,则表示主机每隔10ms向端点要一次数据。

hid描述符
USB主机枚举设备

4. 主机枚举设备----激活设备配置

USB主机枚举设备

//主机请求-激活设备配置
0x00,0x09,0x01,0x00,0x00,0x00,0x00,0x00//0x01表示告知设备使用1号配置

4. 主机枚举设备----HID类设备主机常见类命令请求

USB主机枚举设备类命令请求走控制传输通道。

//主机请求----设置HID设备上传速率
0x21,0x0A,0x00,0x00,0x00,0x00,0x00,0x00//0x00表示告知设备在有数据改变的时候再上传

//主机请求----下传报表 (数据)
0x21,0x09,0x00,0x00,0x00,0x00,0x00,0x00//用于点亮键盘上的LED灯,如Caps Lock键灯、Num键灯等

5. 主机枚举设备----获取报表描述符(HID类设备独有)

报表描述符定义了HID类设备的数据格式和用法。主机只有获取了报表描述符,才能正确地解析数据。报表描述赋予了HID类设备更大的弹性,可以组合成各种不同的功能。
报表描述符有自己的格式,与USB其他描述符完全不一致。HID Report 描述符,不像其他的描述符,仅仅是一个简单的一组数据。其主要由 Item 组成的,其定义依赖于 Report。HID 规范,定义了 3 种类型 的 Item:Main Item、Global Item、Local Item。
USB主机枚举设备

//主机请求----获取报表描述符
0x81,0x06,0x00,0x22,0x00,0x00,0xFF,0x00

//键盘设备上传报表描述符内容
0x05,0x01,// Usage Page,Global, Generic Desktop
0x09,0x06,//Usage, Local, KeyBoard 
0xA1,0x01,// Collection,Main, Application

    0x05,0x07,//Usage Page, Global, KeyBoard    
    
    //第1字节(8个功能键)
    0x19,0xe0,// Local Usage Min (KeyBoard LeftControl)........... (224)
    0x29,0xe7,// Local Usage Max (KeyBoard Right GUI)............. (231)
    0x15,0x00,// Global Logical Min............................... (0)
    0x25,0x01,// Global Logical Max............................... (1) 
    0x95,0x08,// Global ReportCount............................... (8) 
    0x75,0x01,// Global ReportSize.................................(1) 
    0x81,0x02,// Main Input(Data,Var,Abs).............(Data, Variable, asolute)
    
    //第2字节(补充的常量,保留)
    0x95,0x01,// Global ReportCount............ (1)
    0x75,0x08,// Global ReportSize............. (8)
    0x81,0x01,// Main Input...................(Constant)
    
    //第3字节(用于键盘点灯,3bit对应3个灯。注意,本例没有下传端点,所以下传数据走控制端点0。这里定义了下传数据的意义,主机按此发送,设备按此解析并做出相应点灯动作)
    0x95,0x03,// Global ReportCount.................. (3)
    0x75,0x01,// Global ReportSize................... (1)
    0x05,0x08,//Usage Page ..........................( LEDs )
    0x19,0x01,//Usage Minimum........................ (1)
    0x29,0x03.//Usage Maximum.........................(3)
    0x91,0x02,//Main Output...........................(Data, Variable, solute)
    //第3字节(再补5bit,将上面变成1个字节)
    0x95,0x05,// Global ReportCount.................. (5)
    0x75,0x01,// Global ReportSize................... (1)
    0x91,0x01,// Main Output..........................(Constant)
    
    
    //第4-9字节(6个字节,数组形式。键盘上剩余101个按键,键盘是阵列方式,不是一个按键占一个bit)
    0x95,0x06,// Global ReportCount................. (6)
    0x75,0x08,// Global ReportSize.................. (8)
    0x15,0x00,// Global Logical Min................. (0)
    0x25,0x65,//Global Logical Max.................. (101)
    0x05,0x07,//Usage Page........................... (Keyboard/Keypad)
    0x19,0x00,// Local Usage Min..................... (0)
    0x29,0x65,// Local Usage Max..................... (101)
    0x81,0x00,// Main Input......................... (Data,Ary)
0xc0      // Main, End collection
  • Main Item

HID 规范定义了 5 种 Main Item Tag:

与数据关联的 Input、Output、Feature;
Input Item:描述由一个或多个物理控件提供的输入数据的信息。
Output Item:描述由一个或多个物理控件提供的输出数据的信息。
Feature Item:描述设备输入和输出不用于最终用户 — 例如,软件功能或控件面板切换。

与数据无关的Collection、End Collection:
Collection Item:标识两个或多个数据(input、output或feature)之间的关系。
End Collection:当 Collection 项打开一个数据集合时,End Collection 项关闭一个集合

Main Item 定义如下:其中bit7~bit2 表示 Item Tag 和 Type,nn 表示Item 后跟的data 域数据长度。比如nn为01,说明后跟1个字节数据;nn为10,说明后跟2个字节数据。
USB主机枚举设备
Input/Output/Feature​

bit0:表示是数据还是常量
bit1:表示是数组还是变量字段
bit2:表示是绝对数值(基于固定原点)还是相对数值(指示上次报告值变化)
bit3:指示当达到极高或极低值时数据是否“翻滚”
bit4:表示来自设备的原始数据是否经过某种方式处理,不再代表测量的数据与报告的数据之间的线性关系
bit5:指示控件是否具有在用户未与控件进行物理交互时将返回的首选状态。
bit6:指示控件是否处于不发送有意义数据的状态。空状态的一种可能用途是用于需要用户与控件进行物理交互以使其报告有用的数据。
bit7:保留
bit8:指示控件发出固定大小的字节流。数据字段的内容由应用程序决定。缓冲区的内容不会解释为单个数字量。由缓冲字节项定义的报表数据必须在8位边界上对齐。
bit31-9:保留

​Collection/End Collection​

Physical:物理集合用于表示在一个几何点收集的数据点的一组数据项。这对于可能需要将测量或感测数据集与单个点相关联的感测设备很有用。它并不表示一组数据值来自一个设备,例如键盘。在报告多个传感器位置的设备的情况下,物理集合用于显示哪些数据来自每个单独的传感器。
Application:用于识别单个设备中服务于不同条目的的项目组。常见的例子是键盘或鼠标。带有集成指针设备的键盘可以定义为两个不同的应用程序集合。数据报告通常(但不一定)与应用程序集合相关联(每个应用程序至少有一个报告 ID)
Logcal:当一组数据项形成复合数据结构时,将使用逻辑集合
Report:定义一个包含报表中所有字段的逻辑集合。此集合中将包含唯一的报告 ID。应用程序可以轻松确定设备是否支持某个功能。请注意,可以为报告集合声明任何有效的报告 ID 值。
Name dArray:命名数组是包含选择器用法数组的逻辑集合。对于给定的功能,类似设备使用的选择器集可能会有所不同。在记录硬件寄存器时,字段的命名是常见的做法。要确定设备是否支持特定功能(如状态),应用程序可能必须先查询几个已知的状态选择器用法,然后才能确定设备是否支持状态。Named Array 用法允许对包含选择器的 Array 字段进行命名,因此应用程序只需查询 Status 用法即可确定设备支持状态信息。
Usage Switch:是一个逻辑集合,用于修改它所包含的用法的含义。
Usage Modifier:修改附加到包含集合的用法的含义。用法通常为控件定义单一操作模式。使用修饰符允许扩展控件的操作模式。
07~7f:扩展
80~ff:厂商自定义
  • Global Item

全局项目主要用来选择用途页(Usage Page),定义数据域的长度(Report Count)、数量(Report Size)、报告ID(ReportId)等。

全局项目描述对后续的所有项目有效,除非遇到有新的全局项目。

Usage Page(用途页)
Logical Minimum(逻辑最小值)
Logical Maxinum(逻辑最大值)
Physical Minimum(物理最小值)
Physical Maximum(物理最大值)
Report Size:数据域大小,表示每个数据域有多少位
Report Count:数据域有多少个数据域。
ReportId:报告ID
Unit Exponent
Unit:单位
PUSH:将全局项状态表的副本放置在堆栈上
POP:用堆栈中的顶部结构替换全局项状态表。

Global Item 定义如下:其中bit7~bit2 表示 Item Tag 和 Type,nn 表示Item 后跟的data 域数据长度。
USB主机枚举设备USB主机枚举设备

Usage Page:指定设备功能。 Logical Minimum与 Logical
Maximum项目:定义报表的变量(Variable)或阵列(Array) 数据的限制范围,此限制范围以逻辑单位来表示。 Physical
Minimum和Physical Maximum:定义变量或数组的限制范围,此范围以物理单位来表示 Uint
Exponent:定义数值是基于10的基数 Unit:单位 Report Size:指定报表数据区域占的位数 Report
Count:报表数据区域数目 Report ID:报表ID Push:将global 项目状态表送入堆栈 Pop:从堆栈中恢复项目状态表

  • Local Item

Local item标记定义控件的特征。这些项目不会影响到下一个main item。如果一个主项定义了多个控件,则它前面可能有几个类似的local item。

Usage
Usage Minimum
Usage Maximum       

Local Item 定义如下:其中bit7~bit2 表示 Item Tag 和 Type,nn 表示Item 后跟的data 域数据长度。
USB主机枚举设备

Usage:用法索引值,表示对于项目或者集合建议的用法。用于当一个项目描述多个控制,对每一个变量和数组元素都有建议的用法 Usage
Minimum与 Usage Maximum项目:定义阵列和位图中控制第一个和最后一个用法 Designator
Index:确定用于控制的实体,指向物理描述符的目标 Designator Minimum与 和 Designator
Maximum项目:定义阵列和位图中控制起始和终止索引 String Index:确定字符串描述符索引值 String Minimum与 和
String Maximum项目:定义阵列和位图中字符串索引最小值和最大值
Delimiter:定义一组Local 项目的开始和结束。1=开始, 0=结束。

注意:报表上传字节数大于端点一次传输最大字节数时,会自动分包传输。USB主机会等待字节数达到报表字节数时才会从驱动层上传数据至应用层解析。文章来源地址https://www.toymoban.com/news/detail-461619.html

到了这里,关于USB主机枚举设备的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C语言 联合体验证 主机字节序 +枚举

    枚举(Enumeration)是一种在编程语言中表示一组具名 常量 的数据类型。 枚举常常用于定义一组相关的离散值,比如颜色、星期几、月份等。 爱编程的大丙

    2024年02月04日
    浏览(38)
  • 第9课【USB协议】USB总线 接口 端点 管道 数据包 枚举 STM32_USB-FS-Device_Lib V4.1.0

    USB(Universal Serial Bus)通常指通用串行总线,日常生活中常见的计算机USB集线器控制器,手机等终端设备,USB线缆等,都是用了USB进行连接。USB技术体系规定了USB总线规范和USB通信协议,这意味着只要遵循USB技术要求制作的设备,都能通过USB总线进行通信。其中USB2.0规范是目

    2024年02月03日
    浏览(37)
  • 正在解析主机 mirrors.aliyun.com (mirrors.aliyun.com)... 失败:未知的名称或服务。wget: 无法解析主机地址 “mirrors.aliyun.com”

    找到如下配置文件:/etc/resolv.conf   添加如下源地址: 保存退出。就可以下载啦!  

    2024年02月08日
    浏览(51)
  • 在Ubuntu主机上使用USB无线网卡

    前言 上个月冲动消费攒了一台华擎DeskMini X300小主机,装了Ubuntu 22.04,用来解决M1芯片MacBook Pro上无法编译x86_64架构的StarRocks和ClickHouse的问题。 因为没什么特殊需求所以没用Zen 3的5600G / 5700G 当时图便宜买了不带无线网卡的版本(书房有网线,并且自带的AC3168比较emm)。但是最近

    2024年02月12日
    浏览(36)
  • STM32 USB OTG主机模式的实现方法

    为了实现STM32的USB OTG主机模式,我们首先需要了解一些基本概念和原理,然后进行相应的硬件连接和软件编程。 在这篇文章中,我们将介绍如何在STM32微控制器上实现USB OTG主机模式,并提供相应的代码示例。 1. STM32 USB OTG主机模式概述 USB OTG(On-The-Go)是一种USB规范,允许设

    2024年02月22日
    浏览(42)
  • linux usb设备网络共享 usb/ip

    USB设备的网络共享可以通过USB/IP来实现, USB/IP把USB I/O信息封装成TCP/IP格式在网络端传输 ,可以实现usb的全部功能,且跨平台,是个透明的设备共享机制。 -b 后为上面列出的busid ip地址和端口号换成自已的 可以看出串口usb设备已经在客户端显示出来了

    2024年01月23日
    浏览(51)
  • WIN10笔记本偶然会出现插入USB设备的时候报错:无法识别的usb设备,前一个设备不正常......

    WIN10笔记本出现报错:无法识别的usb设备前一个设备不正常,网上很多方法都不管用,最后验证这种方法是可以的!!!! 问题根因:可能由于静电,主板电压和系统设置等原因导致 【解决方案】: 首先按下快捷组合键【WIN+X】,选择【电源选项】,然后点击【更改计划的设

    2024年02月11日
    浏览(51)
  • 三、视频设备的枚举以及插拔检测

            本章主要讲述,如何获取设备名称以及guid,采集设备的采集格式识别,设备的插拔         设备列表以及属性的获取使用的directshow(后续的MediaFoundation无法获取OBS摄像头)         设备的插拔使用的是QT 捕获系统消息,捕获到设备插拔后,重新获取下设备列表(这里并

    2024年02月07日
    浏览(47)
  • 【Linux】编写COM口和USB口的规则文件(.rules)

            当外接存储设备(如:U盘、机械硬盘等)时,由于路径/dev下并没有存储新设备的设备节点、规则文件等,udev会给新的存储设备按照内核的分配规则分配设备节点诸如:/dev/sda(如U盘)、/dev/sdb(如机械硬盘)等临时设备节点, 这些临时设备节点是按照外接设备的

    2024年02月13日
    浏览(46)
  • stlink 未知usb设备 设备描述符请求失败

    一般是STLINK烧了,可以用STM32的串口下载程序: 只可以用UAART_1:PA9,PA10 需要软件:FlyMcu ① PA9:为TX,要接CH340的RX PA10:为RX,要接CH340的TX ② 再给STM32通电3.3V ③ 设置相同相同波特率,并载入HEX文件 ④ STM32上boot0跳帽接高,并按下复位键,点击开始编程,完成后 ⑤ 跳帽接boot0低

    2024年02月13日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包