libxr
Embedded C++ framework for bare-metal, RTOS and Linux
Loading...
Searching...
No Matches
cdc_uart.cpp
1#include "cdc_uart.hpp"
2
3#include <cstring>
4
5namespace LibXR::USB
6{
7
8void CDCUart::BindEndpoints(EndpointPool& endpoint_pool, uint8_t start_itf_num,
9 bool in_isr)
10{
11 CDCBase::BindEndpoints(endpoint_pool, start_itf_num, in_isr);
12 RequestTx(in_isr);
13}
14
15void CDCUart::WriteFun(WritePort& port, bool in_isr)
16{
17 auto* cdc = LibXR::ContainerOf(&port, &CDCUart::write_port_cdc_);
18 cdc->RequestTx(in_isr);
19}
20
22{
23 UNUSED(data);
24 RequestTx(in_isr);
25}
26
27void CDCUart::RequestTx(bool in_isr)
28{
29 tx_service_.Invoke(1U, in_isr,
30 [this](uint32_t, bool owner_in_isr) { ServiceTx(owner_in_isr); });
31}
32
33void CDCUart::ServiceTx(bool in_isr)
34{
35 auto* ep = GetDataInEndpoint();
36 if (ep == nullptr || !Inited() || ep->GetState() != Endpoint::State::IDLE)
37 {
38 return;
39 }
40
41 if (need_write_zlp_)
42 {
43 if (ep->GetActiveLength() == 0U && write_port_cdc_.Size() == 0U)
44 {
45 [[maybe_unused]] const auto ans = ep->TransferZLP();
46 DEV_ASSERT_FROM_CALLBACK(ans == ErrorCode::OK, in_isr);
47 need_write_zlp_ = false;
48 return;
49 }
50 need_write_zlp_ = false;
51 }
52 ProgressTx(in_isr);
53}
54
55void CDCUart::StartTxBuffer(Endpoint& ep, [[maybe_unused]] bool in_isr)
56{
57 const size_t LENGTH = ep.GetActiveLength();
58 DEV_ASSERT_FROM_CALLBACK(LENGTH != 0U, in_isr);
59 ep.SetActiveLength(0U);
60 [[maybe_unused]] const auto ans = ep.Transfer(LENGTH);
61 REQUIRE_FROM_CALLBACK(ans == ErrorCode::OK, in_isr);
62 const size_t MPS = ep.MaxPacketSize();
63 need_write_zlp_ = MPS != 0U && LENGTH % MPS == 0U;
64}
65
66void CDCUart::FillTxBuffer(Endpoint& ep, bool in_isr)
67{
68 auto queue = write_port_cdc_.GetWriteQueue(in_isr);
69 if (queue.Empty())
70 {
71 return;
72 }
73
74 const auto buffer = ep.GetBuffer();
75 ASSERT(buffer.addr_ != nullptr && buffer.size_ != 0U);
76 const size_t LENGTH =
77 queue.PopWithWriter(buffer.size_,
78 [buffer](const uint8_t* first, size_t first_size,
79 const uint8_t* second, size_t second_size) -> size_t
80 {
81 auto* dst = static_cast<uint8_t*>(buffer.addr_);
82 if (first_size != 0U)
83 {
84 std::memcpy(dst, first, first_size);
85 }
86 if (second_size != 0U)
87 {
88 std::memcpy(dst + first_size, second, second_size);
89 }
90 return first_size + second_size;
91 });
92 DEV_ASSERT_FROM_CALLBACK(LENGTH != 0U && LENGTH <= UINT16_MAX, in_isr);
93 ep.SetActiveLength(static_cast<uint16_t>(LENGTH));
94 need_write_zlp_ = false;
95 if (ep.GetState() == Endpoint::State::IDLE)
96 {
97 StartTxBuffer(ep, in_isr);
98 }
99}
100
101void CDCUart::ProgressTx(bool in_isr)
102{
103 auto* ep = GetDataInEndpoint();
104 if (ep == nullptr || !Inited() || ep->GetState() != Endpoint::State::IDLE)
105 {
106 return;
107 }
108
109 if (ep->GetActiveLength() != 0U)
110 {
111 StartTxBuffer(*ep, in_isr);
112 }
113 else
114 {
115 FillTxBuffer(*ep, in_isr);
116 }
117
118 if (ep->GetState() == Endpoint::State::BUSY && ep->UseDoubleBuffer() &&
119 ep->GetActiveLength() == 0U)
120 {
121 FillTxBuffer(*ep, in_isr);
122 }
123}
124
125} // namespace LibXR::USB
只读原始数据视图 / Immutable raw data view
bool Invoke(uint32_t events, bool in_isr, Handler &&handler) noexcept
发布事件并尝试取得执行权 / Publish events and attempt to claim execution.
virtual void BindEndpoints(EndpointPool &endpoint_pool, uint8_t start_itf_num, bool) override
初始化CDC设备 Initialize CDC device
Definition cdc_base.hpp:258
static void WriteFun(WritePort &port, bool in_isr)
发送队列写入门铃 / Transmit queue write doorbell
Definition cdc_uart.cpp:15
void BindEndpoints(EndpointPool &endpoint_pool, uint8_t start_itf_num, bool in_isr) override
绑定端点并恢复配置前已排队的发送 / Bind endpoints and resume queued writes
Definition cdc_uart.cpp:8
void OnDataInComplete(bool in_isr, ConstRawData &data) override
在 IN 完成后请求推进发送 / Request TX progress after IN completion
Definition cdc_uart.cpp:21
USB端点池类 / USB endpoint pool class.
Definition ep_pool.hpp:29
基于 SPSC 字节队列的写端口 / Write endpoint backed by an SPSC byte queue.
WriteQueue GetWriteQueue(bool in_isr=false)
获取已提交队头的出队接口 / Obtain a consumer interface for the released front.
size_t Size() const
获取字节队列当前数据量 / Get current byte queue occupancy.
@ OK
操作成功 / Operation successful
OwnerType * ContainerOf(MemberType *ptr, MemberType OwnerType::*member) noexcept
通过成员指针恢复其所属对象指针 Recover the owning object pointer from a member pointer