1 感性认识
在学习USB CDC之前,先来看下实际日常生活中真实的设备,感官认识下真实应用。下面是我手头的几个,都是通过USB CDC协议实现了虚拟COM口。
为什么叫虚拟COM呢?简单介绍下介绍下物理COM和LPT口:
在比较古老的电脑主板上的COM和LPT接口,现在基本已经淘汰
- COM:串行端口 (Serial Port)。
- LPT:并行端口 (Parallel Port)。
这里简单介绍不再详细展开,感兴趣自行查找深度了解下。
到这就知道为什么说是虚拟COM和LPT了,因为是通过USB协议模拟的,另外可以发现不仅可以模拟串口,还可以模拟SPI、CAN、ETH等等各类的外设接口。
- USB转SPI
- USB转CAN
- USB转ETH
NOTE:
不一定会显示在端口(COM和LTP)下哦,比如:ETH2USB会显示再网络适配器下
感官有一定认识后,下面来理论学习下。
2 简介
USBCDC(Communications Device Class,通信设备类)是 USB 标准中定义的一个设备类别,用于支持通信设备通过 USB 接口与主机进行数据交换和控制。它为标准串口、调制解调器、网络适配器等通信设备提供了统一的识别、配置和数据传输框架,从而实现设备在 USB 总线上的即插即用和互操作性。
该类是USB2.0标准下的一个子类,定义了通信相关设备的抽象集合,另外可以看出众多外设都可以通过USB cdc实现,具体的类协议标准,也可以在USB-IF官网找到。
之前在USB2.0协议深入理解——从零开始学习USB2.0协议(三)3.9节介绍过USB2.0的标准类代码,可知,调制解调器、以太网/WIFI适配器接口类代码0x02,CDC-Data类是0x0A。
1、设备分类与结构
在 USB 描述符体系中,CDC 设备通常包含以下接口类:
- 通信接口类(Communication Interface Class)
- 负责设备管理、呼叫控制与事件通知。
- 通常包含一个中断 IN 端点,用于向主机通知状态变化(如连接建立、速率更改等)。
- 数据接口类(Data Interface Class)
- 负责实际的数据传输。
- 通常包含批量(Bulk)输入与输出端点,用于高效传输数据;某些场景也可能使用同步(Isochronous)端点。
2、支持的设备类型
CDC 可用于实现多种通信设备,例如:
- 虚拟串口(USB 转串口适配器)
- USB 调制解调器
- USB 网卡(如基于 CDC-ECM、CDC-NCM 子类)
- ISDN 终端适配器
ADSL/Cable 调制解调器
3、端点配置
典型的 CDC 设备包含以下端点:
- 中断 IN 端点:用于向主机发送通知(如链路状态变化)。
- 批量 IN/OUT 端点:用于双向数据传输。
- (某些子类可能使用同步端点以满足实时性要求。)
2.1 描述符
和HID类接口一样,CDC类设备除了包含标准标准描述符,还有CDC功能描述符,由于CDC兼容很多类型,所以CDC功能描述符也是相对较为复杂,包含:
CDC功能描述符、CDC头部功能描述符、CDC呼叫管理功能描述符、CDC 抽象控制管理功能描述符、CDC 直连线路管理功能描述符、CDC 电话铃声功能描述符…
当然这些描述符都是为了描述设备功能的,device按照描述符格式来描述功能,host则按照描述符解析从device获取来的描述符,来适配驱动;下图是CDC描述符的关系图:
2.1.1 通用格式
| 偏移 | 字段名 | 大小 | 值/类型 | 描述 |
|---|---|---|---|---|
| 0 | bFunctionLength | 1 | 数值 | 此描述符的大小 |
| 1 | bDescriptorType | 1 | 常量 | CS_INTERFACE,见表1 |
| 2 | bDescriptorSubtype | 1 | 常量 | 功能描述符标识符(ID),见表2 |
| 3 | (function specific data0) | 1 | 可变 | 第一个功能特定数据字节 |
| … | … | … | … | … |
| N+2 | (function specific data N-1) | 1 | 可变 | 第N个功能特定数据字节 |
其中:
- bDescriptorType字段的类型值(
表1)
| 描述符类型 | 值 |
|---|---|
| CS_INTERFACE | 24h |
| CS_ENDPOINT | 25h |
- bDescriptorSubtype字段的类型值(
表2)
| 描述符子类型 | 通信接口描述符 | 数据接口描述符 | 功能描述 |
|---|---|---|---|
| 00h | 是 | 是 | 头部功能描述符(标记功能描述符集合的开始) |
| 01h | 是 | 否 | 呼叫管理功能描述符 |
| 02h | 是 | 否 | 抽象控制管理功能描述符 |
| 03h | 是 | 否 | 直连线路管理功能描述符 |
| 04h | 是 | 否 | 电话振铃功能描述符 |
| 05h | 是 | 否 | 电话呼叫和线路状态报告能力功能描述符 |
| 06h | 是 | 否 | 联合功能描述符 |
| 07h | 是 | 否 | 国家选择功能描述符 |
| 08h | 是 | 否 | 电话操作模式功能描述符 |
| 09h | 是 | 否 | USB终端功能描述符 |
| 0Ah | 是 | 否 | 网络通道终端描述符 |
| 0Bh | 是 | 否 | 协议单元功能描述符 |
| 0Ch | 是 | 否 | 扩展单元功能描述符 |
| 0Dh | 是 | 否 | 多通道管理功能描述符 |
| 0Eh | 是 | 否 | CAPI控制管理功能描述符 |
| 0Fh | 是 | 否 | 以太网网络功能描述符 |
| 10h | 是 | 否 | ATM网络功能描述符 |
| 11h-FFh | N/A | N/A | 保留(将来使用) |
而特定的功能需要根据对应的bDescriptorSubtype字段,来区分出的不同功能描述符来定义,鉴于描述符众多,篇幅有限,这里仅仅罗列几个,需要开发可以参考协议。
2.1.2 头部功能能描述符
**头部功能描述符(Header Functional Descriptor)**用于标识该接口及其相关描述符所遵循的CDC规范版本,是所有CDC类特定描述符的起始部分。
| 偏移 | 字段名 | 大小 | 值/类型 | 描述 |
|---|---|---|---|---|
| 0 | bFunctionLength | 1 | 0x5(固定) | 此描述符的字节数 |
| 1 | bDescriptorType | 1 | number | CS_INTERFACE 描述符类型 |
| 2 | bDescriptorSubtype | 1 | 0x00(固定) | 头部功能描述符子类型 |
| 3 | bcdCDC | 2 | 数值 | 遵循的USB通信设备类规范版本号(BCD编码) |
2.1.3 CDC 呼叫管理功能描述符
**呼叫管理功能描述符(Call Management Functional Descriptor)**用于描述设备是否支持自身呼叫管理、是否可通过数据类接口收发呼叫管理信息,以及相关数据接口号。
| 偏移 | 字段名 | 大小 | 值/类型 | 描述 |
|---|---|---|---|---|
| 0 | bFunctionLength | 1 | 0x5(固定) | 此功能描述符的字节数 |
| 1 | bDescriptorType | 1 | number | CS_INTERFACE 描述符类型 |
| 2 | bDescriptorSubtype | 1 | 0x01 | 呼叫管理功能描述符子类型 |
| 3 | bmCapabilities | 1 | Bitmap | 本配置支持的能力: D7…D2: 保留,置零 D1: 0-仅通过通信类接口收发呼叫管理信息;1-可通过数据类接口收发呼叫管理信息 D0: 0-设备不自行处理呼叫管理;1-设备自行处理呼叫管理。 若D0为0,D1值被忽略,且为兼容性应置零。 |
| 4 | bDataInterface | 1 | number | 可选用于呼叫管理的数据类接口的接口号(配置中的零基索引) |
2.1.4 CDC 抽象控制管理功能描述符
**抽象控制管理功能描述符(Abstract Control Management Functional Descriptor)**用于标识设备支持哪些CDC ACM(如虚拟串口)相关的标准请求和通知,主机据此决定可用的控制命令。用于描述通信类接口(SubClass为抽象控制模型,Abstract Control Model)所支持的命令。它只能出现在接口描述符的类特定部分。
| 偏移 | 字段名 | 大小 | 值/类型 | 描述 |
|---|---|---|---|---|
| 0 | bFunctionLength | 1 | 0x4(固定) | 此功能描述符的字节数 |
| 1 | bDescriptorType | 1 | number | CS_INTERFACE 描述符类型 |
| 2 | bDescriptorSubtype | 1 | 0x02(固定) | 抽象控制管理功能描述符子类型 |
| 3 | bmCapabilities | 1 | Bitmap | 本配置支持的能力位图(位为0表示不支持该请求): D7…D4: 保留,置零 D3: 1-支持Network_Connection通知 D2: 1-支持Send_Break请求 D1: 1-支持Set_Line_Coding、Set_Control_Line_State、Get_Line_Coding请求和Serial_State通知 D0: 1-支持Set_Comm_Feature、Clear_Comm_Feature、Get_Comm_Feature请求 |
2.1.5 CDC 联合功能描述符
**Union Functional Descriptor(联合功能描述符)**用于将多个接口(如通信接口和数据接口)组织为一个功能单元,便于主机识别和统一管理。主控接口可对整个组进行操作和接收通知。
联合功能描述符用于描述一组接口之间的关系,这些接口可以被视为一个功能单元。它只能出现在接口描述符的类特定部分。
在这组接口中,有一个接口被指定为主控接口(master interface),可以通过该接口对整个组进行操作或接收通知。组内的接口可以包括通信类、数据类或其他任何有效的USB接口类(如音频、HID、监控等)。
| 偏移 | 字段名 | 大小 | 值/类型 | 描述 |
|---|---|---|---|---|
| 0 | bFunctionLength | 1 | number | 此功能描述符的字节数 |
| 1 | bDescriptorType | 1 | number | CS_INTERFACE 描述符类型 |
| 2 | bDescriptorSubtype | 1 | 0x06(固定) | 联合功能描述符子类型 |
| 3 | bMasterInterface | 1 | number | 作为主控(master)或控制接口的通信类或数据类接口号(bInterfaceNum,零基) |
| 4 | bSlaveInterface0 | 1 | number | 第一个从属(slave)或关联接口的接口号(bInterfaceNum,零基) |
| … | … | … | … | … |
| N+3 | bSlaveInterfaceN-1 | 1 | number | 第N-1个从属或关联接口的接口号 |
以上简单罗列了4个CDC功能描述符,更多的可以参考协议spec,这里不再一一列举。后续会用一个USB模拟串口实例再来看下描述符具体使用。
2.3 特定类请求
之前由介绍过USB2.0的标准设备请求(请求格式和标准请求),但是作为特定的CDC类,只有标准请求是无法完成设备枚举的,所以就需要特定类请求,下面就来学习了解下CDC的特定类请求。
USB通信接口类(Communication Interface Class)支持一系列类特定请求,用于设备管理、控制、配置和状态查询。这些请求通过管理元素(Management Element)发送,适用于不同的设备视图。
2.3.1 请求格式
实际和标准请求格式是基本一样的,只是在对应位域字段、请求命令以及内容上的不同,另外多了data字段,如下:
| 偏移量 | 字段 | 大小 | 值 | 描述 |
|---|---|---|---|---|
| 0 | bmRequestType | 1 | Bitmap | 请求特性: •D7:数据传输方向 0= 主机到设备1= 设备到主机•D6…5:请求类型 00= 标准01= 类10= 厂商11= 保留•D4…0:接收方 00000= 设备00001= 接口00010= 端点00011= 其他00100…11111= 保留 |
| 1 | bRequest | 1 | number | 具体的请求编号(参见表3) |
| 2 | wValue | 2 | number | 一个字长(2字节)的字段,其含义根据具体请求而变化 |
| 4 | wIndex | 2 | 索引或偏移 | 一个字长(2字节)的字段,其含义根据具体请求而变化;通常用于传递一个接口或端点的索引 |
| 6 | wLength | 2 | 计数 | 如果存在数据阶段,则表示要传输的字节数 |
| 7 | data | n | 值 | 可选的数据阶段内容。此部分并非标准SETUP数据包(固定8字节)的一部分,而是用于表示后续数据阶段可能传输的、长度由wLength指定的数据块。 |
其中
bmRequestType字段,请求类型
如果是标准请求则D6-5=00,而类请求D6-5=01。
其他和标准请求一样,参考之前在USB2.0协议深入理解——从零开始学习USB2.0协议(三)。bRequest字段,请求code(
表3)
| 请求名称 | 代码值(十六进制) | 请求名称 | 代码值(十六进制) |
|---|---|---|---|
| SEND_ENCAPSULATED_COMMAND | 00h | GET_OPERATION_PARMS | 33h |
| GET_ENCAPSULATED_RESPONSE | 01h | SET_LINE_PARMS | 34h |
| SET_COMM_FEATURE | 02h | GET_LINE_PARMS | 35h |
| GET_COMM_FEATURE | 03h | DIAL_DIGITS | 36h |
| CLEAR_COMM_FEATURE | 04h | SET_UNIT_PARAMETER | 37h |
| SET_AUX_LINE_STATE | 10h | GET_UNIT_PARAMETER | 38h |
| SET_HOOK_STATE | 11h | CLEAR_UNIT_PARAMETER | 39h |
| PULSE_SETUP | 12h | GET_PROFILE | 3Ah |
| SEND_PULSE | 13h | SET_ETHERNET_MULTICAST_FILTERS | 40h |
| SET_PULSE_TIME | 14h | SET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER | 41h |
| RING_AUX_JACK | 15h | GET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER | 42h |
| SET_LINE_CODING | 20h | SET_ETHERNET_PACKET_FILTER | 43h |
| GET_LINE_CODING | 21h | GET_ETHERNET_STATISTIC | 44h |
| SET_CONTROL_LINE_STATE | 22h | SET_ATM_DATA_FORMAT | 50h |
| SEND_BREAK | 23h | GET_ATM_DEVICE_STATISTICS | 51h |
| SET_RINGER_PARMS | 30h | SET_ATM_DEFAULT_VC | 52h |
| GET_RINGER_PARMS | 31h | GET_ATM_VC_STATISTICS | 53h |
| SET_OPERATION_PARMS | 32h |
可以看出CDC特定类请求是很多的,这里简单列举几个,其他的可以参考spec。
2.3.2 CDC SendEncapsulatedCommand请求
SendEncapsulatedCommand用于向通信类接口发送一条“封装命令”,命令内容和格式由该接口支持的控制协议(如AT命令、PPP、以太网等)决定。
常用于调制解调器、以太网等CDC设备的主机与设备间的协议命令下发。
| 字段 | 值/说明 |
|---|---|
| bmRequestType | 0x21 (00100001B) • 方向: 主机到设备 • 类型: 类 • 接收者: 接口 |
| bRequest | 0x00 (SEND_ENCAPSULATED_COMMAND) |
| wValue | 0x0000 |
| wIndex | 接口号(Interface Number) |
| wLength | 数据长度(Data阶段下发的命令长度,单位字节) |
| Data | 控制协议命令内容(如AT命令、PPP帧等,具体由设备支持的协议决定) |
示例,比如主机向CDC解制调节器接口发送AT命令,就可以是以下格式:
bmRequestType:0x21bRequest:0x00wValue:0x0000wIndex:0x0001(假设接口号为1) wLength:4Data:“AT\r\n”(ASCII码)2.3.3 CDC GetEncapsulatedResponse请求
GetEncapsulatedResponse用于从通信类接口获取“封装命令”的响应数据。
通常与SendEncapsulatedCommand配对使用,主机先发命令,再用此请求取回设备响应。
| 字段 | 值/说明 |
|---|---|
| bmRequestType | 0xA1 (10100001B) 方向:设备到主机,类型:类,接收者:接口 |
| bRequest | 0x01 (GET_ENCAPSULATED_RESPONSE) |
| wValue | 0x0000 |
| wIndex | 接口号 |
| wLength | 期望读取的最大数据长度(主机分配的缓冲区大小) |
| Data | 设备返回的响应内容(协议相关) |
示例,主机请求调制解调器的AT命令响应:
bmRequestType:0xA1bRequest:0x01wValue:0x0000wIndex:0x0001wLength:64(假设主机准备读取最多64字节) Data:设备返回的响应(如”OK\r\n”)2.3.4 CDC SetLineCoding
SetLineCoding用于设置异步线路字符格式化属性,适用于异步字节流数据类接口和端点。
主机通过此请求配置数据传输的格式参数,如波特率、数据位、停止位、奇偶校验等,影响主机到设备和设备到主机的双向数据传输。
| 字段 | 值/说明 |
|---|---|
| bmRequestType | 0x21 (00100001B) 方向:主机到设备,类型:类,接收者:接口 |
| bRequest | 0x20 (SET_LINE_CODING) |
| wValue | 0x0000 |
| wIndex | 接口号 |
| wLength | Line Coding Structure 的大小(通常为7字节) |
| Data | Line Coding Structure(见下结构体code) |
typedefstruct_LINE_CODING{uint32_tdwDTERate;// 波特率(如9600, 19200, 38400等)uint8_tbCharFormat;// 停止位(0:1位, 1:1.5位, 2:2位)uint8_tbParityType;// 奇偶校验(0:无, 1:奇, 2:偶, 3:标记, 4:空格)uint8_tbDataBits;// 数据位(5,6,7,8,16)}LINE_CODING;2.3.5 CDC GetLineCoding
GetLineCoding 用于获取当前配置的线路编码参数。
主机通过此请求查询设备当前的异步数据传输格式设置,包括波特率、数据位、停止位、奇偶校验等参数。
| 字段 | 值/说明 |
|---|---|
| bmRequestType | 0xA1 (10100001B) 方向:设备到主机,类型:类,接收者:接口 |
| bRequest | 0x21 (GET_LINE_CODING) |
| wValue | 0x0000 |
| wIndex | 接口号 |
| wLength | Line Coding Structure 的大小(7字节) |
| Data | Line Coding Structure(见上面 LINE_CODING结构体) |
2.3.6 CDC SetControlLineState
SetControlLineState用于生成RS-232/V.24风格的控制信号,模拟传统串口通信的控制线状态。
主机通过此请求控制设备的DTR(Data Terminal Ready)和RTS(Request To Send)信号,实现流控制和设备状态指示。
| 字段 | 值/说明 |
|---|---|
| bmRequestType | 0x21 (00100001B) 方向:主机到设备,类型:类,接收者:接口 |
| bRequest | 0x22 (SET_CONTROL_LINE_STATE) |
| wValue | 控制信号位图(Control Signal Bitmap) D15…D2: RESERVED(复位为0) D1: 载波控制(半双工调制解调器)对应V.24信号105和RS-232信号RTS;0:停用载波 1:启用载波 ;全双工模式下设备忽略此位 D0: DTE存在指示;对应V.24信号108/2和RS-232信号DTR;0:不存在 1:存在 |
| wIndex | 接口号 |
| wLength | 0 |
| Data | 无 |
这里仅列举以上几个,另外后续将模拟串口,会用到0x20、0x21和0x22这三个类请求。
2.4 CDC 通知元素通知
Notification Element Notifications定义了通信接口类通知,设备使用这些通知来通知主机接口或端点事件。
这些通知通过中断端点发送,用于实时状态更新和事件报告。
2.4.1 通知格式
| 偏移量 | 字段 | 大小 | 值 | 描述 |
|---|---|---|---|---|
| 0 | bmRequestType | 1 | Bitmap | 请求特性: •D7:数据传输方向 0= 主机到设备1= 设备到主机•D6…5:请求类型 00= 标准01= 类10= 厂商11= 保留•D4…0:接收方 00000= 设备00001= 接口00010= 端点00011= 其他00100…11111= 保留 |
| 1 | bNotification | 1 | number | 具体的通知类型 NETWORK_CONNECTION(网络连接) 00h0 – 断开连接 1 – 已连接RESPONSE_AVAILABLE(响应可用) 01hRESERVED(保留,未来使用) 02h-07hAUX_JACK_HOOK_STATE(辅助插孔挂机状态) 08h0 – 挂机 1 – 摘机RING_DETECT(振铃检测) 09hRESERVED(保留,未来使用) 0Ah-1FhSERIAL_STATE(串口状态) 20hUART 状态位图RESERVED(保留,未来使用) 21h-27hCALL_STATE_CHANGE(呼叫状态变更) 28h包含呼叫索引和状态变更值LINE_STATE_CHANGE(线路状态变更) 29h可变长度线路状态结构CONNECTION_SPEED_CHANGE(连接速度变更) 2Ah8 字节连接速度数据结构RESERVED(保留,未来使用) 2Bh-FFh |
| 2 | wValue | 2 | number | 一个字长(2字节)的字段,其含义根据具体请求而变化 |
| 4 | wIndex | 2 | 索引或偏移 | 一个字长(2字节)的字段,其含义根据具体请求而变化;通常用于传递一个索引或偏移量 |
| 6 | wLength | 2 | 计数 | 如果存在数据阶段,则表示要传输的字节数 |
| 7 | data | n | 值 | 可选,根据特定请求含义不同 |
篇幅原因,后面列举其中两个。
2.4.2 CDC NetworkConnection
NetworkConnection通知允许设备向主机报告网络连接状态的变化。
当设备的网络连接状态发生变化时(如连接建立或断开),设备会通过此通知实时告知主机。
| 字段 | 值/说明 |
|---|---|
| bmRequestType | 0xA1 (10100001B) 方向:设备到主机,类型:类,接收者:接口 |
| bNotification | 0x00 (NETWORK_CONNECTION) |
| wValue | 0 = 断开连接 1 = 已连接 |
| wIndex | 接口号 |
| wLength | 0 |
| Data | 无 |
以太网连接 1 检测到以太网连接建立
以太网断开 0 检测到以太网连接断开
无线网络连接 1 检测到WiFi连接建立
无线网络断开 0 检测到WiFi连接断开
2.4.3 CDC SerialState通知
SerialState 通知发送UART状态的异步通知。
此通知用于报告UART的各种状态信号,包括载波检测、传输载波、中断、振铃信号和设备溢出错误等。这些信号通常存在于UART中,用于通信状态报告。
| 字段 | 值/说明 |
|---|---|
| bmRequestType | 0xA1 (10100001B) 方向:设备到主机,类型:类,接收者:接口 |
| bNotification | 0x20 (SERIAL_STATE) |
| wValue | 0x0000 |
| wIndex | 接口号 |
| wLength | 2 |
| Data | UART状态位图 D15…D7: RESERVED 保留供将来使用 D6: bOverRun 由于设备溢出,接收数据已被丢弃 D5: bParity 发生奇偶校验错误 D4: bFraming 发生帧错误 D3: bRingSignal 设备振铃信号检测状态 D2: bBreak 设备中断检测机制状态 D1: bTxCarrier 传输载波状态。对应V.24信号106和RS-232信号DSR D0: bRxCarrier 设备接收载波检测机制状态。对应V.24信号109和RS-232信号DCD |
3 实例——模拟串口
3.1 描述符
这里简单说下配置描述符,配置描述符定义了一个CDC-ACM(Abstract Control Model)设备,包含:
- 1个配置(Configuration 1)
- 2个接口(Interface 0 和 Interface 1)
- 4个端点(包括EP0,实际描述符中定义了3个额外端点)
关系如下:
其中:
EP0用来管理和关键配置;EP1用来实现异步状态通知;EP2/EP3为数据传输提供独立的物理通道。
配置描述符里详细配置和其他描述符不再一一具体说明,注释里已包含,如有问题,可参照前面章节比对。
constunsignedcharDevDes[18]={0x12,/* bLength */0x01,/* bDescriptorType : device_descriptor */0x00,0x02,/* bcdUSB usb2.0 = 0x0200 usb1.1 = 0x0110 usb3.11 = 0x0311 */0x02,/* bDeviceClass (Notice: should be 0x02 CDC)*/0x02,/* bDeviceSubClass(ACM class) */0x00,/* bDeviceProtocol */0x40,/* bMax EP0 PacketSize : 64bytes*/0x66,0x66,/* idVendor : 2 Bytes (just for test) */0x88,0x88,/* idProduct : 2 Bytes (just for test) */0x00,0x02,/* bcdDevice rel. 2.00 */0x01,/* Index of manufacturer string */0x02,/* Index of product string */0x03,/* Index of serial number string */0x01/* bNumConfigurations */};/* dev Configurations */constunsignedcharConDes[9+9+5+5+4+5+7+9+7+7]={// Configuation Descriptor0x09,/* bLength */0x02,/* bDescriptorType : interface descriptor */sizeof(ConDes)&0xFF,(sizeof(ConDes))>>8&0xFF,// wTotalLength0x02,// bNumInterfaces0x01,// bConfigurationValue0x00,// iConfiguration0x80,// bmAttributes0x32,// bMaxPower : 100mA// Interface 0 (CDC)0x09,// bLength0x04,// bDescriptorType0x00,// bInterfaceNumber0x00,// bAlternateSetting0x01,// bNumEndpoints(exclude Ep0)0x02,// bInterfaceClass (CDC)0x02,// bInterfaceSubClass (Abstract Control Model)0x01,// bInterfaceProtocol : (Common AT Commands)0x00,// iInterface// functional descriptors0x05,// bLength: Endpoint Descriptor size0x24,// bDescriptorType: CS_INTERFACE0x00,// bDescriptorSubtype: Call Management Func Desc0x10,0x01,// bcdCDC: spec release number : 0x01100x05,// bFunctionLength0x24,// bDescriptorType0x01,// bDescriptorSubtype: Call Management Func Desc0x00,// bmCapabilities: D0 + D10x00,// bDataInterface: 10x04,// bFunctionLength0x24,// bDescriptorType: CS_INTERFACE0x02,// bDescriptorSubtype: Abstract Control Management desc0x02,// bmCapabilities suport Set_Line_Coding Set_Control_Line_State Get_Line_Coding Serial_State0x05,// bFunctionLength0x24,// bDescriptorType: CS_INTERFACE0x06,// bDescriptorSubtype: Union func desc0x00,// bMasterInterface: Communication class interface0x01,// bSlaveInterface0: Data Class Interface// Endpoint 10x07,// bLength0x05,// bDescriptorType0x81,// Ep1 : In0x03,// bmAttributes : Interrupt0x40,0x00,// wMaxPackeSize : 0x00400x0F,// bInterval : 256ms// Interface 1 (Data)0x09,// bLength0x04,// bDescriptorType0x01,// bInterfaceNumber0x00,// bAlternateSetting0x02,// bNumEndpoints(exclude Ep0)0x0A,// bInterfaceClass (CDC-Data)0x00,// bInterfaceSubClass (Abstract Control Model)0x00,// bInterfaceProtocol : (Common AT Commands)0x00,// iInterface// Endpoint 20x07,// bLength0x05,// bDescriptorType0x82,// Ep2 : In0x02,// bmAttributes : Bulk0x40,0x00,// wMaxPackeSize : 0x00400x0F,// bInterval// Endpoint 30x07,// bLength0x05,// bDescriptorType0x03,// Ep3 : Out0x02,// bmAttributes : Bulk0x40,0x00,// wMaxPackeSize : 0x00400x00// bInterval};/* langDes */constunsignedcharLangDes[]={0x04,0x03,0x09,0x04};/* Manuf */constunsignedcharManuf_Des[]={0x0E,0x03,0x48,0x00,// Hezaiz0x65,0x00,0x7A,0x00,0x61,0x00,0x69,0x00,0x7A,0x00,};/* product Des */constunsignedcharProd_Des[]={0x20,0x03,0x44,0x00,// DEMO USB2.0 CDC0x45,0x00,0x4D,0x00,0x4F,0x00,0x20,0x00,0x55,0x00,0x53,0x00,0x42,0x00,0x32,0x00,0x2e,0x00,0x30,0x00,0x20,0x00,0x43,0x00,0x44,0x00,0x43,0x00,};/* product ser */constunsignedcharSerDes[18]={0x12,0x03,0x32,0x00,// 202205220x30,0x00,0x32,0x00,0x35,0x00,0x31,0x00,0x32,0x00,0x31,0x00,0x32,0x00,};uint8_tDeviceQualifierDesc[]={0x0A,0x06,0x10,0x01,0x00,0x00,0x00,0x40,0x01,0x00,};// cdc para 57600, 1, None, 8bitunsignedcharLineCoding[7]={0x80,0x25,0x00,0x00,0x00,0x00,0x08};3.2 枚举流程
和HID枚举流程类似,通过控制传输和EP0通信,完成描述符的上报,具体不同点在于类请求部分,但流程大致差不多,具体流程不再展开,可以参考USB2.0枚举流程(以鼠标为例)——从零开始学习USB2.0协议(四)鼠标枚举流程。
3.3 数据收发
device程序里做了一个回显的demo,即:串口助手通过host向device发送数据,device会回复给host相同的数据,并通过真实串口打印出来。
- 演示如下:
USB_CDC_COM
- 抓下数据收发包:
可以通过ASCII码表解析出来,就是“hello world!”,然后组包后由发了出去。 - USB Device Tree抓取host端信息
参考:
usbcdc11
USB CDC从理论到实践_usb cdc土门-CSDN博客
USB通信设备类CDC简介 - USB中文网
USB 设备编程_2 - 韦东山嵌入式开发者社区
全面解析USB CDC通信设备类规范与应用-CSDN博客