libxr  1.0
Want to be the best embedded framework
Loading...
Searching...
No Matches
ep.hpp
1#pragma once
2
3#include <cstdint>
4
5#include "double_buffer.hpp"
6#include "libxr_cb.hpp"
7#include "libxr_def.hpp"
8#include "libxr_mem.hpp"
9#include "libxr_rw.hpp"
10#include "libxr_type.hpp"
11
12namespace LibXR::USB
13{
14
24{
25 public:
30 enum class Direction : uint8_t
31 {
32 OUT = 0,
33 IN = 1,
34 BOTH = 2
35 };
36
41 enum class EPNumber : uint8_t
42 {
43 EP0 = 0,
44 EP1 = 1,
45 EP2 = 2,
46 EP3 = 3,
47 EP4 = 4,
48 EP5 = 5,
49 EP6 = 6,
50 EP7 = 7,
51 EP8 = 8,
52 EP9 = 9,
53 EP10 = 10,
54 EP11 = 11,
55 EP12 = 12,
56 EP13 = 13,
57 EP14 = 14,
58 EP15 = 15,
59 EP_MAX_NUM = 16,
60 EP_AUTO = 0xFE,
61 EP_INVALID = 0xFF
62 };
63
68 enum class Type : uint8_t
69 {
70 CONTROL = 0,
71 ISOCHRONOUS = 1,
72 BULK = 2,
73 INTERRUPT = 3
74 };
75
80 enum class State : uint8_t
81 {
82 DISABLED,
83 IDLE,
84 BUSY,
85 STALLED,
86 ERROR
87 };
88
94 static constexpr uint8_t EPNumberToInt8(EPNumber ep)
95 {
96 return static_cast<uint8_t>(ep);
97 }
98
105 static constexpr uint8_t EPNumberToAddr(EPNumber ep, Direction dir)
106 {
107 ASSERT(dir == Direction::IN || dir == Direction::OUT);
108 return static_cast<uint8_t>(ep) | (dir == Direction::IN ? 0x80 : 0x00);
109 }
110
117 static constexpr EPNumber AddrToEPNumber(uint8_t addr, Direction& dir)
118 {
119 dir = addr & 0x80 ? Direction::IN : Direction::OUT;
120 return static_cast<EPNumber>(addr & 0x7F);
121 }
122
128 static constexpr EPNumber NextEPNumber(EPNumber ep)
129 {
130 ASSERT(ep <= EPNumber::EP15);
131 return static_cast<EPNumber>(EPNumberToInt8(ep) + 1);
132 }
133
138 struct Config
139 {
142 uint16_t max_packet_size = UINT16_MAX;
143 bool double_buffer = false;
144 uint8_t mult = 0;
145 };
146
153 explicit Endpoint(EPNumber number, Direction dir, RawData buffer)
154 : number_(number), avail_direction_(dir), buffer_(buffer), double_buffer_(buffer)
155 {
156 }
157
161 virtual ~Endpoint() = default;
162
163 Endpoint(const Endpoint&) = delete;
164 Endpoint& operator=(const Endpoint&) = delete;
165
170 EPNumber GetNumber() const { return number_; }
171
177
183 {
184 if (state_ == State::DISABLED)
185 {
186 return AvailableDirection();
187 }
188 return config_.direction;
189 }
190
195 uint8_t GetAddress() const
196 {
197 if (state_ == State::DISABLED)
198 {
199 return EPNumberToInt8(number_) & 0x0F;
200 }
202 }
203
208 State GetState() const { return state_; }
209
214 void SetState(State state) { state_ = state; }
215
220 Type GetType() const { return config_.type; }
221
226 uint16_t MaxPacketSize() const { return config_.max_packet_size; }
227
233 bool IsStalled() const { return state_ == State::STALLED; }
234
240 bool UseDoubleBuffer() const { return config_.double_buffer; }
241
247 {
249 {
251 }
252 else
253 {
254 return buffer_;
255 }
256 }
257
266
271 void SetActiveLength(uint16_t len) { double_buffer_.SetActiveLength(len); }
272
278
283 virtual size_t MaxTransferSize() const { return MaxPacketSize(); }
284
289 virtual void Configure(const Config& cfg) = 0;
290
294 virtual void Close() = 0;
295
300 virtual ErrorCode Stall() = 0;
301
306 virtual ErrorCode ClearStall() = 0;
307
313 virtual ErrorCode Transfer(size_t size) = 0;
314
322 {
323 auto ep_buf = GetBuffer();
324 size_t max_chunk = MaxTransferSize();
325
326 ASSERT(max_chunk > 0);
327
328 // 单包就能搞定的情况:不进入 multi-bulk 状态机,保持原有行为
329 if (data.size_ <= max_chunk)
330 {
332 {
333 multi_bulk_ = false;
335 multi_bulk_data_ = {nullptr, 0};
336
337 auto src = static_cast<const uint8_t*>(data.addr_);
338 auto dst = static_cast<uint8_t*>(ep_buf.addr_);
339 Memory::FastCopy(dst, src, data.size_);
340
341 return Transfer(data.size_);
342 }
343
344 // OUT:接收——为了把数据回填到 data,单包也走 multi-bulk
346 {
347 multi_bulk_ = true;
348 multi_bulk_data_ = data;
349 multi_bulk_remain_ = data.size_; // OUT: 剩余可写容量
350 return Transfer(data.size_);
351 }
352
353 return ErrorCode::ARG_ERR;
354 }
355
356 // 需要多包处理的情况
357 multi_bulk_ = true;
358 multi_bulk_data_ = data; // 应用层 buffer 指针 + 最大容量 / 逻辑总长
359 multi_bulk_remain_ = data.size_; // IN: 剩余待发送;OUT: 剩余可写容量
360
361 // 第一包大小
362 size_t first = max_chunk;
363 if (first > multi_bulk_remain_)
364 {
365 first = multi_bulk_remain_;
366 }
367
369 {
370 // IN:发送时,先把第一 chunk 拷到 EP buffer
371 auto src = static_cast<const uint8_t*>(multi_bulk_data_.addr_);
372 auto dst = static_cast<uint8_t*>(ep_buf.addr_);
373 Memory::FastCopy(dst, src, first);
374
375 multi_bulk_remain_ -= first; // 已经准备好 first 字节要发
376 }
377 // OUT:接收时,先启动一次接收,稍后在回调里拷贝到 multi_bulk_data_
378
379 return Transfer(first);
380 }
381
386 virtual ErrorCode TransferZLP() { return Transfer(0); }
387
393 void OnTransferCompleteCallback(bool in_isr, size_t actual_transfer_size)
394 {
395 if (GetState() != State::BUSY)
396 {
397 return;
398 }
399
400 bool callback_uses_app_buffer = false;
401 bool out_switched_before_cb = false;
402
403 const Direction DIR = GetDirection();
404 const size_t MAX_CHUNK = MaxTransferSize();
405 const bool DB = UseDoubleBuffer();
406
407 if (multi_bulk_)
408 {
409 if (DIR == Direction::IN)
410 {
411 if (multi_bulk_remain_ > 0)
412 {
413 auto ep_buf = GetBuffer(); // 此时应是“下一块 Active”(因为 Transfer 已切换)
414 const size_t SENT = multi_bulk_data_.size_ - multi_bulk_remain_;
415
416 size_t chunk = MAX_CHUNK;
417 if (chunk > multi_bulk_remain_) chunk = multi_bulk_remain_;
418
419 auto src = static_cast<const uint8_t*>(multi_bulk_data_.addr_) + SENT;
420 auto dst = static_cast<uint8_t*>(ep_buf.addr_);
421 Memory::FastCopy(dst, src, chunk);
422 multi_bulk_remain_ -= chunk;
423
425 (void)Transfer(chunk);
426 return;
427 }
428
429 // 结束:对上层报告 app buffer
430 multi_bulk_ = false;
431 callback_uses_app_buffer = true;
432 actual_transfer_size = multi_bulk_data_.size_;
433 }
434 else
435 {
436 // OUT:完成时 Active 里是数据
437 auto ep_buf = GetBuffer();
438 size_t prev_remain = multi_bulk_remain_;
439 size_t recvd = actual_transfer_size;
440 if (recvd > prev_remain)
441 {
442 recvd = prev_remain;
443 }
444
445 const size_t OFFSET = multi_bulk_data_.size_ - prev_remain;
446
447 auto dst = static_cast<uint8_t*>(multi_bulk_data_.addr_) + OFFSET;
448 auto src = static_cast<const uint8_t*>(ep_buf.addr_);
449 Memory::FastCopy(dst, src, recvd);
450
451 multi_bulk_remain_ = prev_remain - recvd;
452
453 const bool SHORT_PACKET = (recvd < MAX_CHUNK);
454 const bool BUFFER_FULL = (multi_bulk_remain_ == 0);
455
456 if (DB)
457 {
458 SwitchBuffer(); // 切换后 Pending = 刚接收的包;Active = 下次用
459 out_switched_before_cb = true;
460 }
461
462 if (!SHORT_PACKET && !BUFFER_FULL)
463 {
464 size_t chunk = MAX_CHUNK;
465 if (chunk > multi_bulk_remain_)
466 {
467 chunk = multi_bulk_remain_;
468 }
469
471 (void)Transfer(chunk); // 下一包将落到新的 Active(
472 return;
473 }
474
475 multi_bulk_ = false;
476 callback_uses_app_buffer = true;
477 actual_transfer_size = multi_bulk_data_.size_ - multi_bulk_remain_;
478 }
479 }
480
481 // 非 multi-bulk:OUT 也必须“回调前切换”
482 if (!multi_bulk_ && DB && DIR == Direction::OUT && !out_switched_before_cb)
483 {
484 SwitchBuffer();
485 out_switched_before_cb = true;
486 }
487
489
490 ConstRawData data;
491 if (callback_uses_app_buffer)
492 {
493 data = ConstRawData(multi_bulk_data_.addr_, actual_transfer_size);
494 }
495 else
496 {
497 if (DB)
498 {
499 // 回调里永远取 Pending = 刚刚完成的那包(IN/OUT 一致)
500 data = ConstRawData(double_buffer_.PendingBuffer(), actual_transfer_size);
501 }
502 else
503 {
504 data = ConstRawData(buffer_.addr_, actual_transfer_size);
505 }
506 }
507
508 on_transfer_complete_.Run(in_isr, data);
509 }
510
511 protected:
516 Config& GetConfig() { return config_; }
517
521 virtual void SwitchBuffer()
522 {
525 }
526
532 virtual void SetActiveBlock(bool active_block)
533 {
534 double_buffer_.SetActiveBlock(active_block);
536 }
537
538 private:
541
548
549 bool multi_bulk_ = false;
552 0;
553};
554
555} // namespace LibXR::USB
通用回调包装,支持动态参数传递 / Generic callback wrapper supporting dynamic argument passing
Definition libxr_cb.hpp:142
常量原始数据封装类。 A class for encapsulating constant raw data.
双缓冲区管理类 / Double buffer manager class
void SetActiveLength(size_t length)
设置当前活动缓冲区的数据长度 Sets the size of the active buffer
void SetActiveBlock(bool block)
设置当前活动缓冲区 Sets the active buffer
void EnablePending()
手动启用 pending 状态 Manually sets the pending state to true
size_t Size() const
获取每个缓冲区的大小(单位:字节) Gets the size of each buffer in bytes
uint8_t * ActiveBuffer() const
获取当前正在使用的缓冲区指针 Returns the currently active buffer
size_t GetActiveLength() const
获取当前活动缓冲区中准备好的数据长度 Gets the size of valid data in active buffer
uint8_t * PendingBuffer() const
获取备用缓冲区的指针 Returns the pending (inactive) buffer
void Switch()
切换到备用缓冲区(若其有效) Switches to the pending buffer if it's valid
static void FastCopy(void *dst, const void *src, size_t size)
快速内存拷贝 / Fast memory copy
Definition libxr_mem.cpp:5
原始数据封装类。 A class for encapsulating raw data.
size_t size_
数据大小(字节)。 The size of the data (in bytes).
void * addr_
数据存储地址。 The storage address of the data.
USB 端点基类 / USB Endpoint base class.
Definition ep.hpp:24
Endpoint(EPNumber number, Direction dir, RawData buffer)
构造函数 / Constructor
Definition ep.hpp:153
EPNumber
端点号 Endpoint number
Definition ep.hpp:42
@ EP0
端点 0 / Endpoint 0
@ EP11
端点 11 / Endpoint 11
@ EP5
端点 5 / Endpoint 5
@ EP14
端点 14 / Endpoint 14
@ EP1
端点 1 / Endpoint 1
@ EP_AUTO
自动分配端点号 / Auto allocate
@ EP8
端点 8 / Endpoint 8
@ EP2
端点 2 / Endpoint 2
@ EP7
端点 7 / Endpoint 7
@ EP4
端点 4 / Endpoint 4
@ EP15
端点 15 / Endpoint 15
@ EP_MAX_NUM
端点数量上限 / Maximum number of endpoints
@ EP13
端点 13 / Endpoint 13
@ EP10
端点 10 / Endpoint 10
@ EP3
端点 3 / Endpoint 3
@ EP6
端点 6 / Endpoint 6
@ EP9
端点 9 / Endpoint 9
@ EP_INVALID
非法端点号 / Invalid endpoint
@ EP12
端点 12 / Endpoint 12
RawData multi_bulk_data_
多包 bulk 应用层 buffer / App buffer for multi-bulk
Definition ep.hpp:550
LibXR::DoubleBuffer double_buffer_
双缓冲管理 / Double buffer manager
Definition ep.hpp:547
Direction AvailableDirection() const
获取允许配置的方向 / Get allowed endpoint direction
Definition ep.hpp:176
Type GetType() const
获取端点类型 / Get endpoint type
Definition ep.hpp:220
uint8_t GetAddress() const
获取端点地址(方向 + 号) / Get endpoint address (dir + num)
Definition ep.hpp:195
bool IsStalled() const
是否处于 STALL 状态 / Whether endpoint is stalled
Definition ep.hpp:233
static constexpr uint8_t EPNumberToInt8(EPNumber ep)
端点号转换为 uint8_t / Convert endpoint number to uint8_t
Definition ep.hpp:94
virtual ErrorCode Stall()=0
置 STALL / Stall endpoint
Direction avail_direction_
可配置方向 / Allowed direction
Definition ep.hpp:543
Direction
端点方向 Endpoint direction
Definition ep.hpp:31
@ BOTH
双向(可配置为 IN/OUT) / Both (configurable as IN/OUT)
@ IN
输入方向 / IN direction
@ OUT
输出方向 / OUT direction
static constexpr uint8_t EPNumberToAddr(EPNumber ep, Direction dir)
端点号转换为端点地址 / Convert endpoint number to endpoint address
Definition ep.hpp:105
Direction GetDirection() const
获取当前端点方向 / Get current endpoint direction
Definition ep.hpp:182
virtual ~Endpoint()=default
虚析构函数 / Virtual destructor
bool UseDoubleBuffer() const
是否启用双缓冲 / Whether double buffer is enabled
Definition ep.hpp:240
static constexpr EPNumber AddrToEPNumber(uint8_t addr, Direction &dir)
端点地址转换为端点号 / Convert endpoint address to endpoint number
Definition ep.hpp:117
State state_
当前状态 / Current state
Definition ep.hpp:545
virtual ErrorCode TransferMultiBulk(RawData &data)
Bulk 多包传输辅助接口 / Helper for multi-packet bulk transfer.
Definition ep.hpp:321
virtual void SwitchBuffer()
切换双缓冲 / Switch double buffer
Definition ep.hpp:521
Config & GetConfig()
获取当前配置引用 / Get endpoint config reference
Definition ep.hpp:516
void SetActiveLength(uint16_t len)
设置当前活动缓冲区有效长度 / Set active buffer valid length
Definition ep.hpp:271
void OnTransferCompleteCallback(bool in_isr, size_t actual_transfer_size)
由底层在传输完成时调用 / Called by low-level driver when transfer completes
Definition ep.hpp:393
EPNumber number_
端点号 / Endpoint number
Definition ep.hpp:542
virtual ErrorCode ClearStall()=0
清除 STALL / Clear stall
virtual size_t MaxTransferSize() const
返回当前最大可传输字节数 / Return maximum transferable size at this time
Definition ep.hpp:283
LibXR::RawData buffer_
端点缓冲区 / Endpoint buffer
Definition ep.hpp:546
void SetOnTransferCompleteCallback(Callback< ConstRawData & > cb)
设置传输完成回调 / Set transfer complete callback
Definition ep.hpp:262
static constexpr EPNumber NextEPNumber(EPNumber ep)
获取下一个端点号 / Get the next endpoint number
Definition ep.hpp:128
bool multi_bulk_
多包 bulk 状态机使能 / Multi-bulk state enabled
Definition ep.hpp:549
LibXR::Callback< LibXR::ConstRawData & > on_transfer_complete_
传输完成回调 / Transfer complete callback
Definition ep.hpp:540
virtual void Configure(const Config &cfg)=0
配置端点协议参数 / Configure endpoint protocol parameters
Type
端点类型 Endpoint type
Definition ep.hpp:69
@ ISOCHRONOUS
等时端点 / Isochronous
@ BULK
批量端点 / Bulk
@ INTERRUPT
中断端点 / Interrupt
@ CONTROL
控制端点 / Control
EPNumber GetNumber() const
获取端点号 / Get endpoint number
Definition ep.hpp:170
virtual void Close()=0
关闭端点 / Close endpoint
size_t GetActiveLength()
获取当前活动缓冲区有效长度 / Get active buffer valid length
Definition ep.hpp:277
uint16_t MaxPacketSize() const
获取最大包长 / Get max packet size
Definition ep.hpp:226
State
端点状态 Endpoint state
Definition ep.hpp:81
@ DISABLED
禁用 / Disabled
@ STALLED
停止/挂起 / Stalled
virtual void SetActiveBlock(bool active_block)
设置当前活动缓冲块 / Set active buffer block
Definition ep.hpp:532
void SetState(State state)
设置端点状态 / Set endpoint state
Definition ep.hpp:214
State GetState() const
获取端点状态 / Get endpoint state
Definition ep.hpp:208
virtual ErrorCode TransferZLP()
发送/接收 ZLP(零长度包) / Transfer zero length packet (ZLP)
Definition ep.hpp:386
virtual ErrorCode Transfer(size_t size)=0
启动一次传输 / Start a transfer
Config config_
当前配置 / Current configuration
Definition ep.hpp:544
RawData GetBuffer() const
获取当前可用于传输的缓冲区 / Get current transfer buffer
Definition ep.hpp:246
size_t multi_bulk_remain_
多包 bulk 剩余字节数 / Remaining bytes for multi-bulk
Definition ep.hpp:551
ErrorCode
定义错误码枚举
@ ARG_ERR
参数错误 | Argument error
端点配置参数 / Endpoint configuration parameters
Definition ep.hpp:139
Type type
端点类型 / Endpoint type
Definition ep.hpp:141
bool double_buffer
是否启用双缓冲 / Enable double buffer
Definition ep.hpp:143
uint8_t mult
多包倍数(高带宽端点) / Multiplier (high-bandwidth)
Definition ep.hpp:144
uint16_t max_packet_size
最大包长 / Max packet size
Definition ep.hpp:142
Direction direction
端点方向 / Endpoint direction
Definition ep.hpp:140