5#include "libxr_def.hpp"
7#include "usb/core/desc_cfg.hpp"
26 static constexpr const char* DEFAULT_CONTROL_INTERFACE_STRING =
"XRUSB CDC Control";
27 static constexpr const char* DEFAULT_DATA_INTERFACE_STRING =
"XRUSB CDC Data";
31 enum class DescriptorSubtype : uint8_t
41 enum class Class : uint8_t
48 enum class Protocol : uint8_t
55 enum class Subclass : uint8_t
58 DIRECT_LINE_CONTROL_MODEL =
60 ABSTRACT_CONTROL_MODEL =
65 enum class ClassRequest : uint8_t
67 SET_LINE_CODING = 0x20,
68 GET_LINE_CODING = 0x21,
69 SET_CONTROL_LINE_STATE = 0x22,
74 enum class CDCNotification : uint8_t
76 NETWORK_CONNECTION = 0x00,
77 RESPONSE_AVAILABLE = 0x01,
78 AUX_JACK_HOOK_STATE = 0x08,
108 struct SerialStateNotification
110 uint8_t bmRequestType;
111 uint8_t bNotification;
116 uint16_t serialState;
122 static_assert(
sizeof(CDCLineCoding) == 7,
"LineCoding结构必须7字节");
125 static constexpr uint16_t CDC_CONTROL_LINE_DTR = 0x01;
126 static constexpr uint16_t CDC_CONTROL_LINE_RTS = 0x02;
141 const char* control_interface_string = DEFAULT_CONTROL_INTERFACE_STRING,
142 const char* data_interface_string = DEFAULT_DATA_INTERFACE_STRING)
143 : data_in_ep_num_(data_in_ep_num),
144 data_out_ep_num_(data_out_ep_num),
145 comm_ep_num_(comm_ep_num),
146 control_interface_string_(control_interface_string),
147 data_interface_string_(data_interface_string)
153 switch (local_interface_index)
156 return control_interface_string_;
158 return data_interface_string_;
171 bool IsDtrSet()
const {
return (control_line_state_ & CDC_CONTROL_LINE_DTR) != 0; }
180 bool IsRtsSet()
const {
return (control_line_state_ & CDC_CONTROL_LINE_RTS) != 0; }
196 ASSERT(buffer.size_ >=
sizeof(SerialStateNotification));
197 SerialStateNotification* notification =
198 reinterpret_cast<SerialStateNotification*
>(buffer.addr_);
199 notification->wIndex = itf_comm_in_num_;
207 notification->serialState = 0x03;
211 notification->serialState = 0x00;
216 notification->bmRequestType = 0xA1;
217 notification->bNotification =
static_cast<uint8_t
>(CDCNotification::SERIAL_STATE);
218 notification->wValue = 0;
219 notification->wLength = 2;
221 ep_comm_in_->
Transfer(
sizeof(SerialStateNotification));
232 has_control_line_state_cb_ = !cb.
Empty();
233 on_set_control_line_state_cb_ = cb;
242 has_line_coding_cb_ = !cb.
Empty();
243 on_set_line_coding_cb_ = cb;
261 control_line_state_ = 0;
284 static constexpr uint8_t COMM_INTERFACE = 0;
285 static constexpr uint8_t DATA_INTERFACE = 1;
289 desc_block_.
iad = {8,
290 static_cast<uint8_t
>(DescriptorType::IAD),
291 static_cast<uint8_t
>(COMM_INTERFACE + start_itf_num),
293 static_cast<uint8_t
>(Class::COMM),
294 static_cast<uint8_t
>(Subclass::ABSTRACT_CONTROL_MODEL),
295 static_cast<uint8_t
>(Protocol::NONE),
301 static_cast<uint8_t
>(DescriptorType::INTERFACE),
302 static_cast<uint8_t
>(COMM_INTERFACE + start_itf_num),
305 static_cast<uint8_t
>(Class::COMM),
306 static_cast<uint8_t
>(Subclass::ABSTRACT_CONTROL_MODEL),
307 static_cast<uint8_t
>(Protocol::NONE),
312 desc_block_.cdc_header = {5, DescriptorType::CS_INTERFACE, DescriptorSubtype::HEADER,
317 desc_block_.cdc_callmgmt = {
318 5, DescriptorType::CS_INTERFACE, DescriptorSubtype::CALL_MANAGEMENT,
320 static_cast<uint8_t
>(DATA_INTERFACE + start_itf_num)};
324 desc_block_.cdc_acm = {4, DescriptorType::CS_INTERFACE, DescriptorSubtype::ACM,
329 desc_block_.cdc_union = {5, DescriptorType::CS_INTERFACE, DescriptorSubtype::UNION,
330 static_cast<uint8_t
>(COMM_INTERFACE + start_itf_num),
331 static_cast<uint8_t
>(DATA_INTERFACE + start_itf_num)};
336 static_cast<uint8_t
>(DescriptorType::INTERFACE),
337 static_cast<uint8_t
>(DATA_INTERFACE + start_itf_num),
340 static_cast<uint8_t
>(Class::DATA),
347 static_cast<uint8_t
>(DescriptorType::ENDPOINT),
355 static_cast<uint8_t
>(DescriptorType::ENDPOINT),
356 static_cast<uint8_t
>(ep_data_in_->
GetAddress()),
365 static_cast<uint8_t
>(DescriptorType::ENDPOINT),
366 static_cast<uint8_t
>(ep_comm_in_->
GetAddress()),
372 itf_comm_in_num_ = start_itf_num;
376 SetData(
RawData{
reinterpret_cast<uint8_t*
>(&desc_block_),
sizeof(desc_block_)});
399 control_line_state_ = 0;
400 ep_data_in_->
Close();
401 ep_data_out_->
Close();
402 ep_comm_in_->
Close();
406 endpoint_pool.
Release(ep_data_in_);
407 endpoint_pool.
Release(ep_data_out_);
408 endpoint_pool.
Release(ep_comm_in_);
409 ep_data_in_ =
nullptr;
410 ep_data_out_ =
nullptr;
411 ep_comm_in_ =
nullptr;
482 return ep_data_in_->
GetAddress() == ep_addr ||
502 uint16_t wLength, uint16_t wIndex,
508 switch (
static_cast<ClassRequest
>(bRequest))
510 case ClassRequest::SET_LINE_CODING:
512 if (wLength !=
sizeof(line_coding_))
517 RawData{
reinterpret_cast<uint8_t*
>(&line_coding_),
sizeof(line_coding_)};
520 case ClassRequest::GET_LINE_CODING:
523 if (wLength !=
sizeof(line_coding_))
529 sizeof(line_coding_)};
532 case ClassRequest::SET_CONTROL_LINE_STATE:
535 control_line_state_ = wValue;
538 if (has_control_line_state_cb_)
544 case ClassRequest::SEND_BREAK:
564 switch (
static_cast<ClassRequest
>(bRequest))
566 case ClassRequest::SET_LINE_CODING:
571 cfg.
baudrate = line_coding_.dwDTERate;
572 switch (line_coding_.bCharFormat)
584 switch (line_coding_.bParityType)
596 if (has_line_coding_cb_)
598 on_set_line_coding_cb_.Run(in_isr, cfg);
624 uint8_t bFunctionLength = 5;
625 DescriptorType bDescriptorType = DescriptorType::CS_INTERFACE;
626 DescriptorSubtype bDescriptorSubtype = DescriptorSubtype::HEADER;
632 uint8_t bFunctionLength = 5;
633 DescriptorType bDescriptorType = DescriptorType::CS_INTERFACE;
634 DescriptorSubtype bDescriptorSubtype = DescriptorSubtype::CALL_MANAGEMENT;
641 uint8_t bFunctionLength = 4;
642 DescriptorType bDescriptorType = DescriptorType::CS_INTERFACE;
643 DescriptorSubtype bDescriptorSubtype = DescriptorSubtype::ACM;
649 uint8_t bFunctionLength = 5;
650 DescriptorType bDescriptorType = DescriptorType::CS_INTERFACE;
651 DescriptorSubtype bDescriptorSubtype = DescriptorSubtype::UNION;
666 CDCLineCoding& GetLineCoding() {
return line_coding_; }
668 bool Inited() {
return inited_; }
670 Endpoint* GetDataInEndpoint() {
return ep_data_in_; }
672 Endpoint* GetDataOutEndpoint() {
return ep_data_out_; }
674 Endpoint* GetCommInEndpoint() {
return ep_comm_in_; }
682 const char* control_interface_string_ =
684 const char* data_interface_string_ =
689 Endpoint* ep_data_in_ =
nullptr;
690 Endpoint* ep_data_out_ =
nullptr;
691 Endpoint* ep_comm_in_ =
nullptr;
704 on_set_control_line_state_cb_;
707 on_set_line_coding_cb_;
711 bool inited_ =
false;
712 bool has_control_line_state_cb_ =
false;
713 bool has_line_coding_cb_ =
false;
717 uint8_t itf_comm_in_num_;
721 CDCLineCoding line_coding_ = {115200, 0, 0, 8};
722 uint16_t control_line_state_ = 0;
通用回调包装,支持动态参数传递 / Generic callback wrapper supporting dynamic argument passing
static Callback Create(CallableType fun, BoundArgType arg)
创建回调对象并绑定回调函数与参数 / Create a callback instance with bound function and argument
bool Empty() const
检查回调是否为空 / Check whether the callback is empty
只读原始数据视图 / Immutable raw data view
可写原始数据视图 / Mutable raw data view
@ NO_PARITY
无校验 / No parity
USB CDC ACM (Abstract Control Model) 设备类实现 USB CDC ACM (Abstract Control Model) device class implemen...
void SetOnSetControlLineStateCallback(LibXR::Callback< bool, bool > cb)
设置控制线路状态变更回调 Set control line state change callback
virtual void BindEndpoints(EndpointPool &endpoint_pool, uint8_t start_itf_num, bool) override
初始化CDC设备 Initialize CDC device
size_t GetMaxConfigSize() override
获取最大配置描述符大小 Get maximum configuration descriptor size
void SetOnSetLineCodingCallback(LibXR::Callback< LibXR::UART::Configuration > cb)
设置线路编码变更回调 Set line coding change callback
virtual void OnDataInComplete(bool in_isr, ConstRawData &data)=0
数据IN端点传输完成处理 Handle data IN endpoint transfer completion
const char * GetInterfaceString(size_t local_interface_index) const override
返回本类暴露的第 N 个接口字符串 Return the string for the Nth local interface exposed by this class.
static void OnDataOutCompleteStatic(bool in_isr, CDCBase *self, ConstRawData &data)
数据OUT端点传输完成静态回调 Static callback for data OUT endpoint transfer completion
bool OwnsEndpoint(uint8_t ep_addr) const override
可选:端点归属判定 / Optional: endpoint ownership
bool IsRtsSet() const
检查RTS状态 Check RTS state
ErrorCode OnClassRequest(bool in_isr, uint8_t bRequest, uint16_t wValue, uint16_t wLength, uint16_t wIndex, DeviceClass::ControlTransferResult &result) override
处理类特定请求 Handle class-specific requests
virtual void OnDataOutComplete(bool in_isr, ConstRawData &data)=0
数据OUT端点传输完成处理 Handle data OUT endpoint transfer completion
bool HasIAD() override
检查是否包含IAD Check if IAD is present
static void OnDataInCompleteStatic(bool in_isr, CDCBase *self, ConstRawData &data)
数据IN端点传输完成静态回调 Static callback for data IN endpoint transfer completion
CDCBase(Endpoint::EPNumber data_in_ep_num, Endpoint::EPNumber data_out_ep_num, Endpoint::EPNumber comm_ep_num, const char *control_interface_string=DEFAULT_CONTROL_INTERFACE_STRING, const char *data_interface_string=DEFAULT_DATA_INTERFACE_STRING)
CDC构造函数 CDC constructor.
ErrorCode OnClassData(bool in_isr, uint8_t bRequest, LibXR::ConstRawData &data) override
处理类请求数据阶段 Handle class request data stage
ErrorCode SendSerialState()
发送串行状态通知 Send serial state notification
virtual void UnbindEndpoints(EndpointPool &endpoint_pool, bool) override
反初始化CDC设备 Deinitialize CDC device
size_t GetInterfaceCount() override
获取接口数量 Get number of interfaces
bool IsDtrSet() const
检查DTR状态 Check DTR state
void SetData(RawData data)
设置内部数据缓存 / Set internal data cache
USB 设备类接口基类 / USB device class interface base.
uint8_t GetInterfaceStringIndex(size_t local_interface_index) const
返回已分配的接口字符串索引 Return the assigned USB string index for a local interface.
EPNumber
端点号 Endpoint number
uint8_t GetAddress() const
获取端点地址(方向 + 号) / Get endpoint address (dir + num)
@ OUT
输出方向 / OUT direction
void SetActiveLength(uint16_t len)
设置当前活动缓冲区有效长度 / Set active buffer valid length
void SetOnTransferCompleteCallback(Callback< ConstRawData & > cb)
设置传输完成回调 / Set transfer complete callback
virtual void Configure(const Config &cfg)=0
配置端点协议参数 / Configure endpoint protocol parameters
@ INTERRUPT
中断端点 / Interrupt
virtual void Close()=0
关闭端点 / Close endpoint
uint16_t MaxPacketSize() const
获取最大包长 / Get max packet size
State GetState() const
获取端点状态 / Get endpoint state
virtual ErrorCode Transfer(size_t size)=0
启动一次传输 / Start a transfer
RawData GetBuffer() const
获取当前可用于传输的缓冲区 / Get current transfer buffer
USB端点池类 / USB endpoint pool class.
ErrorCode Release(Endpoint *ep_info)
回收端点 / Release endpoint
ErrorCode Get(Endpoint *&ep_info, Endpoint::Direction direction, Endpoint::EPNumber ep_num)
分配端点 / Allocate endpoint
ErrorCode
定义错误码枚举 / Defines an enumeration for error codes
@ NOT_SUPPORT
不支持 / Not supported
@ OK
操作成功 / Operation successful
@ ARG_ERR
参数错误 / Argument error
UART 配置结构体 / UART configuration structure.
uint8_t stop_bits
停止位长度 / Number of stop bits
uint32_t baudrate
波特率 / Baud rate
CDC描述符块结构 CDC descriptor block structure.
InterfaceDescriptor data_intf
数据接口描述符 / Data interface descriptor
uint8_t bSlaveInterface0
从接口号 / Slave interface number
EndpointDescriptor data_ep_out
数据OUT端点描述符 / Data OUT endpoint descriptor
uint16_t bcdCDC
CDC规范版本 / CDC specification version.
uint8_t bmCapabilities
呼叫管理能力 / Call management capabilities
InterfaceDescriptor comm_intf
通信接口描述符 / Communication interface descriptor
uint8_t bDataInterface
数据接口号 / Data interface number
EndpointDescriptor comm_ep
通信端点描述符 / Communication endpoint descriptor
uint8_t bMasterInterface
主接口号 / Master interface number
EndpointDescriptor data_ep_in
数据IN端点描述符 / Data IN endpoint descriptor
IADDescriptor iad
接口关联描述符 / Interface association descriptor
端点描述符(7 字节)/ Endpoint descriptor (7 bytes)
IAD(8 字节)/ Interface Association Descriptor (8 bytes)
接口描述符(9 字节)/ Interface descriptor (9 bytes)
控制请求(Class/Vendor)处理结果 / Control request (Class/Vendor) handling result
bool write_zlp
发送 STATUS IN(发送 ZLP)/ Send STATUS IN (send ZLP)