libxr  1.0
Want to be the best embedded framework
Loading...
Searching...
No Matches
hid.hpp
1#pragma once
2#include <cstring>
3
4#include "dev_core.hpp"
5#include "usb/core/desc_cfg.hpp"
6
7namespace LibXR::USB
8{
9
21template <size_t REPORT_DESC_LEN, size_t TX_REPORT_LEN, size_t RX_REPORT_LEN = 0>
22class HID : public DeviceClass
23{
24 public:
26 enum class HIDDescriptorType : uint8_t
27 {
28 HID = 0x21,
29 REPORT = 0x22,
30 PHYSICAL = 0x23
31 };
32
34 enum class ClassRequest : uint8_t
35 {
36 GET_REPORT = 0x01,
37 GET_IDLE = 0x02,
38 GET_PROTOCOL = 0x03,
39 SET_REPORT = 0x09,
40 SET_IDLE = 0x0A,
41 SET_PROTOCOL = 0x0B
42 };
43
45 enum class Protocol : uint8_t
46 {
47 BOOT = 0x00,
48 REPORT = 0x01
49 };
50
52 enum class ReportType : uint8_t
53 {
54 INPUT = 1,
55 OUTPUT = 2,
56 FEATURE = 3
57 };
58
59#pragma pack(push, 1)
75
86
98#pragma pack(pop)
99
110 HID(bool enable_out_endpoint = false, uint8_t in_ep_interval = 10,
111 uint8_t out_ep_interval = 10,
114 : in_ep_interval_(in_ep_interval),
115 out_ep_interval_(out_ep_interval),
116 in_ep_num_(in_ep_num),
117 out_ep_num_(out_ep_num),
118 enable_out_endpoint_(enable_out_endpoint)
119 {
120 }
121
122 protected:
130 void BindEndpoints(EndpointPool& endpoint_pool, uint8_t start_itf_num, bool) override
131 {
132 inited_ = false;
133 itf_num_ = start_itf_num;
134 ep_in_ = nullptr;
135 ep_out_ = nullptr;
136
137 // 获取IN端点
138 auto ans = endpoint_pool.Get(ep_in_, Endpoint::Direction::IN, in_ep_num_);
139 ASSERT(ans == ErrorCode::OK);
142
144 {
145 ans = endpoint_pool.Get(ep_out_, Endpoint::Direction::OUT, out_ep_num_);
146 ASSERT(ans == ErrorCode::OK);
149 }
150
151 // 填充接口描述符
152 desc_.intf = {
153 9, // bLength
154 static_cast<uint8_t>(DescriptorType::INTERFACE), // bDescriptorType
155 static_cast<uint8_t>(itf_num_), // bInterfaceNumber
156 0, // bAlternateSetting
157 static_cast<uint8_t>(enable_out_endpoint_ ? 2 : 1), // bNumEndpoints
158 0x03, // bInterfaceClass (HID)
159 0x00, // bInterfaceSubClass
160 0x00, // bInterfaceProtocol (可选键盘/鼠标设置1/2)
161 0 // iInterface
162 };
163
164 // 填充HID描述符
165 desc_.hid = {9,
167 0x0111, // HID v1.11
168 0x00, // 国家码
169 0x01, // 只有一个后续描述符(Report Desc)
171 REPORT_DESC_LEN};
172
173 // 填充IN端点描述符
174 desc_.ep_in = {
175 7,
176 static_cast<uint8_t>(DescriptorType::ENDPOINT),
178 static_cast<uint8_t>(Endpoint::Type::INTERRUPT),
179 TX_REPORT_LEN,
180 in_ep_interval_ // 轮询间隔ms
181 };
182
183 // 填充OUT端点描述符(如启用)
185 {
186 desc_.ep_out = {7,
187 static_cast<uint8_t>(DescriptorType::ENDPOINT),
189 static_cast<uint8_t>(Endpoint::Type::INTERRUPT),
190 RX_REPORT_LEN,
192 }
193
194 // 设置最终数据指针
196 {
197 SetData(RawData{reinterpret_cast<uint8_t*>(&desc_), sizeof(HIDDescBlockINOUT)});
198 }
199 else
200 {
201 SetData(RawData{reinterpret_cast<uint8_t*>(&desc_), sizeof(HIDDescBlockIN)});
202 }
203
204 ep_in_->SetOnTransferCompleteCallback(on_data_in_complete_cb_);
205
207 {
208 ep_out_->SetOnTransferCompleteCallback(on_data_out_complete_cb_);
209 ep_out_->Transfer(RX_REPORT_LEN);
210 }
211
212 inited_ = true;
213 }
214
215 static void OnDataOutCompleteStatic(bool in_isr, HID* self, LibXR::ConstRawData& data)
216 {
217 self->OnDataOutComplete(in_isr, data);
218 self->ep_out_->Transfer(RX_REPORT_LEN);
219 }
220
221 static void OnDataInCompleteStatic(bool in_isr, HID* self, LibXR::ConstRawData& data)
222 {
223 self->OnDataInComplete(in_isr, data);
224 }
225
226 virtual void OnDataOutComplete(bool in_isr, LibXR::ConstRawData& data)
227 {
228 UNUSED(in_isr);
229 UNUSED(data);
230 }
231
232 virtual void OnDataInComplete(bool in_isr, LibXR::ConstRawData& data)
233 {
234 UNUSED(in_isr);
235 UNUSED(data);
236 }
237
244 void UnbindEndpoints(EndpointPool& endpoint_pool, bool) override
245 {
246 inited_ = false;
247 if (ep_in_)
248 {
249 ep_in_->Close();
250 endpoint_pool.Release(ep_in_);
251 ep_in_ = nullptr;
252 }
253 if (ep_out_)
254 {
255 ep_out_->Close();
256 endpoint_pool.Release(ep_out_);
257 ep_out_ = nullptr;
258 }
259 }
260
266 size_t GetInterfaceCount() override { return 1; }
267
275 bool HasIAD() override { return false; }
276
277 bool OwnsEndpoint(uint8_t ep_addr) const override
278 {
279 if (!inited_)
280 {
281 return false;
282 }
283
284 return ep_in_->GetAddress() == ep_addr ||
285 (enable_out_endpoint_ && ep_out_->GetAddress() == ep_addr);
286 }
287
293 size_t GetMaxConfigSize() override
294 {
295 return enable_out_endpoint_ ? sizeof(HIDDescBlockINOUT) : sizeof(HIDDescBlockIN);
296 }
297
309 ErrorCode OnGetDescriptor(bool in_isr, uint8_t bRequest, uint16_t wValue,
310 uint16_t wLength, ConstRawData& need_write) override
311 {
312 UNUSED(in_isr);
313 UNUSED(bRequest);
314
315 uint8_t desc_type = (wValue >> 8) & 0xFF;
316 // uint8_t desc_index = wValue & 0xFF; // 一般为0,暂不需要
317
318 switch (desc_type)
319 {
320 case static_cast<uint8_t>(HIDDescriptorType::HID): // 0x21
321 {
322 // 返回 HID 描述符
323 ConstRawData desc = GetHIDDesc();
324 need_write.addr_ = desc.addr_;
325 need_write.size_ = (wLength < desc.size_) ? wLength : desc.size_;
326 return ErrorCode::OK;
327 }
328 case static_cast<uint8_t>(HIDDescriptorType::REPORT): // 0x22
329 {
330 // 返回 Report Descriptor
332 need_write.addr_ = desc.addr_;
333 need_write.size_ = (wLength < desc.size_) ? wLength : desc.size_;
334 return ErrorCode::OK;
335 }
336 case static_cast<uint8_t>(HIDDescriptorType::PHYSICAL):
337 // 物理描述符(很少用,未实现)
338 default:
339 return ErrorCode::NOT_SUPPORT;
340 }
341 }
342
354 ErrorCode OnClassRequest(bool in_isr, uint8_t bRequest, uint16_t wValue,
355 uint16_t wLength, uint16_t wIndex,
356 DeviceClass::ControlTransferResult& result) override
357 {
358 UNUSED(in_isr);
359 UNUSED(wIndex);
360
361 uint8_t report_id = wValue & 0xFF;
362
363 switch (static_cast<ClassRequest>(bRequest))
364 {
366 {
367 ReportType report_type = static_cast<ReportType>((wValue >> 8) & 0xFF);
368 switch (report_type)
369 {
371 // 查找或生成 Input Report(按你的设备实际逻辑)
372 return OnGetInputReport(report_id, result);
374 // 查找或返回最近收到的 Output Report(通常很少实现GET Output)
375 return OnGetLastOutputReport(report_id, result);
377 // 查找或生成 Feature Report
378 return OnGetFeatureReport(report_id, result);
379 default:
380 return OnCustomClassRequest(in_isr, bRequest, wValue, wLength, result);
381 }
382 }
383
385 if (wLength == 0)
386 {
387 return ErrorCode::ARG_ERR;
388 }
389 // 由OnClassData阶段接收
390 return OnSetReport(report_id, result);
391
393 // 仅支持一个Idle rate
394 if (wLength != 1 || report_id != 0)
395 {
396 return ErrorCode::ARG_ERR;
397 }
398 result.write_data = ConstRawData{&idle_rate_, 1};
399 return ErrorCode::OK;
400
402 if (report_id != 0)
403 {
404 return ErrorCode::ARG_ERR;
405 }
406 idle_rate_ = wValue >> 8;
407 result.write_zlp = true;
408 return ErrorCode::OK;
409
411 result.write_data = ConstRawData{reinterpret_cast<uint8_t*>(&protocol_), 1};
412 return ErrorCode::OK;
413
415 protocol_ = static_cast<Protocol>(wValue & 0xFF);
416 result.write_zlp = true;
417 return ErrorCode::OK;
418
419 default:
420 return ErrorCode::NOT_SUPPORT;
421 }
422 }
423
428 ErrorCode OnClassData(bool in_isr, uint8_t bRequest, LibXR::ConstRawData& data) override
429 {
430 UNUSED(in_isr);
431
432 switch (static_cast<ClassRequest>(bRequest))
433 {
435 {
436 // 通常为 Output Report 或 Feature Report
437 // 你可以区分是 Output 还是 Feature,也可以统一交给
438 // OnSetReportData(推荐如下写法)
439 auto ans = OnSetReportData(in_isr, data);
440 if (ans == ErrorCode::OK)
441 {
442 // 可选:记录最近一次 report id(假定第一个字节是 report id,没有 report id
443 // 就写0)
445 (data.size_ > 0) ? reinterpret_cast<const uint8_t*>(data.addr_)[0] : 0;
446 }
447 return ans;
448 }
449 default:
450 return OnCustomClassData(in_isr, bRequest, data);
451 }
452 }
453
460
467
474 {
475 return ConstRawData{&desc_.hid, sizeof(HIDDescriptor)};
476 }
477
482 virtual ErrorCode OnGetInputReport(uint8_t report_id,
484 {
485 UNUSED(report_id);
486 result.write_data = ConstRawData{nullptr, 0};
487 return ErrorCode::OK;
488 }
489
494 virtual ErrorCode OnGetLastOutputReport(uint8_t report_id,
496 {
497 UNUSED(report_id);
498 result.write_data = ConstRawData{nullptr, 0};
499 return ErrorCode::OK;
500 }
501
506 virtual ErrorCode OnGetFeatureReport(uint8_t report_id,
508 {
509 UNUSED(report_id);
510 result.write_data = ConstRawData{nullptr, 0};
511 return ErrorCode::OK;
512 }
513
525 virtual ErrorCode OnCustomClassRequest(bool in_isr, uint8_t bRequest, uint16_t wValue,
526 uint16_t wLength,
528 {
529 UNUSED(in_isr);
530 UNUSED(bRequest);
531 UNUSED(wValue);
532 UNUSED(wLength);
533 UNUSED(result);
534 return ErrorCode::NOT_SUPPORT;
535 }
536
537 virtual ErrorCode OnCustomClassData(bool in_isr, uint8_t bRequest, ConstRawData& data)
538 {
539 UNUSED(in_isr);
540 UNUSED(bRequest);
541 UNUSED(data);
542 return ErrorCode::NOT_SUPPORT;
543 }
544
549 virtual ErrorCode OnSetReport(uint8_t report_id,
551 {
552 UNUSED(report_id);
553 UNUSED(result);
554
555 return ErrorCode::NOT_SUPPORT;
556 }
557
562 virtual ErrorCode OnSetReportData(bool in_isr, ConstRawData& data)
563 {
564 UNUSED(in_isr);
565 UNUSED(data);
566
567 return ErrorCode::OK;
568 }
569
578 {
579 if (!inited_ || !ep_in_)
580 {
581 return ErrorCode::FAILED;
582 }
583 if (!report.addr_ || report.size_ == 0 || report.size_ > TX_REPORT_LEN)
584 {
585 return ErrorCode::ARG_ERR;
586 }
587
589 {
590 return ErrorCode::BUSY;
591 }
592
593 // 数据拷贝到端点缓冲区
594 auto buf = ep_in_->GetBuffer();
595 if (report.size_ > buf.size_)
596 {
597 return ErrorCode::NO_BUFF;
598 }
599
600 LibXR::Memory::FastCopy(buf.addr_, report.addr_, report.size_);
601
602 // 启动端点传输
603 return ep_in_->Transfer(report.size_);
604 }
605
612 uint8_t GetIDLERate() const { return idle_rate_; }
613
621
629
634 bool HasOutEndpoint() const { return enable_out_endpoint_; }
635
636 private:
642 Endpoint* ep_in_ = nullptr;
643 Endpoint* ep_out_ = nullptr;
645 bool inited_ = false;
646 size_t itf_num_;
647
649 uint8_t idle_rate_ = 0;
651 0;
652
653 LibXR::Callback<LibXR::ConstRawData&> on_data_out_complete_cb_ =
654 LibXR::Callback<LibXR::ConstRawData&>::Create(OnDataOutCompleteStatic, this);
655
656 LibXR::Callback<LibXR::ConstRawData&> on_data_in_complete_cb_ =
657 LibXR::Callback<LibXR::ConstRawData&>::Create(OnDataInCompleteStatic, this);
658};
659
660} // namespace LibXR::USB
通用回调包装,支持动态参数传递 / Generic callback wrapper supporting dynamic argument passing
Definition libxr_cb.hpp:150
static Callback Create(FunType fun, ArgType arg)
创建回调对象并绑定回调函数与参数 / Create a callback instance with bound function and argument
Definition libxr_cb.hpp:167
常量原始数据封装类。 A class for encapsulating constant raw data.
size_t size_
数据大小(字节)。 The size of the data (in bytes).
const void * addr_
数据存储地址(常量)。 The storage address of the data (constant).
static void FastCopy(void *dst, const void *src, size_t size)
快速内存拷贝 / Fast memory copy
Definition libxr_mem.cpp:3
原始数据封装类。 A class for encapsulating raw data.
void SetData(RawData data)
设置内部数据缓存 / Set internal data cache
Definition desc_cfg.hpp:194
USB 设备类接口基类 / USB device class interface base.
Definition dev_core.hpp:26
USB 端点基类 / USB Endpoint base class.
Definition ep.hpp:23
EPNumber
端点号 Endpoint number
Definition ep.hpp:41
@ EP_AUTO
自动分配端点号 / Auto allocate
uint8_t GetAddress() const
获取端点地址(方向 + 号) / Get endpoint address (dir + num)
Definition ep.hpp:194
@ IN
输入方向 / IN direction
@ OUT
输出方向 / OUT direction
void SetOnTransferCompleteCallback(Callback< ConstRawData & > cb)
设置传输完成回调 / Set transfer complete callback
Definition ep.hpp:261
virtual void Configure(const Config &cfg)=0
配置端点协议参数 / Configure endpoint protocol parameters
@ INTERRUPT
中断端点 / Interrupt
virtual void Close()=0
关闭端点 / Close endpoint
State GetState() const
获取端点状态 / Get endpoint state
Definition ep.hpp:207
virtual ErrorCode Transfer(size_t size)=0
启动一次传输 / Start a transfer
RawData GetBuffer() const
获取当前可用于传输的缓冲区 / Get current transfer buffer
Definition ep.hpp:245
USB端点池类 / USB endpoint pool class.
Definition ep_pool.hpp:23
ErrorCode Get(Endpoint *&ep_info, Endpoint::Direction direction, Endpoint::EPNumber ep_num=Endpoint::EPNumber::EP_AUTO)
分配端点 / Allocate endpoint
Definition ep_pool.cpp:11
ErrorCode Release(Endpoint *ep_info)
回收端点 / Release endpoint
Definition ep_pool.cpp:37
USB HID(Human Interface Device)基类,支持可选 OUT 端点、自动生成描述符,适合键盘、鼠标、手柄等扩展。 USB HID (Human Interface Device)...
Definition hid.hpp:23
virtual ConstRawData GetHIDDesc()
获取 HID 描述符 Get HID Descriptor
Definition hid.hpp:473
virtual ErrorCode OnGetInputReport(uint8_t report_id, DeviceClass::ControlTransferResult &result)
获取输入报告 Get Input Report
Definition hid.hpp:482
virtual ErrorCode OnSetReport(uint8_t report_id, DeviceClass::ControlTransferResult &result)
处理 SET_REPORT 请求 Handle SET_REPORT request
Definition hid.hpp:549
bool enable_out_endpoint_
是否启用 OUT 端点 / Whether OUT endpoint is enabled
Definition hid.hpp:644
virtual ErrorCode OnGetFeatureReport(uint8_t report_id, DeviceClass::ControlTransferResult &result)
获取特征报告 Get Feature Report
Definition hid.hpp:506
void UnbindEndpoints(EndpointPool &endpoint_pool, bool) override
反初始化 HID 设备 Deinitialize HID device.
Definition hid.hpp:244
ErrorCode OnGetDescriptor(bool in_isr, uint8_t bRequest, uint16_t wValue, uint16_t wLength, ConstRawData &need_write) override
处理标准请求 GET_DESCRIPTOR(HID/Report 描述符)。 Handle standard GET_DESCRIPTOR requests for HID/Report Descrip...
Definition hid.hpp:309
Endpoint * GetOutEndpoint()
获取输出端点 Get OUT endpoint
Definition hid.hpp:628
bool HasIAD() override
检查是否包含IAD Check if IAD is present
Definition hid.hpp:275
uint8_t last_output_report_id_
最近的 Output Report ID / Last Output Report ID
Definition hid.hpp:650
Endpoint * ep_out_
输出端点指针 / OUT endpoint pointer
Definition hid.hpp:643
HID(bool enable_out_endpoint=false, uint8_t in_ep_interval=10, uint8_t out_ep_interval=10, Endpoint::EPNumber in_ep_num=Endpoint::EPNumber::EP_AUTO, Endpoint::EPNumber out_ep_num=Endpoint::EPNumber::EP_AUTO)
HID 构造函数 HID class constructor.
Definition hid.hpp:110
virtual ConstRawData GetReportDesc()=0
获取 HID 报告描述符 Get HID Report Descriptor
uint8_t idle_rate_
当前空闲率/ Current idle rate (unit 4ms)
Definition hid.hpp:649
ErrorCode SendInputReport(ConstRawData report)
发送输入报告到主机 Send Input Report to host
Definition hid.hpp:577
Endpoint * ep_in_
输入端点指针 / IN endpoint pointer
Definition hid.hpp:642
uint8_t out_ep_interval_
输出端点间隔 / OUT endpoint interval
Definition hid.hpp:638
void BindEndpoints(EndpointPool &endpoint_pool, uint8_t start_itf_num, bool) override
初始化 HID 设备,自动选择端点与描述符块 Initialize HID device and select descriptor block (IN or IN+OUT).
Definition hid.hpp:130
Protocol
HID 协议类型 / HID Protocol Types.
Definition hid.hpp:46
@ REPORT
报告协议 / Report protocol (通用)
@ BOOT
启动协议 / Boot protocol (键盘/鼠标)
size_t GetMaxConfigSize() override
获取最大配置描述符块长度 Get max config descriptor size.
Definition hid.hpp:293
HIDDescBlockINOUT desc_
HID 描述符块/ Descriptor block.
Definition hid.hpp:639
bool OwnsEndpoint(uint8_t ep_addr) const override
可选:端点归属判定 / Optional: endpoint ownership
Definition hid.hpp:277
size_t GetInterfaceCount() override
获取接口数量 Get number of interfaces
Definition hid.hpp:266
virtual ErrorCode OnCustomClassRequest(bool in_isr, uint8_t bRequest, uint16_t wValue, uint16_t wLength, DeviceClass::ControlTransferResult &result)
处理自定义类请求 Handle custom class request
Definition hid.hpp:525
uint8_t in_ep_interval_
输入端点间隔 / IN endpoint interval
Definition hid.hpp:637
Endpoint::EPNumber out_ep_num_
输出端点号 / OUT endpoint number
Definition hid.hpp:641
bool HasOutEndpoint() const
查询是否支持OUT端点 Check if OUT endpoint is enabled
Definition hid.hpp:634
size_t itf_num_
接口号 / Interface number
Definition hid.hpp:646
uint8_t GetIDLERate() const
获取IDLE报告率 Get IDLE report rate
Definition hid.hpp:612
ReportType
HID 报告类型 / HID Report Types.
Definition hid.hpp:53
@ OUTPUT
输出报告 / Output report
@ INPUT
输入报告 / Input report
@ FEATURE
特征报告 / Feature report
Endpoint * GetInEndpoint()
获取输入端点 Get IN endpoint
Definition hid.hpp:620
virtual ErrorCode OnSetReportData(bool in_isr, ConstRawData &data)
处理 SET_REPORT 数据阶段 Handle SET_REPORT data stage
Definition hid.hpp:562
Endpoint::EPNumber in_ep_num_
输入端点号 / IN endpoint number
Definition hid.hpp:640
Protocol protocol_
当前协议类型 / Current protocol
Definition hid.hpp:648
uint8_t GetLastOutputReportID() const
获取最近一次 Output Report 的 Report ID Get the last received Output Report ID.
Definition hid.hpp:459
ErrorCode OnClassRequest(bool in_isr, uint8_t bRequest, uint16_t wValue, uint16_t wLength, uint16_t wIndex, DeviceClass::ControlTransferResult &result) override
处理 HID 类请求 Handle HID class-specific requests
Definition hid.hpp:354
bool inited_
初始化标志 / Initialization flag
Definition hid.hpp:645
HIDDescriptorType
HID 描述符类型 / HID Descriptor Types.
Definition hid.hpp:27
@ HID
HID 类描述符 / HID Class Descriptor.
@ REPORT
报告描述符 / Report Descriptor
@ PHYSICAL
物理描述符 / Physical Descriptor (rarely used)
virtual ErrorCode OnGetLastOutputReport(uint8_t report_id, DeviceClass::ControlTransferResult &result)
获取最近一次输出报告 Get last Output Report
Definition hid.hpp:494
ClassRequest
HID 类请求代码 / HID Class-Specific Requests.
Definition hid.hpp:35
@ SET_PROTOCOL
设置协议 / Set Protocol
@ GET_PROTOCOL
获取协议 / Get Protocol
@ GET_REPORT
获取报告 / Get Report
@ SET_REPORT
设置报告 / Set Report
@ SET_IDLE
设置空闲率 / Set Idle
@ GET_IDLE
获取空闲率 / Get Idle
ErrorCode OnClassData(bool in_isr, uint8_t bRequest, LibXR::ConstRawData &data) override
处理类请求数据阶段 Handle class data stage
Definition hid.hpp:428
端点描述符(7 字节)/ Endpoint descriptor (7 bytes)
Definition desc_cfg.hpp:92
接口描述符(9 字节)/ Interface descriptor (9 bytes)
Definition desc_cfg.hpp:76
控制请求(Class/Vendor)处理结果 / Control request (Class/Vendor) handling result
Definition dev_core.hpp:51
bool write_zlp
发送 STATUS IN(发送 ZLP)/ Send STATUS IN (send ZLP)
Definition dev_core.hpp:58
包含 IN 端点的描述符块 Descriptor block with IN endpoint.
Definition hid.hpp:81
EndpointDescriptor ep_in
IN 端点描述符 / IN endpoint descriptor.
Definition hid.hpp:84
HIDDescriptor hid
HID 描述符 / HID descriptor.
Definition hid.hpp:83
InterfaceDescriptor intf
接口描述符 / Interface descriptor
Definition hid.hpp:82
包含 IN+OUT 端点的描述符块 Descriptor block with IN and OUT endpoints.
Definition hid.hpp:92
HIDDescriptor hid
HID 描述符 / HID descriptor.
Definition hid.hpp:94
EndpointDescriptor ep_out
OUT 端点描述符 / OUT endpoint descriptor.
Definition hid.hpp:96
EndpointDescriptor ep_in
IN 端点描述符 / IN endpoint descriptor.
Definition hid.hpp:95
InterfaceDescriptor intf
接口描述符 / Interface descriptor
Definition hid.hpp:93
HID描述符结构体 HID descriptor structure.
Definition hid.hpp:65
uint8_t bLength
描述符长度 / Descriptor length
Definition hid.hpp:66
uint8_t bNumDescriptors
后续描述符数量 / Number of subordinate descriptors
Definition hid.hpp:70
uint16_t bcdHID
HID 版本号 / HID class specification release.
Definition hid.hpp:68
HIDDescriptorType bReportDescriptorType
报告描述符类型 / Report descriptor type (0x22)
Definition hid.hpp:72
HIDDescriptorType bDescriptorType
描述符类型 / Descriptor type (0x21)
Definition hid.hpp:67
uint16_t wReportDescriptorLength
报告描述符长度 / Report descriptor length
Definition hid.hpp:73
uint8_t bCountryCode
国家码 / Country code
Definition hid.hpp:69