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