libxr  1.0
Want to be the best embedded framework
Loading...
Searching...
No Matches
daplink_v2.hpp
1#pragma once
2
3#include <cstddef>
4#include <cstdint>
5#include <cstring>
6
7#include "daplink_v2_def.hpp"
8#include "debug/swd.hpp"
9#include "dev_core.hpp"
10#include "gpio.hpp"
11#include "libxr_def.hpp"
12#include "libxr_mem.hpp"
13#include "libxr_type.hpp"
14#include "timebase.hpp"
15#include "usb/core/desc_cfg.hpp"
16#include "winusb_msos20.hpp"
17
18namespace LibXR::USB
19{
26template <typename SwdPort, uint16_t DefaultDapPacketSize = 512u,
27 uint8_t AdvertisedPacketCount = 8u, uint16_t MaxDapPacketSize = 1024u,
28 uint16_t QueuedRequestBufferSize = 2048u, uint16_t QueuedCommandCountMax = 255u>
30{
31 public:
32 static constexpr const char* DEFAULT_INTERFACE_STRING = "XRUSB CMSIS-DAP v2";
33
38 {
39 const char* vendor = nullptr;
40 const char* product = nullptr;
41 const char* serial = nullptr;
42 const char* firmware_ver = nullptr;
43
44 const char* device_vendor = nullptr;
45 const char* device_name = nullptr;
46 const char* board_vendor = nullptr;
47 const char* board_name = nullptr;
48 const char* product_fw_ver = nullptr;
49 };
50
51 public:
62 SwdPort& swd_link, LibXR::GPIO* nreset_gpio = nullptr,
65 const char* interface_string = DEFAULT_INTERFACE_STRING)
66 : DeviceClass(),
67 swd_(swd_link),
68 nreset_gpio_(nreset_gpio),
69 interface_string_(interface_string),
70 data_in_ep_num_(data_in_ep_num),
71 data_out_ep_num_(data_out_ep_num)
72 {
73 (void)swd_.SetClockHz(swj_clock_hz_);
74
75 // Init WinUSB descriptor templates (constant parts)
76 InitWinUsbDescriptors();
77 }
78
82 ~DapLinkV2Class() override = default;
83
84 DapLinkV2Class(const DapLinkV2Class&) = delete;
85 DapLinkV2Class& operator=(const DapLinkV2Class&) = delete;
86
87 public:
88 const char* GetInterfaceString(size_t local_interface_index) const override
89 {
90 return (local_interface_index == 0u) ? interface_string_ : nullptr;
91 }
92
97 void SetInfoStrings(const InfoStrings& info) { info_ = info; }
98
104
109 bool IsInited() const { return inited_; }
110
117 bool EpInBusy()
118 {
119 auto ep = ep_data_in_;
120 return ep->GetState() != Endpoint::State::IDLE;
121 }
122
130 {
131 auto ep = ep_data_out_;
132 return ep->GetState() != Endpoint::State::IDLE;
133 }
134
135 protected:
142 void BindEndpoints(EndpointPool& endpoint_pool, uint8_t start_itf_num, bool) override
143 {
144 inited_ = false;
145
146 interface_num_ = start_itf_num;
147
148 // Patch WinUSB function subset to match this interface number
149 UpdateWinUsbInterfaceFields();
150
151 // Allocate endpoints
152 auto ans =
154 ASSERT(ans == ErrorCode::OK);
155
157 ASSERT(ans == ErrorCode::OK);
158
159 // Configure endpoints
160 // - Use upper bound; core will choose a valid max packet size <= this limit.
161 // - Enable double_buffer for USB pipeline overlap.
165 {Endpoint::Direction::IN, Endpoint::Type::BULK, UINT16_MAX, true});
166
167 // Hook callbacks
170
171 // Interface descriptor (vendor specific, 2 endpoints)
172 desc_block_.intf = {9,
173 static_cast<uint8_t>(DescriptorType::INTERFACE),
175 0,
176 2,
177 0xFF, // vendor specific
178 0x00,
179 0x00,
181
182 desc_block_.ep_out = {7,
183 static_cast<uint8_t>(DescriptorType::ENDPOINT),
184 static_cast<uint8_t>(ep_data_out_->GetAddress()),
185 static_cast<uint8_t>(Endpoint::Type::BULK),
187 0};
188
189 desc_block_.ep_in = {7,
190 static_cast<uint8_t>(DescriptorType::ENDPOINT),
191 static_cast<uint8_t>(ep_data_in_->GetAddress()),
192 static_cast<uint8_t>(Endpoint::Type::BULK),
194 0};
195
196 SetData(RawData{reinterpret_cast<uint8_t*>(&desc_block_), sizeof(desc_block_)});
197
198 // Runtime defaults
199 dap_state_ = {};
200 dap_state_.debug_port = LibXR::USB::DapLinkV2Def::DebugPort::DISABLED;
202
203 swj_clock_hz_ = 1'000'000u;
204 (void)swd_.SetClockHz(swj_clock_hz_);
205
206 // SWJ shadow defaults: SWDIO=1, nRESET=1, SWCLK=0
208 swj_shadow_ = static_cast<uint8_t>(DapLinkV2Def::DAP_SWJ_SWDIO_TMS |
209 DapLinkV2Def::DAP_SWJ_NRESET);
210
211 ResetResponseQueue();
212 ResetQueuedCommandState();
214
215 inited_ = true;
216 ArmOutTransferIfIdle();
217 }
218
224 void UnbindEndpoints(EndpointPool& endpoint_pool, bool) override
225 {
226 inited_ = false;
227 ResetResponseQueue();
228 ResetQueuedCommandState();
229
230 dap_state_.debug_port = LibXR::USB::DapLinkV2Def::DebugPort::DISABLED;
232
233 if (ep_data_in_)
234 {
237 endpoint_pool.Release(ep_data_in_);
238 ep_data_in_ = nullptr;
239 }
240
241 if (ep_data_out_)
242 {
245 endpoint_pool.Release(ep_data_out_);
246 ep_data_out_ = nullptr;
247 }
248
249 swd_.Close();
250
251 // Reset shadow defaults
253 swj_shadow_ = static_cast<uint8_t>(DapLinkV2Def::DAP_SWJ_SWDIO_TMS |
254 DapLinkV2Def::DAP_SWJ_NRESET);
255 }
256
261 size_t GetInterfaceCount() override { return 1; }
262
267 bool HasIAD() override { return false; }
268
274 bool OwnsEndpoint(uint8_t ep_addr) const override
275 {
276 if (!inited_)
277 {
278 return false;
279 }
280 return (ep_data_in_ && ep_addr == ep_data_in_->GetAddress()) ||
281 (ep_data_out_ && ep_addr == ep_data_out_->GetAddress());
282 }
283
288 size_t GetMaxConfigSize() override { return sizeof(desc_block_); }
289
295 {
296 return ConstRawData{reinterpret_cast<const uint8_t*>(&winusb_msos20_),
297 sizeof(winusb_msos20_)};
298 }
299
304 size_t GetBosCapabilityCount() override { return 1; }
305
311 BosCapability* GetBosCapability(size_t index) override
312 {
313 if (index == 0)
314 {
315 return &winusb_msos20_cap_;
316 }
317 return nullptr;
318 }
319
320 private:
321 // ============================================================================
322 // Local helpers (kept with original comments, moved inside the class)
323 // ============================================================================
324
325 // 枚举/整型uint8_t。Cast enum/integer to uint8_t.
326 template <typename E>
327 static constexpr uint8_t ToU8(E e)
328 {
329 return static_cast<uint8_t>(e);
330 }
331
332 // CMSIS-DAP status bytes
333 static constexpr uint8_t DAP_OK = 0x00u;
334 static constexpr uint8_t DAP_ERROR = 0xFFu;
335
336 // 未知命令响应:单字节 0xFF。Unknown command response: single byte 0xFF.
337 static inline ErrorCode BuildUnknownCmdResponse(uint8_t* resp, uint16_t cap,
338 uint16_t& out_len)
339 {
340 if (!resp || cap < 1u)
341 {
342 out_len = 0u;
344 }
345 resp[0] = 0xFFu;
346 out_len = 1u;
347 return ErrorCode::OK;
348 }
349
350 // 命令状态响应:<cmd, status>。Command status response: <cmd, status>.
351 static inline ErrorCode BuildCmdStatusResponse(uint8_t cmd, uint8_t status,
352 uint8_t* resp, uint16_t cap,
353 uint16_t& out_len)
354 {
355 if (!resp || cap < 2u)
356 {
357 out_len = 0u;
359 }
360 resp[0] = cmd;
361 resp[1] = status;
362 out_len = 2u;
363 return ErrorCode::OK;
364 }
365
366 private:
367 // ============================================================================
368 // WinUSB descriptors
369 // ============================================================================
370
371 void InitWinUsbDescriptors()
372 {
373 winusb_msos20_.set.wLength = static_cast<uint16_t>(sizeof(winusb_msos20_.set));
374 winusb_msos20_.set.wDescriptorType =
375 LibXR::USB::WinUsbMsOs20::MS_OS_20_SET_HEADER_DESCRIPTOR;
376 winusb_msos20_.set.dwWindowsVersion = 0x06030000; // Win 8.1+
377 winusb_msos20_.set.wTotalLength = static_cast<uint16_t>(sizeof(winusb_msos20_));
378
379 winusb_msos20_.cfg.wLength = static_cast<uint16_t>(sizeof(winusb_msos20_.cfg));
380 winusb_msos20_.cfg.wDescriptorType =
381 LibXR::USB::WinUsbMsOs20::MS_OS_20_SUBSET_HEADER_CONFIGURATION;
382
383 // MS OS 2.0 configuration subset uses a zero-based configuration index.
384 winusb_msos20_.cfg.bConfigurationValue = 0u;
385 winusb_msos20_.cfg.bReserved = 0;
386 winusb_msos20_.cfg.wTotalLength = static_cast<uint16_t>(
387 sizeof(winusb_msos20_) - offsetof(WinUsbMsOs20DescSet, cfg));
388
389 winusb_msos20_.func.wLength = static_cast<uint16_t>(sizeof(winusb_msos20_.func));
390 winusb_msos20_.func.wDescriptorType =
391 LibXR::USB::WinUsbMsOs20::MS_OS_20_SUBSET_HEADER_FUNCTION;
392 winusb_msos20_.func.bReserved = 0;
393 winusb_msos20_.func.wTotalLength = static_cast<uint16_t>(
394 sizeof(winusb_msos20_) - offsetof(WinUsbMsOs20DescSet, func));
395
396 winusb_msos20_.compat.wLength = static_cast<uint16_t>(sizeof(winusb_msos20_.compat));
397 winusb_msos20_.compat.wDescriptorType =
398 LibXR::USB::WinUsbMsOs20::MS_OS_20_FEATURE_COMPATIBLE_ID;
399
400 winusb_msos20_.prop.header.wDescriptorType =
401 LibXR::USB::WinUsbMsOs20::MS_OS_20_FEATURE_REG_PROPERTY;
402 winusb_msos20_.prop.header.wPropertyDataType = LibXR::USB::WinUsbMsOs20::REG_MULTI_SZ;
403 winusb_msos20_.prop.header.wPropertyNameLength =
404 LibXR::USB::WinUsbMsOs20::PROP_NAME_DEVICE_INTERFACE_GUIDS_BYTES;
405
406 Memory::FastCopy(winusb_msos20_.prop.name,
407 LibXR::USB::WinUsbMsOs20::PROP_NAME_DEVICE_INTERFACE_GUIDS_UTF16,
408 LibXR::USB::WinUsbMsOs20::PROP_NAME_DEVICE_INTERFACE_GUIDS_BYTES);
409
410 // DeviceInterfaceGUIDs: REG_MULTI_SZ UTF-16LE, include double-NUL terminator
411 // 注意:此处为“单 GUID + NUL 结束”的 REG_MULTI_SZ / Single GUID + double-NUL end.
412 const char GUID_STR[] = "{CDB3B5AD-293B-4663-AA36-1AAE46463776}";
413 const size_t GUID_LEN = sizeof(GUID_STR) - 1;
414
415 for (size_t i = 0; i < GUID_LEN; ++i)
416 {
417 winusb_msos20_.prop.data[i * 2] = static_cast<uint8_t>(GUID_STR[i]);
418 winusb_msos20_.prop.data[i * 2 + 1] = 0x00;
419 }
420
421 // Append UTF-16 NUL + extra UTF-16 NUL (REG_MULTI_SZ end)
422 winusb_msos20_.prop.data[GUID_LEN * 2 + 0] = 0x00;
423 winusb_msos20_.prop.data[GUID_LEN * 2 + 1] = 0x00;
424 winusb_msos20_.prop.data[GUID_LEN * 2 + 2] = 0x00;
425 winusb_msos20_.prop.data[GUID_LEN * 2 + 3] = 0x00;
426
427 winusb_msos20_.prop.wPropertyDataLength = static_cast<uint16_t>((GUID_LEN * 2) + 4);
428 winusb_msos20_.prop.header.wLength =
429 static_cast<uint16_t>(sizeof(winusb_msos20_.prop));
430
431 // Sync to BOS capability object
434 }
435
436 void UpdateWinUsbInterfaceFields()
437 {
438 // Function subset interface number
439 winusb_msos20_.func.bFirstInterface = interface_num_;
440
441 // 内容变化但总长度不变;同步一次保持一致
442 // Content changes but total size stays the same; resync for consistency.
444 }
445
446 private:
447 // ============================================================================
448 // USB callbacks
449 // ============================================================================
450
454 static void OnDataOutCompleteStatic(bool in_isr, DapLinkV2Class* self,
456 {
457 if (self && self->inited_)
458 {
459 self->OnDataOutComplete(in_isr, data);
460 }
461 }
462
466 static void OnDataInCompleteStatic(bool in_isr, DapLinkV2Class* self,
468 {
469 if (self && self->inited_)
470 {
471 self->OnDataInComplete(in_isr, data);
472 }
473 }
474
478 void OnDataOutComplete(bool in_isr, LibXR::ConstRawData& data)
479 {
480 (void)in_isr;
481
482 if (!inited_ || !ep_data_in_ || !ep_data_out_)
483 {
484 return;
485 }
486
487 // 尽早 re-arm OUT 以覆盖 host->probe 流水 /
488 // Re-arm OUT early to overlap the host->probe pipeline.
489 ArmOutTransferIfIdle();
490
491 const auto* req = static_cast<const uint8_t*>(data.addr_);
492 const uint16_t REQ_LEN = static_cast<uint16_t>(data.size_);
493
494 // 快路径:IN idle 且无积压时,直接在 IN 缓冲构造响应并发包 /
495 // Fast path: build directly
496 // in IN endpoint buffer and submit without extra response copy.
497 if (!HasDeferredResponseInEpBuffer() && IsResponseQueueEmpty() &&
499 CanBuildResponseDirectlyInEpBuffer())
500 {
501 auto tx_buff = ep_data_in_->GetBuffer();
502 if (tx_buff.addr_ && tx_buff.size_ > 0u)
503 {
504 auto* tx_buf = static_cast<uint8_t*>(tx_buff.addr_);
505 uint16_t out_len = 0u;
506 auto ans = ProcessOneCommand(in_isr, req, REQ_LEN, tx_buf,
507 static_cast<uint16_t>(tx_buff.size_), out_len);
508 UNUSED(ans);
509
510 out_len = ClipResponseLength(out_len, static_cast<uint16_t>(tx_buff.size_));
511 if (StartInTransferFromCurrentBuffer(out_len))
512 {
513 return;
514 }
515
516 if (!EnqueueResponse(tx_buf, out_len))
517 {
518 (void)SubmitNextQueuedResponseIfIdle();
519 (void)EnqueueResponse(tx_buf, out_len);
520 }
521
522 (void)SubmitNextQueuedResponseIfIdle();
523 ArmOutTransferIfIdle();
524 return;
525 }
526 }
527
528 // 延迟快路径:IN busy 且无积压时,直接写入另一IN 双缓/ Deferred fast path:
529 // build next response in the other IN DB buffer to avoid queue copy.
530 if (!HasDeferredResponseInEpBuffer() && IsResponseQueueEmpty() &&
532 CanBuildResponseDirectlyInEpBuffer())
533 {
534 auto tx_buff = ep_data_in_->GetBuffer();
535 if (tx_buff.addr_ && tx_buff.size_ > 0u)
536 {
537 auto* tx_buf = static_cast<uint8_t*>(tx_buff.addr_);
538 uint16_t out_len = 0u;
539 auto ans = ProcessOneCommand(in_isr, req, REQ_LEN, tx_buf,
540 static_cast<uint16_t>(tx_buff.size_), out_len);
541 UNUSED(ans);
542
543 out_len = ClipResponseLength(out_len, static_cast<uint16_t>(tx_buff.size_));
544 SetDeferredResponseInEpBuffer(out_len);
545 ArmOutTransferIfIdle();
546 return;
547 }
548 }
549
550 if (TryBuildAndEnqueueResponse(in_isr, req, REQ_LEN))
551 {
552 (void)SubmitDeferredResponseIfIdle();
553 (void)SubmitNextQueuedResponseIfIdle();
554 ArmOutTransferIfIdle();
555 return;
556 }
557
558 // 正常背压下不应触发;这里做一best-effort 腾挪后重试队列构建
559 // Should not happen with proper backpressure; drain once and retry queue build.
560 (void)SubmitNextQueuedResponseIfIdle();
561 (void)TryBuildAndEnqueueResponse(in_isr, req, REQ_LEN);
562
563 (void)SubmitDeferredResponseIfIdle();
564 (void)SubmitNextQueuedResponseIfIdle();
565 ArmOutTransferIfIdle();
566 }
567
571 void OnDataInComplete(bool /*in_isr*/, LibXR::ConstRawData& /*data*/)
572 {
573 (void)SubmitDeferredResponseIfIdle();
574 (void)SubmitNextQueuedResponseIfIdle();
575 ArmOutTransferIfIdle();
576 }
577
578 private:
582 uint16_t GetDapPacketSize() const
583 {
584 constexpr uint16_t OPENOCD_SAFE_PS = static_cast<uint16_t>((255u * 5u) + 4u);
585 constexpr uint16_t RAW_PS =
586 (MaxDapPacketSize == 0u) ? DefaultDapPacketSize : MaxDapPacketSize;
587 return (RAW_PS > OPENOCD_SAFE_PS) ? OPENOCD_SAFE_PS : RAW_PS;
588 }
589 bool CanBuildResponseDirectlyInEpBuffer() const
590 {
591 if (!ep_data_in_)
592 {
593 return false;
594 }
595 auto tx_buff = ep_data_in_->GetBuffer();
596 if (!tx_buff.addr_ || tx_buff.size_ == 0u)
597 {
598 return false;
599 }
600 return GetDapPacketSize() <= static_cast<uint16_t>(tx_buff.size_);
601 }
602
603 bool StartInTransferFromCurrentBuffer(uint16_t len)
604 {
605 if (!ep_data_in_)
606 {
607 return false;
608 }
609 auto tx_buff = ep_data_in_->GetBuffer();
610 if (!tx_buff.addr_ || tx_buff.size_ == 0u)
611 {
612 return false;
613 }
614 uint16_t tx_len = len;
615 if (tx_len > tx_buff.size_)
616 {
617 tx_len = static_cast<uint16_t>(tx_buff.size_);
618 }
619 if (tx_len <= static_cast<uint16_t>(ep_data_in_->MaxTransferSize()))
620 {
621 return ep_data_in_->Transfer(tx_len) == ErrorCode::OK;
622 }
623 LibXR::RawData in_multi{tx_buff.addr_, tx_len};
624 return ep_data_in_->TransferMultiBulk(in_multi) == ErrorCode::OK;
625 }
626 bool StartInTransferFromPayload(const uint8_t* data, uint16_t len)
627 {
628 if (!ep_data_in_ || !data)
629 {
630 return false;
631 }
632 auto tx_buff = ep_data_in_->GetBuffer();
633 if (!tx_buff.addr_ || tx_buff.size_ == 0u)
634 {
635 return false;
636 }
637 uint16_t tx_len = len;
638 if (tx_len > MAX_DAP_PACKET_SIZE)
639 {
640 tx_len = MAX_DAP_PACKET_SIZE;
641 }
642 const uint16_t MAX_XFER = static_cast<uint16_t>(ep_data_in_->MaxTransferSize());
643 if (tx_len <= MAX_XFER && tx_len <= static_cast<uint16_t>(tx_buff.size_))
644 {
645 if (tx_len > 0u)
646 {
647 Memory::FastCopy(tx_buff.addr_, data, tx_len);
648 }
649 return ep_data_in_->Transfer(tx_len) == ErrorCode::OK;
650 }
651 if (tx_len > static_cast<uint16_t>(sizeof(in_tx_multi_storage_)))
652 {
653 tx_len = static_cast<uint16_t>(sizeof(in_tx_multi_storage_));
654 }
655 if (tx_len > 0u && data != in_tx_multi_storage_)
656 {
657 Memory::FastCopy(in_tx_multi_storage_, data, tx_len);
658 }
659 in_tx_multi_buf_.addr_ = in_tx_multi_storage_;
660 in_tx_multi_buf_.size_ = tx_len;
661 return ep_data_in_->TransferMultiBulk(in_tx_multi_buf_) == ErrorCode::OK;
662 }
663
668 uint16_t ClipResponseLength(uint16_t len, uint16_t cap) const
669 {
670 const uint16_t DAP_PS = GetDapPacketSize();
671 if (len > DAP_PS)
672 {
673 len = DAP_PS;
674 }
675 if (len > RESP_SLOT_SIZE)
676 {
677 len = RESP_SLOT_SIZE;
678 }
679 if (len > cap)
680 {
681 len = cap;
682 }
683 return len;
684 }
685
686 static constexpr uint8_t NextRespQueueIndex(uint8_t idx)
687 {
688 return static_cast<uint8_t>((idx + 1u) & (RESP_QUEUE_DEPTH - 1u));
689 }
690
691 void ResetResponseQueue()
692 {
693 resp_q_head_ = 0u;
694 resp_q_tail_ = 0u;
695 resp_q_count_ = 0u;
696 deferred_in_resp_valid_ = false;
697 deferred_in_resp_len_ = 0u;
698 }
699
700 bool HasDeferredResponseInEpBuffer() const { return deferred_in_resp_valid_; }
701
702 void SetDeferredResponseInEpBuffer(uint16_t len)
703 {
704 deferred_in_resp_len_ = len;
705 deferred_in_resp_valid_ = true;
706 }
707
708 bool SubmitDeferredResponseIfIdle()
709 {
710 if (!deferred_in_resp_valid_ || !ep_data_in_ ||
712 {
713 return false;
714 }
715
716 const uint16_t TX_LEN = deferred_in_resp_len_;
717 if (!StartInTransferFromCurrentBuffer(TX_LEN))
718 {
719 return false;
720 }
721
722 deferred_in_resp_valid_ = false;
723 deferred_in_resp_len_ = 0u;
724 return true;
725 }
726
727 bool IsResponseQueueEmpty() const { return resp_q_count_ == 0u; }
728
729 bool IsResponseQueueFull() const { return resp_q_count_ >= RESP_QUEUE_DEPTH; }
730
731 void ResetQueuedCommandState()
732 {
733 queued_request_length_ = 0u;
734 queued_command_count_ = 0u;
735 }
736
737 // ============================================================================
738 // Queued command helpers
739 // ============================================================================
740
749 bool ParseQueuedCommandLength(const uint8_t* req, uint16_t avail,
750 uint16_t& cmd_len) const
751 {
752 cmd_len = 0u;
753 if (!req || avail < 1u)
754 {
755 return false;
756 }
757
758 const uint8_t CMD = req[0];
759 switch (CMD)
760 {
761 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::INFO):
762 cmd_len = 2u;
763 return avail >= cmd_len;
764 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::HOST_STATUS):
765 cmd_len = 3u;
766 return avail >= cmd_len;
767 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::CONNECT):
768 cmd_len = 2u;
769 return avail >= cmd_len;
770 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::DISCONNECT):
771 cmd_len = 1u;
772 return avail >= cmd_len;
773 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::TRANSFER_CONFIGURE):
774 cmd_len = 6u;
775 return avail >= cmd_len;
776 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::TRANSFER_ABORT):
777 cmd_len = 1u;
778 return avail >= cmd_len;
779 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::WRITE_ABORT):
780 cmd_len = 6u;
781 return avail >= cmd_len;
782 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::DELAY):
783 cmd_len = 3u;
784 return avail >= cmd_len;
785 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::RESET_TARGET):
786 cmd_len = 1u;
787 return avail >= cmd_len;
788 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::SWJ_PINS):
789 cmd_len = 7u;
790 return avail >= cmd_len;
791 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::SWJ_CLOCK):
792 cmd_len = 5u;
793 return avail >= cmd_len;
794 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::SWD_CONFIGURE):
795 cmd_len = 2u;
796 return avail >= cmd_len;
797 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::SWJ_SEQUENCE):
798 {
799 if (avail < 2u)
800 {
801 return false;
802 }
803 const uint32_t BIT_COUNT = (req[1] == 0u) ? 256u : static_cast<uint32_t>(req[1]);
804 const uint32_t BYTE_COUNT = (BIT_COUNT + 7u) / 8u;
805 const uint32_t NEED = 2u + BYTE_COUNT;
806 if (NEED > avail)
807 {
808 return false;
809 }
810 cmd_len = static_cast<uint16_t>(NEED);
811 return true;
812 }
813 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::SWD_SEQUENCE):
814 {
815 if (avail < 2u)
816 {
817 return false;
818 }
819 const uint8_t SEQ_CNT = req[1];
820 uint32_t off = 2u;
821 for (uint32_t i = 0u; i < SEQ_CNT; ++i)
822 {
823 if (off >= avail)
824 {
825 return false;
826 }
827
828 const uint8_t INFO = req[off++];
829 uint32_t cycles = static_cast<uint32_t>(INFO & 0x3Fu);
830 if (cycles == 0u)
831 {
832 cycles = 64u;
833 }
834
835 const bool MODE_IN = ((INFO & 0x80u) != 0u);
836 const uint32_t BYTES = (cycles + 7u) / 8u;
837 if (!MODE_IN)
838 {
839 if (off + BYTES > avail)
840 {
841 return false;
842 }
843 off += BYTES;
844 }
845 }
846 cmd_len = static_cast<uint16_t>(off);
847 return true;
848 }
849 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::TRANSFER):
850 {
851 if (avail < 3u)
852 {
853 return false;
854 }
855 const uint8_t COUNT = req[2];
856 uint32_t off = 3u;
857 for (uint32_t i = 0u; i < COUNT; ++i)
858 {
859 if (off >= avail)
860 {
861 return false;
862 }
863
864 const uint8_t RQ = req[off++];
865 const bool RNW = LibXR::USB::DapLinkV2Def::req_is_read(RQ);
866 const bool MATCH_VALUE =
867 ((RQ & LibXR::USB::DapLinkV2Def::DAP_TRANSFER_MATCH_VALUE) != 0u);
868 if (!RNW || MATCH_VALUE)
869 {
870 if (off + 4u > avail)
871 {
872 return false;
873 }
874 off += 4u;
875 }
876 }
877 cmd_len = static_cast<uint16_t>(off);
878 return true;
879 }
880 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::TRANSFER_BLOCK):
881 {
882 if (avail < 5u)
883 {
884 return false;
885 }
886 uint16_t count = 0u;
887 Memory::FastCopy(&count, &req[2], sizeof(count));
888 const bool RNW = LibXR::USB::DapLinkV2Def::req_is_read(req[4]);
889 uint32_t need = 5u;
890 if (!RNW)
891 {
892 need += static_cast<uint32_t>(count) * 4u;
893 }
894 if (need > avail)
895 {
896 return false;
897 }
898 cmd_len = static_cast<uint16_t>(need);
899 return true;
900 }
901
902 // Reject nested queue/execute in queued stream.
903 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::QUEUE_COMMANDS):
904 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::EXECUTE_COMMANDS):
905 default:
906 return false;
907 }
908 }
909
919 bool TryExecuteQueuedCommandStream(bool in_isr, uint8_t* resp, uint16_t resp_cap,
920 uint16_t& out_len)
921 {
922 out_len = 0u;
923 if (!resp || resp_cap < 1u)
924 {
925 return false;
926 }
927
928 resp[0] = ToU8(LibXR::USB::DapLinkV2Def::CommandId::EXECUTE_COMMANDS);
929 out_len = 1u;
930
931 if (queued_command_count_ == 0u)
932 {
933 return true;
934 }
935
936 uint16_t req_off = 0u;
937 uint16_t resp_off = 1u;
938 for (uint32_t i = 0u; i < queued_command_count_; ++i)
939 {
940 if (req_off >= queued_request_length_)
941 {
942 return false;
943 }
944
945 uint16_t cmd_len = 0u;
947 &queued_request_buffer_[req_off],
948 static_cast<uint16_t>(queued_request_length_ - req_off), cmd_len) ||
949 cmd_len == 0u)
950 {
951 return false;
952 }
953
954 if (resp_off >= resp_cap)
955 {
956 return false;
957 }
958
959 uint16_t cmd_out = 0u;
960 const ErrorCode ans = ProcessOneCommand(
961 in_isr, &queued_request_buffer_[req_off], cmd_len, &resp[resp_off],
962 static_cast<uint16_t>(resp_cap - resp_off), cmd_out);
963 UNUSED(ans);
964
965 if (static_cast<uint32_t>(resp_off) + static_cast<uint32_t>(cmd_out) >
966 static_cast<uint32_t>(resp_cap))
967 {
968 return false;
969 }
970
971 req_off = static_cast<uint16_t>(req_off + cmd_len);
972 resp_off = static_cast<uint16_t>(resp_off + cmd_out);
973 }
974
975 if (req_off != queued_request_length_)
976 {
977 return false;
978 }
979
980 out_len = resp_off;
981 return true;
982 }
983
984 bool TryBuildAndEnqueueResponse(bool in_isr, const uint8_t* req, uint16_t req_len)
985 {
986 if (!req || IsResponseQueueFull())
987 {
988 return false;
989 }
990
991 auto& slot = resp_q_[resp_q_tail_];
992 uint16_t out_len = 0u;
993 auto ans =
994 ProcessOneCommand(in_isr, req, req_len, slot.payload, RESP_SLOT_SIZE, out_len);
995 UNUSED(ans);
996 slot.len = ClipResponseLength(out_len, RESP_SLOT_SIZE);
997
998 resp_q_tail_ = NextRespQueueIndex(resp_q_tail_);
999 ++resp_q_count_;
1000 return true;
1001 }
1002
1003 uint8_t OutstandingResponseCount() const
1004 {
1005 const uint8_t IN_FLIGHT =
1007 const uint8_t DEFERRED = deferred_in_resp_valid_ ? 1u : 0u;
1008 return static_cast<uint8_t>(resp_q_count_ + IN_FLIGHT + DEFERRED);
1009 }
1010
1011 bool EnqueueResponse(const uint8_t* data, uint16_t len)
1012 {
1013 if (!data || IsResponseQueueFull())
1014 {
1015 return false;
1016 }
1017
1018 auto& slot = resp_q_[resp_q_tail_];
1019 const uint16_t CLIPPED = ClipResponseLength(len, RESP_SLOT_SIZE);
1020 slot.len = CLIPPED;
1021 if (CLIPPED > 0u)
1022 {
1023 Memory::FastCopy(slot.payload, data, CLIPPED);
1024 }
1025
1026 resp_q_tail_ = NextRespQueueIndex(resp_q_tail_);
1027 ++resp_q_count_;
1028 return true;
1029 }
1030
1031 bool SubmitNextQueuedResponseIfIdle()
1032 {
1034 IsResponseQueueEmpty())
1035 {
1036 return false;
1037 }
1038 auto& slot = resp_q_[resp_q_head_];
1039 if (!StartInTransferFromPayload(slot.payload, slot.len))
1040 {
1041 return false;
1042 }
1043 resp_q_head_ = NextRespQueueIndex(resp_q_head_);
1044 --resp_q_count_;
1045 return true;
1046 }
1047
1048 void ArmOutTransferIfIdle()
1049 {
1050 if (!inited_ || ep_data_out_ == nullptr || ep_data_in_ == nullptr)
1051 {
1052 return;
1053 }
1054
1056 {
1057 return;
1058 }
1059
1060 // 对总未完成响应做背压(in-flight + queued Backpressure on total outstanding
1061 // responses (in-flight + queued).
1062 if (OutstandingResponseCount() >= MAX_OUTSTANDING_RESPONSES)
1063 {
1064 return;
1065 }
1066
1067 uint16_t out_rx_len = GetDapPacketSize();
1068 if (out_rx_len == 0u)
1069 {
1070 out_rx_len = DEFAULT_DAP_PACKET_SIZE;
1071 }
1072 if (out_rx_len > MAX_DAP_PACKET_SIZE)
1073 {
1074 out_rx_len = MAX_DAP_PACKET_SIZE;
1075 }
1076
1077 const uint16_t OUT_MAX_XFER = static_cast<uint16_t>(ep_data_out_->MaxTransferSize());
1078 if (OUT_MAX_XFER == 0u)
1079 {
1080 return;
1081 }
1082
1083 if (out_rx_len <= OUT_MAX_XFER)
1084 {
1085 (void)ep_data_out_->Transfer(out_rx_len);
1086 return;
1087 }
1088
1089 if (out_rx_len > static_cast<uint16_t>(sizeof(out_req_multi_storage_)))
1090 {
1091 out_rx_len = static_cast<uint16_t>(sizeof(out_req_multi_storage_));
1092 }
1093
1094 // Endpoint MPS is capped by hardware (HS bulk = 512), so larger DAP requests
1095 // must be received with multi-bulk reassembly.
1096 out_req_multi_buf_.addr_ = out_req_multi_storage_;
1097 out_req_multi_buf_.size_ = out_rx_len;
1098 (void)ep_data_out_->TransferMultiBulk(out_req_multi_buf_);
1099 }
1100
1101 private:
1102 // ============================================================================
1103 // Command dispatch
1104 // ============================================================================
1105
1117 ErrorCode ProcessOneCommand(bool in_isr, const uint8_t* req, uint16_t req_len,
1118 uint8_t* resp, uint16_t resp_cap, uint16_t& out_len)
1119 {
1120 out_len = 0;
1121
1122 if (!req || !resp || req_len < 1u || resp_cap < 1u)
1123 {
1124 if (resp && resp_cap >= 1u)
1125 {
1126 BuildNotSupportResponse(resp, resp_cap, out_len);
1127 }
1128 return ErrorCode::ARG_ERR;
1129 }
1130
1131 const uint8_t CMD = req[0];
1132
1133 switch (CMD)
1134 {
1135 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::INFO):
1136 return HandleInfo(in_isr, req, req_len, resp, resp_cap, out_len);
1137 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::HOST_STATUS):
1138 return HandleHostStatus(in_isr, req, req_len, resp, resp_cap, out_len);
1139 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::CONNECT):
1140 return HandleConnect(in_isr, req, req_len, resp, resp_cap, out_len);
1141 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::DISCONNECT):
1142 return HandleDisconnect(in_isr, req, req_len, resp, resp_cap, out_len);
1143 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::TRANSFER_CONFIGURE):
1144 return HandleTransferConfigure(in_isr, req, req_len, resp, resp_cap, out_len);
1145 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::TRANSFER):
1146 return HandleTransfer(in_isr, req, req_len, resp, resp_cap, out_len);
1147 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::TRANSFER_BLOCK):
1148 return HandleTransferBlock(in_isr, req, req_len, resp, resp_cap, out_len);
1149 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::TRANSFER_ABORT):
1150 return HandleTransferAbort(in_isr, req, req_len, resp, resp_cap, out_len);
1151 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::WRITE_ABORT):
1152 return HandleWriteABORT(in_isr, req, req_len, resp, resp_cap, out_len);
1153 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::DELAY):
1154 return HandleDelay(in_isr, req, req_len, resp, resp_cap, out_len);
1155 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::RESET_TARGET):
1156 return HandleResetTarget(in_isr, req, req_len, resp, resp_cap, out_len);
1157
1158 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::SWJ_PINS):
1159 return HandleSWJPins(in_isr, req, req_len, resp, resp_cap, out_len);
1160 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::SWJ_CLOCK):
1161 return HandleSWJClock(in_isr, req, req_len, resp, resp_cap, out_len);
1162 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::SWJ_SEQUENCE):
1163 return HandleSWJSequence(in_isr, req, req_len, resp, resp_cap, out_len);
1164 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::SWD_CONFIGURE):
1165 return HandleSWDConfigure(in_isr, req, req_len, resp, resp_cap, out_len);
1166 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::SWD_SEQUENCE):
1167 return HandleSWDSequence(in_isr, req, req_len, resp, resp_cap, out_len);
1168
1169 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::QUEUE_COMMANDS):
1170 return HandleQueueCommands(in_isr, req, req_len, resp, resp_cap, out_len);
1171 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::EXECUTE_COMMANDS):
1172 return HandleExecuteCommands(in_isr, req, req_len, resp, resp_cap, out_len);
1173
1174 default:
1175 (void)BuildUnknownCmdResponse(resp, resp_cap, out_len);
1177 }
1178 }
1179
1187 void BuildNotSupportResponse(uint8_t* resp, uint16_t resp_cap, uint16_t& out_len)
1188 {
1189 if (!resp || resp_cap < 1u)
1190 {
1191 out_len = 0u;
1192 return;
1193 }
1194 resp[0] = 0xFFu;
1195 out_len = 1u;
1196 }
1197
1198 private:
1199 // ============================================================================
1200 // DAP_Info
1201 // ============================================================================
1202
1203 ErrorCode HandleInfo(bool /*in_isr*/, const uint8_t* req, uint16_t req_len,
1204 uint8_t* resp, uint16_t resp_cap, uint16_t& out_len)
1205 {
1206 if (req_len < 2u)
1207 {
1208 resp[0] = ToU8(LibXR::USB::DapLinkV2Def::CommandId::INFO);
1209 resp[1] = 0u;
1210 out_len = 2u;
1211 return ErrorCode::ARG_ERR;
1212 }
1213
1214 const uint8_t INFO_ID = req[1];
1215
1216 resp[0] = ToU8(LibXR::USB::DapLinkV2Def::CommandId::INFO);
1217
1218 switch (INFO_ID)
1219 {
1220 case ToU8(LibXR::USB::DapLinkV2Def::InfoId::VENDOR):
1221 return BuildInfoStringResponse(resp[0], info_.vendor, resp, resp_cap, out_len);
1222 case ToU8(LibXR::USB::DapLinkV2Def::InfoId::PRODUCT):
1223 return BuildInfoStringResponse(resp[0], info_.product, resp, resp_cap, out_len);
1224 case ToU8(LibXR::USB::DapLinkV2Def::InfoId::SERIAL_NUMBER):
1225 return BuildInfoStringResponse(resp[0], info_.serial, resp, resp_cap, out_len);
1226 case ToU8(LibXR::USB::DapLinkV2Def::InfoId::FIRMWARE_VERSION):
1227 return BuildInfoStringResponse(resp[0], info_.firmware_ver, resp, resp_cap,
1228 out_len);
1229
1230 case ToU8(LibXR::USB::DapLinkV2Def::InfoId::DEVICE_VENDOR):
1231 return BuildInfoStringResponse(resp[0], info_.device_vendor, resp, resp_cap,
1232 out_len);
1233 case ToU8(LibXR::USB::DapLinkV2Def::InfoId::DEVICE_NAME):
1234 return BuildInfoStringResponse(resp[0], info_.device_name, resp, resp_cap,
1235 out_len);
1236 case ToU8(LibXR::USB::DapLinkV2Def::InfoId::BOARD_VENDOR):
1237 return BuildInfoStringResponse(resp[0], info_.board_vendor, resp, resp_cap,
1238 out_len);
1239 case ToU8(LibXR::USB::DapLinkV2Def::InfoId::BOARD_NAME):
1240 return BuildInfoStringResponse(resp[0], info_.board_name, resp, resp_cap,
1241 out_len);
1242 case ToU8(LibXR::USB::DapLinkV2Def::InfoId::PRODUCT_FIRMWARE_VERSION):
1243 return BuildInfoStringResponse(resp[0], info_.product_fw_ver, resp, resp_cap,
1244 out_len);
1245
1246 case ToU8(LibXR::USB::DapLinkV2Def::InfoId::CAPABILITIES):
1247 return BuildInfoU8Response(resp[0], LibXR::USB::DapLinkV2Def::DAP_CAP_SWD, resp,
1248 resp_cap, out_len);
1249 case ToU8(LibXR::USB::DapLinkV2Def::InfoId::PACKET_COUNT):
1250 return BuildInfoU8Response(resp[0], PACKET_COUNT_EFFECTIVE, resp, resp_cap,
1251 out_len);
1252 case ToU8(LibXR::USB::DapLinkV2Def::InfoId::PACKET_SIZE):
1253 {
1254 const uint16_t DAP_PS = GetDapPacketSize();
1255 return BuildInfoU16Response(resp[0], DAP_PS, resp, resp_cap, out_len);
1256 }
1257 case ToU8(LibXR::USB::DapLinkV2Def::InfoId::TIMESTAMP_CLOCK):
1258 return BuildInfoU32Response(resp[0], 1000000U, resp, resp_cap, out_len);
1259
1260 default:
1261 resp[1] = 0u;
1262 out_len = 2u;
1263 return ErrorCode::OK;
1264 }
1265 }
1266
1267 ErrorCode BuildInfoStringResponse(uint8_t cmd, const char* str, uint8_t* resp,
1268 uint16_t resp_cap, uint16_t& out_len)
1269 {
1270 resp[0] = cmd;
1271 resp[1] = 0u;
1272
1273 if (!str)
1274 {
1275 out_len = 2u;
1276 return ErrorCode::OK;
1277 }
1278
1279 const size_t N_WITH_NUL = std::strlen(str) + 1; // include '\0'
1280 const size_t MAX_PAYLOAD = (resp_cap >= 2u) ? (resp_cap - 2u) : 0u;
1281 if (MAX_PAYLOAD == 0u)
1282 {
1283 out_len = 2u;
1284 return ErrorCode::OK;
1285 }
1286
1287 const size_t COPY_N = (N_WITH_NUL > MAX_PAYLOAD) ? MAX_PAYLOAD : N_WITH_NUL;
1288 Memory::FastCopy(&resp[2], str, COPY_N);
1289
1290 // Ensure termination even when truncated
1291 resp[2 + COPY_N - 1] = 0x00;
1292
1293 resp[1] = static_cast<uint8_t>(COPY_N);
1294 out_len = static_cast<uint16_t>(2u + COPY_N);
1295 return ErrorCode::OK;
1296 }
1297
1298 ErrorCode BuildInfoU8Response(uint8_t cmd, uint8_t val, uint8_t* resp,
1299 uint16_t resp_cap, uint16_t& out_len)
1300 {
1301 if (resp_cap < 3u)
1302 {
1303 out_len = 0;
1304 return ErrorCode::NOT_FOUND;
1305 }
1306 resp[0] = cmd;
1307 resp[1] = 1u;
1308 resp[2] = val;
1309 out_len = 3u;
1310 return ErrorCode::OK;
1311 }
1312
1313 ErrorCode BuildInfoU16Response(uint8_t cmd, uint16_t val, uint8_t* resp,
1314 uint16_t resp_cap, uint16_t& out_len)
1315 {
1316 if (resp_cap < 4u)
1317 {
1318 out_len = 0;
1319 return ErrorCode::NOT_FOUND;
1320 }
1321 resp[0] = cmd;
1322 resp[1] = 2u;
1323
1324 // Little-endian device only: direct memcpy to payload (alignment-safe).
1325 Memory::FastCopy(&resp[2], &val, sizeof(val));
1326
1327 out_len = 4u;
1328 return ErrorCode::OK;
1329 }
1330
1331 ErrorCode BuildInfoU32Response(uint8_t cmd, uint32_t val, uint8_t* resp,
1332 uint16_t resp_cap, uint16_t& out_len)
1333 {
1334 if (resp_cap < 6u)
1335 {
1336 out_len = 0;
1337 return ErrorCode::NOT_FOUND;
1338 }
1339 resp[0] = cmd;
1340 resp[1] = 4u;
1341
1342 // Little-endian device only: direct memcpy to payload (alignment-safe).
1343 Memory::FastCopy(&resp[2], &val, sizeof(val));
1344
1345 out_len = 6u;
1346 return ErrorCode::OK;
1347 }
1348
1349 private:
1350 // ============================================================================
1351 // Simple control handlers
1352 // ============================================================================
1353
1354 ErrorCode HandleHostStatus(bool /*in_isr*/, const uint8_t* /*req*/,
1355 uint16_t /*req_len*/, uint8_t* resp, uint16_t resp_cap,
1356 uint16_t& out_len)
1357 {
1358 if (resp_cap < 2u)
1359 {
1360 out_len = 0;
1361 return ErrorCode::NOT_FOUND;
1362 }
1363 resp[0] = ToU8(LibXR::USB::DapLinkV2Def::CommandId::HOST_STATUS);
1364 resp[1] = ToU8(LibXR::USB::DapLinkV2Def::Status::OK);
1365 out_len = 2u;
1366 return ErrorCode::OK;
1367 }
1368
1369 ErrorCode HandleConnect(bool /*in_isr*/, const uint8_t* req, uint16_t req_len,
1370 uint8_t* resp, uint16_t resp_cap, uint16_t& out_len)
1371 {
1372 if (resp_cap < 2u)
1373 {
1374 out_len = 0;
1375 return ErrorCode::NOT_FOUND;
1376 }
1377
1378 resp[0] = ToU8(LibXR::USB::DapLinkV2Def::CommandId::CONNECT);
1379
1380 uint8_t port = 0u;
1381 if (req_len >= 2u)
1382 {
1383 port = req[1];
1384 }
1385
1386 // SWD-only
1387 if (port == 0u || port == ToU8(LibXR::USB::DapLinkV2Def::Port::SWD))
1388 {
1389 (void)swd_.EnterSwd();
1390 (void)swd_.SetClockHz(swj_clock_hz_);
1391
1392 dap_state_.debug_port = LibXR::USB::DapLinkV2Def::DebugPort::SWD;
1393 dap_state_.transfer_abort = false;
1394 ResetQueuedCommandState();
1395
1396 resp[1] = ToU8(LibXR::USB::DapLinkV2Def::Port::SWD);
1397 }
1398 else
1399 {
1400 resp[1] = ToU8(LibXR::USB::DapLinkV2Def::Port::DISABLED);
1401 }
1402
1403 out_len = 2u;
1404 return ErrorCode::OK;
1405 }
1406
1407 ErrorCode HandleDisconnect(bool /*in_isr*/, const uint8_t* /*req*/,
1408 uint16_t /*req_len*/, uint8_t* resp, uint16_t resp_cap,
1409 uint16_t& out_len)
1410 {
1411 if (resp_cap < 2u)
1412 {
1413 out_len = 0;
1414 return ErrorCode::NOT_FOUND;
1415 }
1416
1417 swd_.Close();
1418 dap_state_.debug_port = LibXR::USB::DapLinkV2Def::DebugPort::DISABLED;
1419 dap_state_.transfer_abort = false;
1420 ResetQueuedCommandState();
1421
1422 resp[0] = ToU8(LibXR::USB::DapLinkV2Def::CommandId::DISCONNECT);
1423 resp[1] = ToU8(LibXR::USB::DapLinkV2Def::Status::OK);
1424 out_len = 2u;
1425 return ErrorCode::OK;
1426 }
1427
1428 ErrorCode HandleTransferConfigure(bool /*in_isr*/, const uint8_t* req, uint16_t req_len,
1429 uint8_t* resp, uint16_t resp_cap, uint16_t& out_len)
1430 {
1431 if (resp_cap < 2u)
1432 {
1433 out_len = 0;
1434 return ErrorCode::NOT_FOUND;
1435 }
1436
1437 resp[0] = ToU8(LibXR::USB::DapLinkV2Def::CommandId::TRANSFER_CONFIGURE);
1438
1439 // Req: [0]=0x04 [1]=idle_cycles [2..3]=wait_retry [4..5]=match_retry
1440 if (req_len < 6u)
1441 {
1442 resp[1] = ToU8(LibXR::USB::DapLinkV2Def::Status::ERROR);
1443 out_len = 2u;
1444 return ErrorCode::ARG_ERR;
1445 }
1446
1447 const uint8_t IDLE = req[1];
1448
1449 uint16_t wait_retry = 0u;
1450 uint16_t match_retry = 0u;
1451 Memory::FastCopy(&wait_retry, &req[2], sizeof(wait_retry));
1452 Memory::FastCopy(&match_retry, &req[4], sizeof(match_retry));
1453
1455 dap_state_.transfer_cfg.retry_count = wait_retry;
1456 dap_state_.transfer_cfg.match_retry = match_retry;
1457
1458 // Map to SWD transaction policy
1459 Debug::Swd::TransferPolicy pol = swd_.GetTransferPolicy();
1460 pol.idle_cycles = IDLE;
1461 pol.wait_retry = wait_retry;
1462 swd_.SetTransferPolicy(pol);
1463
1464 resp[1] = ToU8(LibXR::USB::DapLinkV2Def::Status::OK);
1465 out_len = 2u;
1466 return ErrorCode::OK;
1467 }
1468
1469 ErrorCode HandleTransferAbort(bool /*in_isr*/, const uint8_t* /*req*/,
1470 uint16_t /*req_len*/, uint8_t* resp, uint16_t resp_cap,
1471 uint16_t& out_len)
1472 {
1473 if (resp_cap < 2u)
1474 {
1475 out_len = 0;
1476 return ErrorCode::NOT_FOUND;
1477 }
1478
1479 SetTransferAbortFlag(true);
1480
1481 resp[0] = ToU8(LibXR::USB::DapLinkV2Def::CommandId::TRANSFER_ABORT);
1482 resp[1] = ToU8(LibXR::USB::DapLinkV2Def::Status::OK);
1483 out_len = 2u;
1484 return ErrorCode::OK;
1485 }
1486
1487 ErrorCode HandleWriteABORT(bool /*in_isr*/, const uint8_t* req, uint16_t req_len,
1488 uint8_t* resp, uint16_t resp_cap, uint16_t& out_len)
1489 {
1490 if (resp_cap < 2u)
1491 {
1492 out_len = 0;
1493 return ErrorCode::NOT_FOUND;
1494 }
1495
1496 resp[0] = ToU8(LibXR::USB::DapLinkV2Def::CommandId::WRITE_ABORT);
1497
1498 if (req_len < 6u)
1499 {
1500 resp[1] = ToU8(LibXR::USB::DapLinkV2Def::Status::ERROR);
1501 out_len = 2u;
1502 return ErrorCode::ARG_ERR;
1503 }
1504
1505 uint32_t flags = 0u;
1506 Memory::FastCopy(&flags, &req[2], sizeof(flags));
1507
1508 LibXR::Debug::SwdProtocol::Ack ack = LibXR::Debug::SwdProtocol::Ack::PROTOCOL;
1509
1510 const ErrorCode EC = swd_.WriteAbortTxn(flags, ack);
1511 resp[1] = (EC == ErrorCode::OK && ack == LibXR::Debug::SwdProtocol::Ack::OK)
1512 ? ToU8(LibXR::USB::DapLinkV2Def::Status::OK)
1513 : ToU8(LibXR::USB::DapLinkV2Def::Status::ERROR);
1514
1515 out_len = 2u;
1516 return ErrorCode::OK;
1517 }
1518
1519 ErrorCode HandleDelay(bool /*in_isr*/, const uint8_t* req, uint16_t req_len,
1520 uint8_t* resp, uint16_t resp_cap, uint16_t& out_len)
1521 {
1522 if (resp_cap < 2u)
1523 {
1524 out_len = 0;
1525 return ErrorCode::NOT_FOUND;
1526 }
1527
1528 resp[0] = ToU8(LibXR::USB::DapLinkV2Def::CommandId::DELAY);
1529
1530 if (req_len < 3u)
1531 {
1532 resp[1] = ToU8(LibXR::USB::DapLinkV2Def::Status::ERROR);
1533 out_len = 2u;
1534 return ErrorCode::ARG_ERR;
1535 }
1536
1537 uint16_t us = 0u;
1538 Memory::FastCopy(&us, &req[1], sizeof(us));
1539
1541
1542 resp[1] = ToU8(LibXR::USB::DapLinkV2Def::Status::OK);
1543 out_len = 2u;
1544 return ErrorCode::OK;
1545 }
1546
1547 ErrorCode HandleResetTarget(bool in_isr, const uint8_t* /*req*/, uint16_t /*req_len*/,
1548 uint8_t* resp, uint16_t resp_cap, uint16_t& out_len)
1549 {
1550 if (!resp || resp_cap < 3u)
1551 {
1552 out_len = 0u;
1553 return ErrorCode::NOT_FOUND;
1554 }
1555
1556 resp[0] = ToU8(LibXR::USB::DapLinkV2Def::CommandId::RESET_TARGET);
1557
1558 uint8_t execute = 0u;
1559
1560 if (nreset_gpio_ != nullptr)
1561 {
1562 DriveReset(false);
1563 DelayUsIfAllowed(in_isr, 1000u);
1564 DriveReset(true);
1565 DelayUsIfAllowed(in_isr, 1000u);
1566 execute = 1u;
1567 }
1568
1569 // 关键:无论是否实reset,都返回 DAP_OK;未实现Execute=0
1570 // Key: Always return DAP_OK; if not implemented, Execute=0.
1571 resp[1] = DAP_OK;
1572 resp[2] = execute;
1573 out_len = 3u;
1574 return ErrorCode::OK;
1575 }
1576
1577 private:
1578 // ============================================================================
1579 // SWJ / SWD handlers
1580 // ============================================================================
1581 ErrorCode HandleSWJPins(bool /*in_isr*/, const uint8_t* req, uint16_t req_len,
1582 uint8_t* resp, uint16_t resp_cap, uint16_t& out_len)
1583 {
1584 if (!resp || resp_cap < 2u)
1585 {
1586 out_len = 0u;
1587 return ErrorCode::NOT_FOUND;
1588 }
1589
1590 resp[0] = ToU8(LibXR::USB::DapLinkV2Def::CommandId::SWJ_PINS);
1591
1592 // Req: [0]=0x10 [1]=PinOut [2]=PinSelect [3..6]=PinWait(us)
1593 if (!req || req_len < 7u)
1594 {
1595 resp[1] = 0u;
1596 out_len = 2u;
1597 return ErrorCode::ARG_ERR;
1598 }
1599
1600 const uint8_t PIN_OUT = req[1];
1601 const uint8_t PIN_SEL = req[2];
1602
1603 uint32_t wait_us = 0u;
1604 Memory::FastCopy(&wait_us, &req[3], sizeof(wait_us));
1605
1606 // 0) Latch requested states into shadow for ALL selected pins (even if unsupported)
1607 swj_shadow_ = static_cast<uint8_t>((swj_shadow_ & static_cast<uint8_t>(~PIN_SEL)) |
1608 (PIN_OUT & PIN_SEL));
1609
1610 // 1) Only physically support nRESET (best-effort)
1611 if ((PIN_SEL & LibXR::USB::DapLinkV2Def::DAP_SWJ_NRESET) != 0u)
1612 {
1613 const bool LEVEL_HIGH =
1614 ((PIN_OUT & LibXR::USB::DapLinkV2Def::DAP_SWJ_NRESET) != 0u);
1615 // DriveReset updates last_nreset_level_high_ and shadow, and writes GPIO if
1616 // present.
1617 DriveReset(LEVEL_HIGH);
1618 }
1619
1620 // Read helper: start from shadow; override nRESET with physical level if wired.
1621 auto read_pins = [&]() -> uint8_t
1622 {
1623 uint8_t pin_in = swj_shadow_;
1624
1625 if (nreset_gpio_ != nullptr)
1626 {
1627 if (nreset_gpio_->Read())
1628 {
1629 pin_in |= LibXR::USB::DapLinkV2Def::DAP_SWJ_NRESET;
1630 }
1631 else
1632 {
1633 pin_in = static_cast<uint8_t>(
1634 pin_in & static_cast<uint8_t>(~LibXR::USB::DapLinkV2Def::DAP_SWJ_NRESET));
1635 }
1636 }
1637
1638 return pin_in;
1639 };
1640
1641 // 2) PinWait: wait until (PinInput & PinSelect) matches (PinOut & PinSelect), or
1642 // timeout. Since SWCLK/SWDIO are shadow-only now, their selected bits will already
1643 // match immediately.
1644 uint8_t pin_in = 0u;
1645
1646 if (wait_us == 0u || PIN_SEL == 0u)
1647 {
1648 pin_in = read_pins();
1649 }
1650 else
1651 {
1652 const uint64_t START = LibXR::Timebase::GetMicroseconds();
1653 const uint8_t EXPECT = static_cast<uint8_t>(PIN_OUT & PIN_SEL);
1654
1655 do
1656 {
1657 pin_in = read_pins();
1658 if ((pin_in & PIN_SEL) == EXPECT)
1659 {
1660 break;
1661 }
1662 } while ((static_cast<uint64_t>(LibXR::Timebase::GetMicroseconds()) - START) <
1663 wait_us);
1664 }
1665
1666 resp[1] = pin_in;
1667 out_len = 2u;
1668 return ErrorCode::OK;
1669 }
1670
1671 ErrorCode HandleSWJClock(bool /*in_isr*/, const uint8_t* req, uint16_t req_len,
1672 uint8_t* resp, uint16_t resp_cap, uint16_t& out_len)
1673 {
1674 if (resp_cap < 2u)
1675 {
1676 out_len = 0;
1677 return ErrorCode::NOT_FOUND;
1678 }
1679
1680 resp[0] = ToU8(LibXR::USB::DapLinkV2Def::CommandId::SWJ_CLOCK);
1681
1682 if (req_len < 5u)
1683 {
1684 resp[1] = ToU8(LibXR::USB::DapLinkV2Def::Status::ERROR);
1685 out_len = 2u;
1686 return ErrorCode::ARG_ERR;
1687 }
1688
1689 uint32_t hz = 0u;
1690 Memory::FastCopy(&hz, &req[1], sizeof(hz));
1691
1692 swj_clock_hz_ = hz;
1693 (void)swd_.SetClockHz(hz);
1694
1695 resp[1] = ToU8(LibXR::USB::DapLinkV2Def::Status::OK);
1696 out_len = 2u;
1697 return ErrorCode::OK;
1698 }
1699
1700 ErrorCode HandleSWJSequence(bool /*in_isr*/, const uint8_t* req, uint16_t req_len,
1701 uint8_t* resp, uint16_t resp_cap, uint16_t& out_len)
1702 {
1703 if (!resp || resp_cap < 2u)
1704 {
1705 out_len = 0u;
1706 return ErrorCode::NOT_FOUND;
1707 }
1708
1709 resp[0] = ToU8(LibXR::USB::DapLinkV2Def::CommandId::SWJ_SEQUENCE);
1710 resp[1] = ToU8(LibXR::USB::DapLinkV2Def::Status::OK);
1711 out_len = 2u;
1712
1713 // Req: [0]=0x12 [1]=bit_count(0=>256) [2..]=data (LSB-first)
1714 if (!req || req_len < 2u)
1715 {
1716 resp[1] = ToU8(LibXR::USB::DapLinkV2Def::Status::ERROR);
1717 return ErrorCode::ARG_ERR;
1718 }
1719
1720 const uint8_t RAW_COUNT = req[1];
1721 const uint32_t BIT_COUNT =
1722 (RAW_COUNT == 0u) ? 256u : static_cast<uint32_t>(RAW_COUNT);
1723 const uint32_t BYTE_COUNT = (BIT_COUNT + 7u) / 8u;
1724
1725 if (2u + BYTE_COUNT > req_len)
1726 {
1727 resp[1] = ToU8(LibXR::USB::DapLinkV2Def::Status::ERROR);
1728 return ErrorCode::ARG_ERR;
1729 }
1730
1731 const uint8_t* data = &req[2];
1732
1733 // Delegate to SwdPort implementation (no RawMode / no pin-level control here)
1734 const ErrorCode EC = swd_.SeqWriteBits(BIT_COUNT, data);
1735 if (EC != ErrorCode::OK)
1736 {
1737 resp[1] = ToU8(LibXR::USB::DapLinkV2Def::Status::ERROR);
1738 // Keep transport-level OK so host still gets a valid response.
1739 return ErrorCode::OK;
1740 }
1741
1742 // Maintain shadow semantics: keep SWCLK=0, SWDIO=last bit
1743 swj_shadow_ = static_cast<uint8_t>(
1744 swj_shadow_ & static_cast<uint8_t>(~LibXR::USB::DapLinkV2Def::DAP_SWJ_SWCLK_TCK));
1745
1746 bool last_swdio = false;
1747 if (BIT_COUNT != 0u)
1748 {
1749 const uint32_t LAST_I = BIT_COUNT - 1u;
1750 last_swdio = (((data[LAST_I / 8u] >> (LAST_I & 7u)) & 0x01u) != 0u);
1751 }
1752
1753 if (last_swdio)
1754 {
1755 swj_shadow_ |= LibXR::USB::DapLinkV2Def::DAP_SWJ_SWDIO_TMS;
1756 }
1757 else
1758 {
1759 swj_shadow_ = static_cast<uint8_t>(
1760 swj_shadow_ &
1761 static_cast<uint8_t>(~LibXR::USB::DapLinkV2Def::DAP_SWJ_SWDIO_TMS));
1762 }
1763
1764 return ErrorCode::OK;
1765 }
1766
1767 ErrorCode HandleSWDConfigure(bool /*in_isr*/, const uint8_t* req, uint16_t req_len,
1768 uint8_t* resp, uint16_t resp_cap, uint16_t& out_len)
1769 {
1770 if (resp_cap < 2u)
1771 {
1772 out_len = 0;
1773 return ErrorCode::NOT_FOUND;
1774 }
1775
1776 resp[0] = ToU8(LibXR::USB::DapLinkV2Def::CommandId::SWD_CONFIGURE);
1777
1778 if (req == nullptr || req_len < 2u)
1779 {
1780 resp[1] = ToU8(LibXR::USB::DapLinkV2Def::Status::ERROR);
1781 out_len = 2u;
1782 return ErrorCode::ARG_ERR;
1783 }
1784
1785 const uint8_t cfg = req[1];
1786 dap_state_.swd_cfg.turnaround = static_cast<uint8_t>((cfg & 0x03u) + 1u);
1787 dap_state_.swd_cfg.data_phase = ((cfg & 0x04u) != 0u);
1788
1789 resp[1] = ToU8(LibXR::USB::DapLinkV2Def::Status::OK);
1790 out_len = 2u;
1791 return ErrorCode::OK;
1792 }
1793
1794 ErrorCode HandleSWDSequence(bool /*in_isr*/, const uint8_t* req, uint16_t req_len,
1795 uint8_t* resp, uint16_t resp_cap, uint16_t& out_len)
1796 {
1797 if (!req || !resp || resp_cap < 2u)
1798 {
1799 out_len = 0u;
1800 return ErrorCode::ARG_ERR;
1801 }
1802
1803 resp[0] = ToU8(LibXR::USB::DapLinkV2Def::CommandId::SWD_SEQUENCE);
1804 resp[1] = DAP_OK;
1805 out_len = 2u;
1806
1807 // Req: [0]=0x1D [1]=SequenceCount [ ... sequences ... ]
1808 // Each sequence:
1809 // INFO: [7]=Direction (1=input,0=output), [5:0]=cycles (0=>64)
1810 // If output: followed by ceil(cycles/8) bytes data (LSB-first)
1811 // If input : no data in request; response appends ceil(cycles/8) bytes data
1812 // (LSB-first)
1813 if (req_len < 2u)
1814 {
1815 resp[1] = DAP_ERROR;
1816 out_len = 2u;
1817 return ErrorCode::ARG_ERR;
1818 }
1819
1820 const uint8_t SEQ_CNT = req[1];
1821 uint16_t req_off = 2u;
1822 uint16_t resp_off = 2u;
1823
1824 for (uint32_t s = 0; s < SEQ_CNT; ++s)
1825 {
1826 if (req_off >= req_len)
1827 {
1828 resp[1] = DAP_ERROR;
1829 out_len = 2u;
1830 return ErrorCode::ARG_ERR;
1831 }
1832
1833 const uint8_t INFO = req[req_off++];
1834
1835 uint32_t cycles = static_cast<uint32_t>(INFO & 0x3Fu);
1836 if (cycles == 0u)
1837 {
1838 cycles = 64u;
1839 }
1840
1841 const bool MODE_IN = ((INFO & 0x80u) != 0u);
1842 const uint16_t BYTES = static_cast<uint16_t>((cycles + 7u) / 8u);
1843
1844 if (!MODE_IN)
1845 {
1846 // Output: data bytes are in request
1847 if (req_off + BYTES > req_len)
1848 {
1849 resp[1] = DAP_ERROR;
1850 out_len = 2u;
1851 return ErrorCode::ARG_ERR;
1852 }
1853
1854 const uint8_t* data = &req[req_off];
1855 req_off = static_cast<uint16_t>(req_off + BYTES);
1856
1857 const ErrorCode EC = swd_.SeqWriteBits(cycles, data);
1858 if (EC != ErrorCode::OK)
1859 {
1860 resp[1] = DAP_ERROR;
1861 out_len = 2u;
1862 // Return OK so host gets a valid response packet
1863 return ErrorCode::OK;
1864 }
1865 }
1866 else
1867 {
1868 // Input: captured data is appended to response
1869 if (resp_off + BYTES > resp_cap)
1870 {
1871 resp[1] = DAP_ERROR;
1872 out_len = 2u;
1873 return ErrorCode::NOT_FOUND;
1874 }
1875
1876 Memory::FastSet(&resp[resp_off], 0, BYTES);
1877
1878 const ErrorCode EC = swd_.SeqReadBits(cycles, &resp[resp_off]);
1879 if (EC != ErrorCode::OK)
1880 {
1881 resp[1] = DAP_ERROR;
1882 out_len = 2u;
1883 return ErrorCode::OK;
1884 }
1885
1886 resp_off = static_cast<uint16_t>(resp_off + BYTES);
1887 }
1888 }
1889
1890 out_len = resp_off;
1891 return ErrorCode::OK;
1892 }
1893
1897 ErrorCode HandleQueueCommands(bool /*in_isr*/, const uint8_t* req, uint16_t req_len,
1898 uint8_t* resp, uint16_t resp_cap, uint16_t& out_len)
1899 {
1900 if (!req || req_len < 2u)
1901 {
1902 return BuildCmdStatusResponse(
1903 ToU8(LibXR::USB::DapLinkV2Def::CommandId::QUEUE_COMMANDS), DAP_ERROR, resp,
1904 resp_cap, out_len);
1905 }
1906
1907 const uint8_t NUM = req[1];
1908 if (NUM == 0u)
1909 {
1910 return BuildCmdStatusResponse(
1911 ToU8(LibXR::USB::DapLinkV2Def::CommandId::QUEUE_COMMANDS), DAP_OK, resp,
1912 resp_cap, out_len);
1913 }
1914
1915 uint16_t req_off = 2u;
1916 for (uint32_t i = 0u; i < NUM; ++i)
1917 {
1918 if (req_off >= req_len)
1919 {
1920 return BuildCmdStatusResponse(
1921 ToU8(LibXR::USB::DapLinkV2Def::CommandId::QUEUE_COMMANDS), DAP_ERROR, resp,
1922 resp_cap, out_len);
1923 }
1924
1925 uint16_t cmd_len = 0u;
1926 if (!ParseQueuedCommandLength(&req[req_off],
1927 static_cast<uint16_t>(req_len - req_off), cmd_len) ||
1928 cmd_len == 0u)
1929 {
1930 return BuildCmdStatusResponse(
1931 ToU8(LibXR::USB::DapLinkV2Def::CommandId::QUEUE_COMMANDS), DAP_ERROR, resp,
1932 resp_cap, out_len);
1933 }
1934 req_off = static_cast<uint16_t>(req_off + cmd_len);
1935 }
1936
1937 if (req_off != req_len)
1938 {
1939 return BuildCmdStatusResponse(
1940 ToU8(LibXR::USB::DapLinkV2Def::CommandId::QUEUE_COMMANDS), DAP_ERROR, resp,
1941 resp_cap, out_len);
1942 }
1943
1944 if (static_cast<uint32_t>(queued_request_length_) +
1945 static_cast<uint32_t>(req_len - 2u) >
1946 static_cast<uint32_t>(QUEUED_REQ_BUFFER_SIZE) ||
1947 static_cast<uint32_t>(queued_command_count_) + static_cast<uint32_t>(NUM) >
1948 static_cast<uint32_t>(QUEUED_CMD_COUNT_MAX))
1949 {
1950 return BuildCmdStatusResponse(
1951 ToU8(LibXR::USB::DapLinkV2Def::CommandId::QUEUE_COMMANDS), DAP_ERROR, resp,
1952 resp_cap, out_len);
1953 }
1954
1955 Memory::FastCopy(&queued_request_buffer_[queued_request_length_], &req[2],
1956 req_len - 2u);
1957 queued_request_length_ =
1958 static_cast<uint16_t>(queued_request_length_ + (req_len - 2u));
1959 queued_command_count_ = static_cast<uint16_t>(queued_command_count_ + NUM);
1960
1961 return BuildCmdStatusResponse(
1962 ToU8(LibXR::USB::DapLinkV2Def::CommandId::QUEUE_COMMANDS), DAP_OK, resp, resp_cap,
1963 out_len);
1964 }
1965
1969 ErrorCode HandleExecuteCommands(bool in_isr, const uint8_t* /*req*/,
1970 uint16_t /*req_len*/, uint8_t* resp, uint16_t resp_cap,
1971 uint16_t& out_len)
1972 {
1973 const bool ok = TryExecuteQueuedCommandStream(in_isr, resp, resp_cap, out_len);
1974 ResetQueuedCommandState();
1975
1976 if (!ok)
1977 {
1978 return BuildCmdStatusResponse(
1979 ToU8(LibXR::USB::DapLinkV2Def::CommandId::EXECUTE_COMMANDS), DAP_ERROR, resp,
1980 resp_cap, out_len);
1981 }
1982
1983 return ErrorCode::OK;
1984 }
1985
1986 private:
1987 // ============================================================================
1988 // Transfer helpers
1989 // ============================================================================
1990
1991 uint8_t MapAckToDapResp(LibXR::Debug::SwdProtocol::Ack ack) const
1992 {
1993 static constexpr uint8_t ACK_MAP[8] = {7u, 1u, 2u, 7u, 4u, 7u, 7u, 7u};
1994 return ACK_MAP[static_cast<uint8_t>(ack) & 0x07u];
1995 }
1996
1997 static inline uint16_t LoadU16Le(const uint8_t* p)
1998 {
1999 return static_cast<uint16_t>(
2000 static_cast<uint16_t>(p[0]) |
2001 static_cast<uint16_t>(static_cast<uint16_t>(p[1]) << 8u));
2002 }
2003
2004 static inline void StoreU16Le(uint8_t* p, uint16_t v)
2005 {
2006 p[0] = static_cast<uint8_t>(v & 0xFFu);
2007 p[1] = static_cast<uint8_t>((v >> 8u) & 0xFFu);
2008 }
2009
2010 static inline uint32_t LoadU32Le(const uint8_t* p)
2011 {
2012 return static_cast<uint32_t>(
2013 static_cast<uint32_t>(p[0]) | (static_cast<uint32_t>(p[1]) << 8u) |
2014 (static_cast<uint32_t>(p[2]) << 16u) | (static_cast<uint32_t>(p[3]) << 24u));
2015 }
2016
2017 static inline void StoreU32Le(uint8_t* p, uint32_t v)
2018 {
2019 p[0] = static_cast<uint8_t>(v & 0xFFu);
2020 p[1] = static_cast<uint8_t>((v >> 8u) & 0xFFu);
2021 p[2] = static_cast<uint8_t>((v >> 16u) & 0xFFu);
2022 p[3] = static_cast<uint8_t>((v >> 24u) & 0xFFu);
2023 }
2024
2025 ErrorCode TransferTxnFast(const LibXR::Debug::SwdProtocol::Request& req,
2027 {
2028 const ErrorCode EC0 = swd_.Transfer(req, resp);
2029 if (EC0 != ErrorCode::OK)
2030 {
2031 return EC0;
2032 }
2033
2034 if (resp.ack == LibXR::Debug::SwdProtocol::Ack::WAIT)
2035 {
2036 return swd_.TransferWithRetry(req, resp);
2037 }
2038
2039 if (resp.ack == LibXR::Debug::SwdProtocol::Ack::FAULT)
2040 {
2041 const auto POL = swd_.GetTransferPolicy();
2042 if (POL.clear_sticky_on_fault)
2043 {
2044 LibXR::Debug::SwdProtocol::Ack abort_ack =
2045 LibXR::Debug::SwdProtocol::Ack::PROTOCOL;
2046 (void)swd_.WriteAbort(LibXR::Debug::SwdProtocol::DP_ABORT_STKCMPCLR |
2047 LibXR::Debug::SwdProtocol::DP_ABORT_STKERRCLR |
2048 LibXR::Debug::SwdProtocol::DP_ABORT_WDERRCLR |
2049 LibXR::Debug::SwdProtocol::DP_ABORT_ORUNERRCLR,
2050 abort_ack);
2051 }
2052 }
2053
2054 return ErrorCode::OK;
2055 }
2056
2057 ErrorCode DpReadRdbuffFast(uint32_t& val, LibXR::Debug::SwdProtocol::Ack& ack_out)
2058 {
2060 const auto req = LibXR::Debug::SwdProtocol::make_dp_read_req(
2061 LibXR::Debug::SwdProtocol::DpReadReg::RDBUFF);
2062 const ErrorCode ec = TransferTxnFast(req, swd_resp);
2063 ack_out = swd_resp.ack;
2064 if (ec != ErrorCode::OK)
2065 {
2066 return ec;
2067 }
2068 if (swd_resp.ack != LibXR::Debug::SwdProtocol::Ack::OK || !swd_resp.parity_ok)
2069 {
2070 return ErrorCode::FAILED;
2071 }
2072 val = swd_resp.rdata;
2073 return ErrorCode::OK;
2074 }
2075
2076 ErrorCode ApReadPostedFast(uint8_t addr2b, uint32_t& posted,
2077 LibXR::Debug::SwdProtocol::Ack& ack_out)
2078 {
2080 const auto req = LibXR::Debug::SwdProtocol::make_ap_read_req(addr2b);
2081 const ErrorCode ec = TransferTxnFast(req, swd_resp);
2082 ack_out = swd_resp.ack;
2083 if (ec != ErrorCode::OK)
2084 {
2085 return ec;
2086 }
2087 if (swd_resp.ack != LibXR::Debug::SwdProtocol::Ack::OK || !swd_resp.parity_ok)
2088 {
2089 return ErrorCode::FAILED;
2090 }
2091 posted = swd_resp.rdata;
2092 return ErrorCode::OK;
2093 }
2094
2095 void SetTransferAbortFlag(bool on) { dap_state_.transfer_abort = on; }
2096
2097 private:
2098 // ============================================================================
2099 // DAP_Transfer / DAP_TransferBlock
2100 // ============================================================================
2101
2102 // 说明:以下长函数保持原样;本 cpp 文件不补充函数级注释,hpp 中再统一给出接口说明
2103 // Note: The following long functions are kept as-is; no function-level docs in this
2104 // cpp. HPP will carry API docs.
2105
2106 ErrorCode HandleTransfer(bool /*in_isr*/, const uint8_t* req, uint16_t req_len,
2107 uint8_t* resp, uint16_t resp_cap, uint16_t& out_len)
2108 {
2109 out_len = 0u;
2110 if (!req || !resp || resp_cap < 3u)
2111 {
2112 return ErrorCode::ARG_ERR;
2113 }
2114
2115 resp[0] = ToU8(LibXR::USB::DapLinkV2Def::CommandId::TRANSFER);
2116 resp[1] = 0u; // response_count = #successful transfers
2117 resp[2] = 0u; // response_value (ACK bits / ERROR / MISMATCH)
2118 uint16_t resp_off = 3u;
2119
2120 // Req: [0]=CMD [1]=DAP index [2]=count [3..]=transfers...
2121 if (req_len < 3u)
2122 {
2123 resp[2] = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
2124 out_len = 3u;
2125 return ErrorCode::ARG_ERR;
2126 }
2127
2129 {
2130 dap_state_.transfer_abort = false;
2131 resp[2] = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
2132 out_len = 3u;
2133 return ErrorCode::OK;
2134 }
2135
2136 const uint8_t COUNT = req[2];
2137 uint16_t req_off = 3u;
2138
2139 auto push_u32 = [&](uint32_t v) -> bool
2140 {
2141 if (resp_off + 4u > resp_cap)
2142 {
2143 return false;
2144 }
2145 Memory::FastCopy(&resp[resp_off], &v, sizeof(v));
2146 resp_off = static_cast<uint16_t>(resp_off + 4u);
2147 return true;
2148 };
2149
2150 auto push_timestamp = [&]() -> bool
2151 {
2152 const uint32_t T = static_cast<uint32_t>(LibXR::Timebase::GetMicroseconds());
2153 return push_u32(T);
2154 };
2155
2156 auto ensure_space = [&](uint16_t bytes) -> bool
2157 { return (resp_off + bytes) <= resp_cap; };
2158
2159 auto bytes_for_read = [&](bool need_ts) -> uint16_t
2160 { return static_cast<uint16_t>(need_ts ? 8u : 4u); };
2161
2162 uint8_t response_count = 0u;
2163 // Keep reference behavior: if no transfer executes, response_value remains 0.
2164 uint8_t response_value = 0u;
2165
2166 // Whether a final DP_RDBUFF flush is required for write-fault cleanup.
2167 bool check_write = false;
2168
2169 // -------- posted-read pipeline state (AP read only) --------
2170 struct PendingApRead
2171 {
2172 bool valid = false;
2173 bool need_ts = false; // Whether this AP read transfer needs timestamp.
2174 } pending;
2175
2176 auto emit_read_with_ts = [&](bool need_ts, uint32_t data) -> bool
2177 {
2178 if (need_ts)
2179 {
2180 if (!push_timestamp())
2181 {
2182 return false;
2183 }
2184 }
2185 if (!push_u32(data))
2186 {
2187 return false;
2188 }
2189 response_count++;
2190 return true;
2191 };
2192
2193 // Complete a pending AP read by DP_RDBUFF
2194 // (used on sequence tail, AP-read interruption, or abnormal tail handling).
2195 auto complete_pending_by_rdbuff = [&]() -> bool
2196 {
2197 if (!pending.valid)
2198 {
2199 return true;
2200 }
2201
2202 if (!ensure_space(bytes_for_read(pending.need_ts)))
2203 {
2204 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
2205 return false;
2206 }
2207
2208 uint32_t rdata = 0u;
2209 LibXR::Debug::SwdProtocol::Ack ack = LibXR::Debug::SwdProtocol::Ack::PROTOCOL;
2210 const ErrorCode EC = DpReadRdbuffFast(rdata, ack);
2211
2212 const uint8_t V = MapAckToDapResp(ack);
2213 if (V != LibXR::USB::DapLinkV2Def::DAP_TRANSFER_OK)
2214 {
2215 response_value = V;
2216 return false;
2217 }
2218 if (EC != ErrorCode::OK)
2219 {
2220 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
2221 return false;
2222 }
2223
2224 if (!emit_read_with_ts(pending.need_ts, rdata))
2225 {
2226 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
2227 return false;
2228 }
2229
2230 pending.valid = false;
2231 pending.need_ts = false;
2232
2233 // RDBUFF has been read; equivalent to one posted/fault flush.
2234 check_write = false;
2235
2236 // 成功路径保持 OK
2237 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_OK;
2238 return true;
2239 };
2240
2241 // Flush pending AP read before handling non-AP normal read
2242 // to keep response ordering stable.
2243 auto flush_pending_if_any = [&]() -> bool
2244 { return pending.valid ? complete_pending_by_rdbuff() : true; };
2245
2246 // -------- main loop --------
2247 for (uint32_t i = 0; i < COUNT; ++i)
2248 {
2249 if (req_off >= req_len)
2250 {
2251 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
2252 break;
2253 }
2254
2255 const uint8_t RQ = req[req_off++];
2256
2257 const bool AP = LibXR::USB::DapLinkV2Def::req_is_ap(RQ);
2258 const bool RNW = LibXR::USB::DapLinkV2Def::req_is_read(RQ);
2259 const uint8_t ADDR2B = LibXR::USB::DapLinkV2Def::req_addr2b(RQ);
2260
2262 const bool MATCH_VALUE =
2263 ((RQ & LibXR::USB::DapLinkV2Def::DAP_TRANSFER_MATCH_VALUE) != 0u);
2264 const bool MATCH_MASK =
2265 ((RQ & LibXR::USB::DapLinkV2Def::DAP_TRANSFER_MATCH_MASK) != 0u);
2266
2267 // Spec rule: timestamp cannot be combined with match bits.
2268 if (TS && (MATCH_VALUE || MATCH_MASK))
2269 {
2270 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
2271 break;
2272 }
2273
2274 LibXR::Debug::SwdProtocol::Ack ack = LibXR::Debug::SwdProtocol::Ack::PROTOCOL;
2276
2277 if (!RNW)
2278 {
2279 // ---------------- WRITE ----------------
2280 // Config-like operations do not participate in AP posted pipeline;
2281 // flush pending first.
2282 if (!flush_pending_if_any())
2283 {
2284 break;
2285 }
2286
2287 if (req_off + 4u > req_len)
2288 {
2289 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
2290 break;
2291 }
2292
2293 uint32_t wdata = LoadU32Le(&req[req_off]);
2294 req_off = static_cast<uint16_t>(req_off + 4u);
2295
2296 if (MATCH_MASK)
2297 {
2298 match_mask_ = wdata;
2299 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_OK;
2300 response_count++; // MATCH_MASK 视为成功 transfer
2301 continue;
2302 }
2303 if (AP)
2304 {
2305 ec = swd_.ApWriteTxn(ADDR2B, wdata, ack);
2306 }
2307 else
2308 {
2309 ec = swd_.DpWriteTxn(static_cast<LibXR::Debug::SwdProtocol::DpWriteReg>(ADDR2B),
2310 wdata, ack);
2311 }
2312
2313 response_value = MapAckToDapResp(ack);
2314 if (response_value != LibXR::USB::DapLinkV2Def::DAP_TRANSFER_OK)
2315 {
2316 break;
2317 }
2318 if (ec != ErrorCode::OK)
2319 {
2320 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
2321 break;
2322 }
2323
2324 if (TS)
2325 {
2326 if (!push_timestamp())
2327 {
2328 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
2329 break;
2330 }
2331 }
2332
2333 response_count++;
2334 check_write = true;
2335 }
2336 else
2337 {
2338 // ---------------- READ ----------------
2339
2340 if (MATCH_VALUE)
2341 {
2342 // MATCH_VALUE does not return read data.
2343 // For simpler semantics, flush pending first, then keep using ApReadTxn
2344 // for AP reads.
2345 if (!flush_pending_if_any())
2346 {
2347 break;
2348 }
2349
2350 if (req_off + 4u > req_len)
2351 {
2352 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
2353 break;
2354 }
2355
2356 uint32_t match_val = LoadU32Le(&req[req_off]);
2357 req_off = static_cast<uint16_t>(req_off + 4u);
2358
2359 uint32_t rdata = 0u;
2360 uint32_t retry = dap_state_.transfer_cfg.match_retry;
2361 bool matched = false;
2362
2363 while (true)
2364 {
2365 if (AP)
2366 {
2367 ec = swd_.ApReadTxn(ADDR2B, rdata, ack); // 内含 RDBUFF
2368 if (ec == ErrorCode::OK && ack == LibXR::Debug::SwdProtocol::Ack::OK)
2369 {
2370 // ApReadTxn already reads RDBUFF; equivalent to a flush.
2371 check_write = false;
2372 }
2373 }
2374 else
2375 {
2376 ec = swd_.DpReadTxn(
2377 static_cast<LibXR::Debug::SwdProtocol::DpReadReg>(ADDR2B), rdata, ack);
2378 }
2379
2380 response_value = MapAckToDapResp(ack);
2381 if (response_value != LibXR::USB::DapLinkV2Def::DAP_TRANSFER_OK)
2382 {
2383 break;
2384 }
2385 if (ec != ErrorCode::OK)
2386 {
2387 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
2388 break;
2389 }
2390
2391 if ((rdata & match_mask_) == (match_val & match_mask_))
2392 {
2393 matched = true;
2394 break;
2395 }
2396
2397 if (retry == 0u)
2398 {
2399 break;
2400 }
2401 --retry;
2402 }
2403
2404 if (response_value != LibXR::USB::DapLinkV2Def::DAP_TRANSFER_OK)
2405 {
2406 break;
2407 }
2408
2409 if (!matched)
2410 {
2411 response_value =
2412 static_cast<uint8_t>(LibXR::USB::DapLinkV2Def::DAP_TRANSFER_OK |
2413 LibXR::USB::DapLinkV2Def::DAP_TRANSFER_MISMATCH);
2414 // MISMATCH does not increase response_count.
2415 break;
2416 }
2417
2418 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_OK;
2419 response_count++;
2420 continue;
2421 }
2422
2423 // ---- Normal read ----
2424 if (!AP)
2425 {
2426 // DP read:不参与 pipeline;先 flush pending
2427 if (!flush_pending_if_any())
2428 {
2429 break;
2430 }
2431
2432 uint32_t rdata = 0u;
2433 ec = swd_.DpReadTxn(static_cast<LibXR::Debug::SwdProtocol::DpReadReg>(ADDR2B),
2434 rdata, ack);
2435
2436 response_value = MapAckToDapResp(ack);
2437 if (response_value != LibXR::USB::DapLinkV2Def::DAP_TRANSFER_OK)
2438 {
2439 break;
2440 }
2441 if (ec != ErrorCode::OK)
2442 {
2443 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
2444 break;
2445 }
2446
2447 if (!ensure_space(bytes_for_read(TS)))
2448 {
2449 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
2450 break;
2451 }
2452
2453 if (!emit_read_with_ts(TS, rdata))
2454 {
2455 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
2456 break;
2457 }
2458
2459 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_OK;
2460 continue;
2461 }
2462
2463 // AP normal read:posted-read pipeline
2464 if (!pending.valid)
2465 {
2466 // First AP read in this contiguous AP-read segment:
2467 // start one posted AP read and discard returned posted data.
2468 uint32_t dummy_posted = 0u;
2469 ec = ApReadPostedFast(ADDR2B, dummy_posted, ack);
2470
2471 response_value = MapAckToDapResp(ack);
2472 if (response_value != LibXR::USB::DapLinkV2Def::DAP_TRANSFER_OK)
2473 {
2474 break;
2475 }
2476 if (ec != ErrorCode::OK)
2477 {
2478 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
2479 {
2480 break;
2481 }
2482 }
2483
2484 pending.valid = true;
2485 pending.need_ts = TS;
2486
2487 // Transfer is not "complete" yet.
2488 // Data will be produced by next AP read or tail RDBUFF.
2489 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_OK;
2490 }
2491 else
2492 {
2493 // Pending exists: current AP read returns posted data
2494 // from the previous AP read.
2495 if (!ensure_space(bytes_for_read(pending.need_ts)))
2496 {
2497 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
2498 break;
2499 }
2500
2501 uint32_t posted_prev = 0u;
2502 ec = ApReadPostedFast(ADDR2B, posted_prev, ack);
2503
2504 const uint8_t CUR_V = MapAckToDapResp(ack);
2505 if (CUR_V != LibXR::USB::DapLinkV2Def::DAP_TRANSFER_OK || ec != ErrorCode::OK)
2506 {
2507 // Current AP read failed: try best effort to complete pending by RDBUFF.
2508 // Otherwise, response_count may miss one and pipeline may remain dirty.
2509 const uint8_t PROOR_FAIL =
2510 (CUR_V != LibXR::USB::DapLinkV2Def::DAP_TRANSFER_OK)
2511 ? CUR_V
2512 : LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
2513
2514 if (!complete_pending_by_rdbuff())
2515 {
2516 // Pending itself failed: return earlier failure
2517 // (complete_pending_by_rdbuff already wrote response_value).
2518 break;
2519 }
2520
2521 // Pending completion succeeded: keep current failure.
2522 response_value = PROOR_FAIL;
2523 break;
2524 }
2525
2526 // Current AP read succeeded: emit pending first (using posted_prev),
2527 // then mark current read as new pending.
2528 if (!emit_read_with_ts(pending.need_ts, posted_prev))
2529 {
2530 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
2531 break;
2532 }
2533
2534 pending.valid = true;
2535 pending.need_ts = TS;
2536
2537 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_OK;
2538 }
2539 }
2540
2542 {
2543 dap_state_.transfer_abort = false;
2544 break;
2545 }
2546 }
2547
2548 // If pending AP read still exists at tail:
2549 // - when response_value == OK: normal tail by one RDBUFF;
2550 // - when response_value != OK: try pending completion first; if completion
2551 // succeeds, keep original failure; otherwise use pending failure.
2552 if (pending.valid)
2553 {
2554 const uint8_t PRIOR_FAIL = response_value;
2555
2556 if (!complete_pending_by_rdbuff())
2557 {
2558 // Pending failure wins here (response_value already written).
2559 }
2560 else
2561 {
2562 // Pending completion succeeded: keep original failure
2563 // (if original was OK, keep OK).
2564 if (PRIOR_FAIL != 0u && PRIOR_FAIL != LibXR::USB::DapLinkV2Def::DAP_TRANSFER_OK)
2565 {
2566 response_value = PRIOR_FAIL;
2567 }
2568 }
2569 }
2570
2571 // Tail write flush: if all OK and there was a real write, and no RDBUFF
2572 // flush happened in between, perform one DP_RDBUFF read (discard).
2573 if (response_value == LibXR::USB::DapLinkV2Def::DAP_TRANSFER_OK && check_write)
2574 {
2575 uint32_t dummy = 0u;
2576 LibXR::Debug::SwdProtocol::Ack ack = LibXR::Debug::SwdProtocol::Ack::PROTOCOL;
2577 const ErrorCode EC = DpReadRdbuffFast(dummy, ack);
2578 const uint8_t V = MapAckToDapResp(ack);
2579
2580 if (V != LibXR::USB::DapLinkV2Def::DAP_TRANSFER_OK)
2581 {
2582 response_value = V;
2583 }
2584 else if (EC != ErrorCode::OK)
2585 {
2586 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
2587 }
2588 }
2589
2590 resp[1] = response_count;
2591 resp[2] = response_value;
2592 out_len = resp_off;
2593 return ErrorCode::OK;
2594 }
2595 ErrorCode HandleTransferBlock(bool /*in_isr*/, const uint8_t* req, uint16_t req_len,
2596 uint8_t* resp, uint16_t resp_cap, uint16_t& out_len)
2597 {
2598 // Req: [0]=0x06 [1]=index [2..3]=count [4]=request [5..]=data(write)
2599 // Resp: [0]=0x06 [1..2]=done [3]=resp [4..]=data(read)
2600 if (!resp || resp_cap < 4u)
2601 {
2602 out_len = 0u;
2603 return ErrorCode::NOT_FOUND;
2604 }
2605
2606 resp[0] = ToU8(LibXR::USB::DapLinkV2Def::CommandId::TRANSFER_BLOCK);
2607 resp[1] = 0u;
2608 resp[2] = 0u;
2609 resp[3] = 0u;
2610 out_len = 4u;
2611
2612 if (!req || req_len < 5u)
2613 {
2614 resp[3] = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
2615 return ErrorCode::ARG_ERR;
2616 }
2617
2619 {
2620 dap_state_.transfer_abort = false;
2621 resp[3] = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
2622 return ErrorCode::OK;
2623 }
2624
2625 uint16_t count = 0u;
2626 count = LoadU16Le(&req[2]);
2627
2628 const uint8_t DAP_RQ = req[4];
2629
2630 // TransferBlock does not support match or timestamp
2631 if ((DAP_RQ & (LibXR::USB::DapLinkV2Def::DAP_TRANSFER_MATCH_VALUE |
2632 LibXR::USB::DapLinkV2Def::DAP_TRANSFER_MATCH_MASK)) != 0u)
2633 {
2634 resp[3] = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
2636 }
2638 {
2639 resp[3] = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
2641 }
2642
2643 // Count==0: return OK
2644 if (count == 0u)
2645 {
2646 const uint16_t DONE0 = 0u;
2647 StoreU16Le(&resp[1], DONE0);
2648 resp[3] = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_OK;
2649 out_len = 4u;
2650 return ErrorCode::OK;
2651 }
2652
2653 const bool AP = LibXR::USB::DapLinkV2Def::req_is_ap(DAP_RQ);
2654 const bool RNW = LibXR::USB::DapLinkV2Def::req_is_read(DAP_RQ);
2655 const uint8_t ADDR2B = LibXR::USB::DapLinkV2Def::req_addr2b(DAP_RQ);
2656
2657 uint16_t done = 0u;
2658 uint8_t xresp = 0u;
2659
2660 uint16_t req_off = 5u;
2661 uint16_t resp_off = 4u;
2662
2663 // WRITE path: keep original behavior
2664 if (!RNW)
2665 {
2666 const uint32_t REQ_NEED =
2667 static_cast<uint32_t>(req_off) + (static_cast<uint32_t>(count) * 4u);
2668 if (REQ_NEED > req_len)
2669 {
2670 xresp |= LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
2671 StoreU16Le(&resp[1], done);
2672 resp[3] = xresp;
2673 out_len = resp_off;
2674 return ErrorCode::OK;
2675 }
2676 if (AP)
2677 {
2678 auto swd_req = LibXR::Debug::SwdProtocol::make_ap_write_req(ADDR2B, 0u);
2680 for (uint32_t i = 0; i < count; ++i)
2681 {
2682 uint32_t wdata = LoadU32Le(&req[req_off]);
2683 req_off = static_cast<uint16_t>(req_off + 4u);
2684 swd_req.wdata = wdata;
2685 const ErrorCode ec = TransferTxnFast(swd_req, swd_resp);
2686 xresp = MapAckToDapResp(swd_resp.ack);
2687 if (swd_resp.ack != LibXR::Debug::SwdProtocol::Ack::OK)
2688 {
2689 break;
2690 }
2691 if (ec != ErrorCode::OK)
2692 {
2693 xresp |= LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
2694 break;
2695 }
2696 done = static_cast<uint16_t>(i + 1u);
2697 }
2698 }
2699 else
2700 {
2701 for (uint32_t i = 0; i < count; ++i)
2702 {
2703 LibXR::Debug::SwdProtocol::Ack ack = LibXR::Debug::SwdProtocol::Ack::PROTOCOL;
2705 uint32_t wdata = LoadU32Le(&req[req_off]);
2706 req_off = static_cast<uint16_t>(req_off + 4u);
2707 ec = swd_.DpWriteTxn(static_cast<LibXR::Debug::SwdProtocol::DpWriteReg>(ADDR2B),
2708 wdata, ack);
2709 xresp = MapAckToDapResp(ack);
2710 if (ack != LibXR::Debug::SwdProtocol::Ack::OK)
2711 {
2712 break;
2713 }
2714 if (ec != ErrorCode::OK)
2715 {
2716 xresp |= LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
2717 break;
2718 }
2719 done = static_cast<uint16_t>(i + 1u);
2720 }
2721 }
2722 StoreU16Le(&resp[1], done);
2723 resp[3] = xresp;
2724 out_len = resp_off;
2725 return ErrorCode::OK;
2726 }
2727
2728 // READ path
2729 if (!AP)
2730 {
2731 const uint32_t RESP_NEED =
2732 static_cast<uint32_t>(resp_off) + (static_cast<uint32_t>(count) * 4u);
2733 if (RESP_NEED > resp_cap)
2734 {
2735 xresp |= LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
2736 StoreU16Le(&resp[1], done);
2737 resp[3] = xresp;
2738 out_len = resp_off;
2739 return ErrorCode::OK;
2740 }
2741
2742 // DP read: keep original behavior
2743 for (uint32_t i = 0; i < count; ++i)
2744 {
2745 LibXR::Debug::SwdProtocol::Ack ack = LibXR::Debug::SwdProtocol::Ack::PROTOCOL;
2747 uint32_t rdata = 0u;
2748 ec = swd_.DpReadTxn(static_cast<LibXR::Debug::SwdProtocol::DpReadReg>(ADDR2B),
2749 rdata, ack);
2750 xresp = MapAckToDapResp(ack);
2751 if (ack != LibXR::Debug::SwdProtocol::Ack::OK)
2752 {
2753 break;
2754 }
2755 if (ec != ErrorCode::OK)
2756 {
2757 xresp |= LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
2758 break;
2759 }
2760 StoreU32Le(&resp[resp_off], rdata);
2761 resp_off = static_cast<uint16_t>(resp_off + 4u);
2762 done = static_cast<uint16_t>(i + 1u);
2763 }
2764 StoreU16Le(&resp[1], done);
2765 resp[3] = xresp;
2766 out_len = resp_off;
2767 return ErrorCode::OK;
2768 }
2769
2770 // AP read: posted-read pipeline
2771 {
2772 const uint32_t RESP_NEED =
2773 static_cast<uint32_t>(resp_off) + (static_cast<uint32_t>(count) * 4u);
2774 if (RESP_NEED > resp_cap)
2775 {
2776 xresp |= LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
2777 StoreU16Le(&resp[1], done);
2778 resp[3] = xresp;
2779 out_len = resp_off;
2780 return ErrorCode::OK;
2781 }
2782
2783 auto ap_read_req = LibXR::Debug::SwdProtocol::make_ap_read_req(ADDR2B);
2784 const auto rdbuff_req = LibXR::Debug::SwdProtocol::make_dp_read_req(
2785 LibXR::Debug::SwdProtocol::DpReadReg::RDBUFF);
2786 LibXR::Debug::SwdProtocol::Response ap_read_resp = {};
2787 ErrorCode ec = TransferTxnFast(ap_read_req, ap_read_resp);
2788 xresp = MapAckToDapResp(ap_read_resp.ack);
2789 if (ap_read_resp.ack != LibXR::Debug::SwdProtocol::Ack::OK)
2790 {
2791 goto out_ap_read; // NOLINT
2792 }
2793 if (ec != ErrorCode::OK || !ap_read_resp.parity_ok)
2794 {
2795 xresp |= LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
2796 goto out_ap_read; // NOLINT
2797 }
2798
2799 // i=1..COUNT-1: each AP read returns previous posted data.
2800 for (uint32_t i = 1; i < count; ++i)
2801 {
2802 ec = TransferTxnFast(ap_read_req, ap_read_resp);
2803 const uint8_t CUR = MapAckToDapResp(ap_read_resp.ack);
2804
2805 if (ap_read_resp.ack != LibXR::Debug::SwdProtocol::Ack::OK ||
2806 ec != ErrorCode::OK || !ap_read_resp.parity_ok)
2807 {
2808 // Current AP read failed; try to flush previous pending data via RDBUFF.
2809 if (resp_off + 4u <= resp_cap)
2810 {
2811 LibXR::Debug::SwdProtocol::Response rdbuff_resp = {};
2812 const ErrorCode EC2 = TransferTxnFast(rdbuff_req, rdbuff_resp);
2813 const uint8_t V2 = MapAckToDapResp(rdbuff_resp.ack);
2814
2815 if (V2 == 1u && EC2 == ErrorCode::OK && rdbuff_resp.parity_ok)
2816 {
2817 StoreU32Le(&resp[resp_off], rdbuff_resp.rdata);
2818 resp_off = static_cast<uint16_t>(resp_off + 4u);
2819 done = static_cast<uint16_t>(i); // done includes transfer [0..i-1]
2820 }
2821 else
2822 {
2823 xresp = V2;
2824 if (EC2 != ErrorCode::OK)
2825 {
2826 xresp |= LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
2827 }
2828 goto out_ap_read; // NOLINT
2829 }
2830 }
2831
2832 xresp = CUR;
2833 if (ec != ErrorCode::OK)
2834 {
2835 xresp |= LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
2836 }
2837 goto out_ap_read; // NOLINT
2838 }
2839
2840 StoreU32Le(&resp[resp_off], ap_read_resp.rdata);
2841 resp_off = static_cast<uint16_t>(resp_off + 4u);
2842 done = static_cast<uint16_t>(i); // completed [0..i-1]
2843 xresp = CUR;
2844 }
2845
2846 // Tail flush: read final posted value from RDBUFF.
2847 {
2848 LibXR::Debug::SwdProtocol::Response rdbuff_resp = {};
2849 const ErrorCode EC2 = TransferTxnFast(rdbuff_req, rdbuff_resp);
2850 const uint8_t V2 = MapAckToDapResp(rdbuff_resp.ack);
2851
2852 xresp = V2;
2853 if (V2 != 1u)
2854 {
2855 goto out_ap_read; // NOLINT
2856 }
2857 if (EC2 != ErrorCode::OK || !rdbuff_resp.parity_ok)
2858 {
2859 xresp |= LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
2860 goto out_ap_read; // NOLINT
2861 }
2862
2863 StoreU32Le(&resp[resp_off], rdbuff_resp.rdata);
2864 resp_off = static_cast<uint16_t>(resp_off + 4u);
2865 done = count;
2866 }
2867
2868 out_ap_read:
2869 StoreU16Le(&resp[1], done);
2870 resp[3] = xresp;
2871 out_len = resp_off;
2872 return ErrorCode::OK;
2873 }
2874 }
2875
2876 private:
2877 // ============================================================================
2878 // Reset helpers
2879 // ============================================================================
2880
2881 void DriveReset(bool release)
2882 {
2883 last_nreset_level_high_ = release;
2884
2885 // Update shadow regardless of whether GPIO exists
2886 if (release)
2887 {
2888 swj_shadow_ |= LibXR::USB::DapLinkV2Def::DAP_SWJ_NRESET;
2889 }
2890 else
2891 {
2892 swj_shadow_ = static_cast<uint8_t>(
2893 swj_shadow_ & static_cast<uint8_t>(~LibXR::USB::DapLinkV2Def::DAP_SWJ_NRESET));
2894 }
2895
2896 if (nreset_gpio_ != nullptr)
2897 {
2898 (void)nreset_gpio_->Write(release);
2899 }
2900 }
2901
2902 void DelayUsIfAllowed(bool /*in_isr*/, uint32_t us)
2903 {
2905 }
2906
2907 private:
2908 static constexpr uint16_t DEFAULT_DAP_PACKET_SIZE = DefaultDapPacketSize;
2909 static constexpr uint8_t PACKET_COUNT_ADVERTISED = AdvertisedPacketCount;
2910 static constexpr uint8_t PACKET_COUNT_EFFECTIVE =
2911 (PACKET_COUNT_ADVERTISED > 4u) ? 4u : PACKET_COUNT_ADVERTISED;
2912 static constexpr uint8_t MAX_OUTSTANDING_RESPONSES = PACKET_COUNT_EFFECTIVE;
2913 // OpenOCD 0.12 computes pending_queue_len = (packet_size - 4) / 5 for CMD_DAP_TFER.
2914 // CMD_DAP_TFER transfer_count is u8, so cap host-visible packet size to avoid
2915 // transfer_count > 255 and "expected X, got Y" mismatch.
2916 static constexpr uint16_t OPENOCD_SAFE_DAP_PACKET_SIZE =
2917 static_cast<uint16_t>((255u * 5u) + 4u);
2918 // Host-visible CMSIS-DAP packet size; endpoint MPS limits are handled by
2919 // TransferMultiBulk segmentation/reassembly.
2920 static constexpr uint16_t MAX_DAP_PACKET_SIZE = MaxDapPacketSize;
2921 static constexpr uint16_t QUEUED_REQ_BUFFER_SIZE = QueuedRequestBufferSize;
2922 static constexpr uint16_t QUEUED_CMD_COUNT_MAX = QueuedCommandCountMax;
2923 static constexpr uint16_t RESP_SLOT_SIZE = MAX_DAP_PACKET_SIZE;
2924 static constexpr uint8_t RESP_QUEUE_DEPTH = PACKET_COUNT_EFFECTIVE;
2925 static constexpr uint16_t QUEUED_REQ_BUFFER_ALLOC_SIZE = QUEUED_REQ_BUFFER_SIZE;
2926 static_assert(PACKET_COUNT_ADVERTISED > 0u, "PACKET_COUNT_ADVERTISED must be > 0");
2927 static_assert(PACKET_COUNT_EFFECTIVE > 0u, "PACKET_COUNT_EFFECTIVE must be > 0");
2928 static_assert(MAX_DAP_PACKET_SIZE >= DEFAULT_DAP_PACKET_SIZE,
2929 "MAX_DAP_PACKET_SIZE must be >= DEFAULT_DAP_PACKET_SIZE");
2930 static_assert(MAX_DAP_PACKET_SIZE <= OPENOCD_SAFE_DAP_PACKET_SIZE,
2931 "MAX_DAP_PACKET_SIZE exceeds OpenOCD-safe limit");
2932 static_assert(((OPENOCD_SAFE_DAP_PACKET_SIZE - 4u) / 5u) <= 255u,
2933 "OPENOCD_SAFE_DAP_PACKET_SIZE too large for CMD_DAP_TFER u8 count");
2934 static_assert(QUEUED_REQ_BUFFER_SIZE > 0u, "QUEUED_REQ_BUFFER_SIZE must be > 0");
2935 static_assert(QUEUED_CMD_COUNT_MAX > 0u, "QUEUED_CMD_COUNT_MAX must be > 0");
2936 static_assert(RESP_SLOT_SIZE >= DEFAULT_DAP_PACKET_SIZE,
2937 "RESP_SLOT_SIZE must cover FS bulk packet size");
2938 static_assert((RESP_QUEUE_DEPTH & (RESP_QUEUE_DEPTH - 1u)) == 0u,
2939 "Response queue depth must be power-of-two");
2940
2941 static constexpr uint8_t WINUSB_VENDOR_CODE =
2942 0x20;
2943
2944 // REG_MULTI_SZ: "<GUID>\0\0" (UTF-16LE). GUID_STR_UTF16_BYTES should already include
2945 // the first UTF-16 NUL.
2946 static constexpr uint16_t GUID_MULTI_SZ_UTF_16_BYTES =
2947 static_cast<uint16_t>(LibXR::USB::WinUsbMsOs20::GUID_STR_UTF16_BYTES +
2948 2);
2949
2951 {
2952 uint16_t len = 0u;
2953 uint8_t payload[RESP_SLOT_SIZE] = {};
2954 };
2955
2956 ResponseSlot resp_q_[RESP_QUEUE_DEPTH] = {};
2957 uint8_t resp_q_head_ = 0u;
2958 uint8_t resp_q_tail_ = 0u;
2959 uint8_t resp_q_count_ = 0u;
2960 bool deferred_in_resp_valid_ = false;
2961 uint16_t deferred_in_resp_len_ = 0u;
2962
2963 uint8_t queued_request_buffer_[QUEUED_REQ_BUFFER_ALLOC_SIZE] = {};
2964 uint16_t queued_request_length_ = 0u;
2965 uint16_t queued_command_count_ = 0u;
2966
2967 uint8_t out_req_multi_storage_[MAX_DAP_PACKET_SIZE] = {};
2968 LibXR::RawData out_req_multi_buf_{out_req_multi_storage_, DEFAULT_DAP_PACKET_SIZE};
2969 uint8_t in_tx_multi_storage_[MAX_DAP_PACKET_SIZE] = {};
2970 LibXR::RawData in_tx_multi_buf_{in_tx_multi_storage_, DEFAULT_DAP_PACKET_SIZE};
2971
2972LIBXR_PACKED_BEGIN
3001LIBXR_PACKED_END
3002
3003 private:
3004 SwdPort& swd_;
3005
3007
3008 uint8_t swj_shadow_ = static_cast<uint8_t>(
3009 DapLinkV2Def::DAP_SWJ_SWDIO_TMS |
3010 DapLinkV2Def::DAP_SWJ_NRESET);
3011
3013
3015 InfoStrings info_{"XRobot", "DAPLinkV2", "00000001", "2.0.0", "XRUSB",
3016 "XRDAP", "XRobot", "DAP_DEMO", "0.1.0"};
3017
3018 uint32_t swj_clock_hz_ = 1000000u;
3019
3020 const char* interface_string_ = nullptr;
3021
3024
3027
3028 bool inited_ = false;
3029 uint8_t interface_num_ = 0;
3030
3031LIBXR_PACKED_BEGIN
3042LIBXR_PACKED_END
3043
3044 private:
3048
3049 uint32_t match_mask_ = 0xFFFFFFFFu;
3050
3053
3056};
3057
3058} // namespace LibXR::USB
通用回调包装,支持动态参数传递 / Generic callback wrapper supporting dynamic argument passing
Definition libxr_cb.hpp:144
static Callback Create(CallableType fun, BoundArgType arg)
创建回调对象并绑定回调函数与参数 / Create a callback instance with bound function and argument
Definition libxr_cb.hpp:167
只读原始数据视图 / Immutable raw data view
size_t size_
数据字节数 / Data size in bytes
const void * addr_
数据起始地址 / Data start address
通用输入输出(GPIO)接口类。General Purpose Input/Output (GPIO) interface class.
Definition gpio.hpp:13
virtual bool Read()=0
读取 GPIO 引脚状态。Reads the GPIO pin state.
virtual void Write(bool value)=0
写入 GPIO 引脚状态。Writes the GPIO pin state.
static void FastSet(void *dst, uint8_t value, size_t size)
快速内存填充 / Fast memory fill
static void FastCopy(void *dst, const void *src, size_t size)
快速内存拷贝 / Fast memory copy
Definition libxr_mem.cpp:5
可写原始数据视图 / Mutable raw data view
size_t size_
数据字节数 / Data size in bytes
void * addr_
数据起始地址 / Data start address
static MicrosecondTimestamp GetMicroseconds()
获取当前时间的微秒级时间戳。 Gets the current timestamp in microseconds.
Definition timebase.hpp:48
static void DelayMicroseconds(uint32_t us)
微秒级延时 / Delay in microseconds
Definition timebase.hpp:68
BOS 能力接口 / BOS capability interface.
Definition bos.hpp:57
void SetData(RawData data)
设置内部数据缓存 / Set internal data cache
Definition desc_cfg.hpp:193
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.
USB 端点基类 / USB Endpoint base class.
Definition ep.hpp:24
EPNumber
端点号 Endpoint number
Definition ep.hpp:42
@ EP_AUTO
自动分配端点号 / Auto allocate
uint8_t GetAddress() const
获取端点地址(方向 + 号) / Get endpoint address (dir + num)
Definition ep.hpp:195
@ IN
输入方向 / IN direction
@ OUT
输出方向 / OUT direction
virtual ErrorCode TransferMultiBulk(RawData &data)
Bulk 多包传输辅助接口 / Helper for multi-packet bulk transfer.
Definition ep.hpp:321
void SetActiveLength(uint16_t len)
设置当前活动缓冲区有效长度 / Set active buffer valid length
Definition ep.hpp:271
virtual size_t MaxTransferSize() const
返回当前最大可传输字节数 / Return maximum transferable size at this time
Definition ep.hpp:283
void SetOnTransferCompleteCallback(Callback< ConstRawData & > cb)
设置传输完成回调 / Set transfer complete callback
Definition ep.hpp:262
virtual void Configure(const Config &cfg)=0
配置端点协议参数 / Configure endpoint protocol parameters
@ BULK
批量端点 / Bulk
virtual void Close()=0
关闭端点 / Close endpoint
uint16_t MaxPacketSize() const
获取最大包长 / Get max packet size
Definition ep.hpp:226
State GetState() const
获取端点状态 / Get endpoint state
Definition ep.hpp:208
virtual ErrorCode Transfer(size_t size)=0
启动一次传输 / Start a transfer
RawData GetBuffer() const
获取当前可用于传输的缓冲区 / Get current transfer buffer
Definition ep.hpp:246
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
LibXR 命名空间
Definition ch32_can.hpp:14
ErrorCode
定义错误码枚举
@ NOT_FOUND
未找到 | Not found
@ NOT_SUPPORT
不支持 | Not supported
@ FAILED
操作失败 | Operation failed
@ OK
操作成功 | Operation successful
@ ARG_ERR
参数错误 | Argument error
SWD 传输请求 / SWD transfer request.
SWD 传输响应 / SWD transfer response.
bool parity_ok
奇偶校验是否正确 / Whether parity is OK
uint32_t rdata
读数据(仅读响应有效)/ Read data (valid for read responses)
端点描述符(7 字节)/ Endpoint descriptor (7 bytes)
Definition desc_cfg.hpp:91
接口描述符(9 字节)/ Interface descriptor (9 bytes)
Definition desc_cfg.hpp:75