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/jtag_dp.hpp"
9#include "debug/swd.hpp"
10#include "dev_core.hpp"
11#include "gpio.hpp"
12#include "libxr_def.hpp"
13#include "libxr_mem.hpp"
14#include "libxr_type.hpp"
15#include "timebase.hpp"
16#include "usb/core/desc_cfg.hpp"
17#include "winusb_msos20.hpp"
18
19namespace LibXR::USB
20{
21#ifndef LIBXR_USB_DAPLINK_V2_BUILD_CONFIG_DEFINED
22#define LIBXR_USB_DAPLINK_V2_BUILD_CONFIG_DEFINED
23namespace DapLinkV2BuildConfig
24{
25static constexpr bool kEnableJtag = true;
26}
27#endif
28
35template <typename SwdPort, uint16_t DefaultDapPacketSize = 512u,
36 uint8_t AdvertisedPacketCount = 8u, uint16_t MaxDapPacketSize = 1024u,
37 uint16_t QueuedRequestBufferSize = 2048u, uint16_t QueuedCommandCountMax = 255u>
39{
40 public:
41 static constexpr bool JTAG_ENABLED = DapLinkV2BuildConfig::kEnableJtag;
42 static constexpr const char* DEFAULT_INTERFACE_STRING = "CMSIS-DAP v2";
43
48 {
49 const char* vendor = nullptr;
50 const char* product = nullptr;
51 const char* serial = nullptr;
52 const char* firmware_ver = nullptr;
53
54 const char* device_vendor = nullptr;
55 const char* device_name = nullptr;
56 const char* board_vendor = nullptr;
57 const char* board_name = nullptr;
58 const char* product_fw_ver = nullptr;
59 };
60
61 public:
71 explicit DapLinkV2Class(Endpoint::EPNumber data_in_ep_num,
72 Endpoint::EPNumber data_out_ep_num, SwdPort& swd_link,
73 LibXR::GPIO* nreset_gpio = nullptr,
74 const char* interface_string = DEFAULT_INTERFACE_STRING)
75 : DeviceClass(),
76 swd_(swd_link),
77 nreset_gpio_(nreset_gpio),
78 interface_string_(interface_string),
79 data_in_ep_num_(data_in_ep_num),
80 data_out_ep_num_(data_out_ep_num)
81 {
82 (void)swd_.SetClockHz(swj_clock_hz_);
83
84 // Init WinUSB descriptor templates (constant parts)
85 InitWinUsbDescriptors();
86 }
87
91 ~DapLinkV2Class() override = default;
92
93 DapLinkV2Class(const DapLinkV2Class&) = delete;
94 DapLinkV2Class& operator=(const DapLinkV2Class&) = delete;
95
96 public:
97 const char* GetInterfaceString(size_t local_interface_index) const override
98 {
99 return (local_interface_index == 0u) ? interface_string_ : nullptr;
100 }
101
106 void SetInfoStrings(const InfoStrings& info) { info_ = info; }
107
108 void SetJtag(LibXR::Debug::Jtag* jtag)
109 {
110 if constexpr (JTAG_ENABLED)
111 {
112 jtag_ = jtag;
114 ResetJtagChainState();
115 if (jtag_ != nullptr)
116 {
118 }
119 }
120 else
121 {
122 (void)jtag;
123 }
124 }
125
131
136 bool IsInited() const { return inited_; }
137
144 bool EpInBusy()
145 {
146 auto ep = ep_data_in_;
147 return ep->GetState() != Endpoint::State::IDLE;
148 }
149
157 {
158 auto ep = ep_data_out_;
159 return ep->GetState() != Endpoint::State::IDLE;
160 }
161
162 protected:
169 void BindEndpoints(EndpointPool& endpoint_pool, uint8_t start_itf_num, bool) override
170 {
171 inited_ = false;
172
173 interface_num_ = start_itf_num;
174
175 // Patch WinUSB function subset to match this interface number
176 UpdateWinUsbInterfaceFields();
177
178 // Allocate endpoints
179 auto ans =
181 ASSERT(ans == ErrorCode::OK);
182
184 ASSERT(ans == ErrorCode::OK);
185
186 // Configure endpoints
187 // - Use upper bound; core will choose a valid max packet size <= this limit.
188 // - Enable double_buffer for USB pipeline overlap.
192 {Endpoint::Direction::IN, Endpoint::Type::BULK, UINT16_MAX, true});
193
194 // Hook callbacks
197
198 // Interface descriptor (vendor specific, 2 endpoints)
199 desc_block_.intf = {9,
200 static_cast<uint8_t>(DescriptorType::INTERFACE),
202 0,
203 2,
204 0xFF, // vendor specific
205 0x00,
206 0x00,
208
209 desc_block_.ep_out = {7,
210 static_cast<uint8_t>(DescriptorType::ENDPOINT),
211 static_cast<uint8_t>(ep_data_out_->GetAddress()),
212 static_cast<uint8_t>(Endpoint::Type::BULK),
214 0};
215
216 desc_block_.ep_in = {7,
217 static_cast<uint8_t>(DescriptorType::ENDPOINT),
218 static_cast<uint8_t>(ep_data_in_->GetAddress()),
219 static_cast<uint8_t>(Endpoint::Type::BULK),
221 0};
222
223 SetData(RawData{reinterpret_cast<uint8_t*>(&desc_block_), sizeof(desc_block_)});
224
225 // Runtime defaults
226 dap_state_ = {};
227 dap_state_.debug_port = LibXR::USB::DapLinkV2Def::DebugPort::DISABLED;
229
230 swj_clock_hz_ = 1'000'000u;
231 (void)swd_.SetClockHz(swj_clock_hz_);
232 if constexpr (JTAG_ENABLED)
233 {
234 if (jtag_ != nullptr)
235 {
237 }
238 }
239
240 // SWJ shadow defaults: SWDIO=1, nRESET=1, SWCLK=0
242 swj_shadow_ = static_cast<uint8_t>(DapLinkV2Def::DAP_SWJ_SWDIO_TMS |
243 DapLinkV2Def::DAP_SWJ_NRESET);
244
245 ResetResponseQueue();
246 ResetQueuedCommandState();
247 ResetJtagChainState();
249
250 inited_ = true;
251 ArmOutTransferIfIdle();
252 }
253
259 void UnbindEndpoints(EndpointPool& endpoint_pool, bool) override
260 {
261 inited_ = false;
262 ResetResponseQueue();
263 ResetQueuedCommandState();
264
265 dap_state_.debug_port = LibXR::USB::DapLinkV2Def::DebugPort::DISABLED;
267
268 if (ep_data_in_)
269 {
272 endpoint_pool.Release(ep_data_in_);
273 ep_data_in_ = nullptr;
274 }
275
276 if (ep_data_out_)
277 {
280 endpoint_pool.Release(ep_data_out_);
281 ep_data_out_ = nullptr;
282 }
283
284 swd_.Close();
285 if constexpr (JTAG_ENABLED)
286 {
287 if (jtag_ != nullptr)
288 {
289 jtag_->Close();
290 }
291 }
292
293 // Reset shadow defaults
295 swj_shadow_ = static_cast<uint8_t>(DapLinkV2Def::DAP_SWJ_SWDIO_TMS |
296 DapLinkV2Def::DAP_SWJ_NRESET);
297 }
298
303 size_t GetInterfaceCount() override { return 1; }
304
309 bool HasIAD() override { return false; }
310
316 bool OwnsEndpoint(uint8_t ep_addr) const override
317 {
318 if (!inited_)
319 {
320 return false;
321 }
322 return (ep_data_in_ && ep_addr == ep_data_in_->GetAddress()) ||
323 (ep_data_out_ && ep_addr == ep_data_out_->GetAddress());
324 }
325
330 size_t GetMaxConfigSize() override { return sizeof(desc_block_); }
331
337 {
338 return ConstRawData{reinterpret_cast<const uint8_t*>(&winusb_msos20_),
339 sizeof(winusb_msos20_)};
340 }
341
346 size_t GetBosCapabilityCount() override { return 1; }
347
353 BosCapability* GetBosCapability(size_t index) override
354 {
355 if (index == 0)
356 {
357 return &winusb_msos20_cap_;
358 }
359 return nullptr;
360 }
361
362 private:
363 // ============================================================================
364 // Local helpers (kept with original comments, moved inside the class)
365 // ============================================================================
366
367 // Cast enum/integer to uint8_t.
368 template <typename E>
369 static constexpr uint8_t ToU8(E e)
370 {
371 return static_cast<uint8_t>(e);
372 }
373
374 // CMSIS-DAP status bytes
375 static constexpr uint8_t DAP_OK = 0x00u;
376 static constexpr uint8_t DAP_ERROR = 0xFFu;
377
378 // Unknown command response: single byte 0xFF.
379 static inline ErrorCode BuildUnknownCmdResponse(uint8_t* resp, uint16_t cap,
380 uint16_t& out_len)
381 {
382 if (!resp || cap < 1u)
383 {
384 out_len = 0u;
386 }
387 resp[0] = 0xFFu;
388 out_len = 1u;
389 return ErrorCode::OK;
390 }
391
392 // Command status response: <cmd, status>.
393 static inline ErrorCode BuildCmdStatusResponse(uint8_t cmd, uint8_t status,
394 uint8_t* resp, uint16_t cap,
395 uint16_t& out_len)
396 {
397 if (!resp || cap < 2u)
398 {
399 out_len = 0u;
401 }
402 resp[0] = cmd;
403 resp[1] = status;
404 out_len = 2u;
405 return ErrorCode::OK;
406 }
407
408 private:
409 // ============================================================================
410 // WinUSB descriptors
411 // ============================================================================
412
413 void InitWinUsbDescriptors()
414 {
415 winusb_msos20_.set.wLength = static_cast<uint16_t>(sizeof(winusb_msos20_.set));
416 winusb_msos20_.set.wDescriptorType =
417 LibXR::USB::WinUsbMsOs20::MS_OS_20_SET_HEADER_DESCRIPTOR;
418 winusb_msos20_.set.dwWindowsVersion = 0x06030000; // Win 8.1+
419 winusb_msos20_.set.wTotalLength = static_cast<uint16_t>(sizeof(winusb_msos20_));
420
421 winusb_msos20_.cfg.wLength = static_cast<uint16_t>(sizeof(winusb_msos20_.cfg));
422 winusb_msos20_.cfg.wDescriptorType =
423 LibXR::USB::WinUsbMsOs20::MS_OS_20_SUBSET_HEADER_CONFIGURATION;
424
425 // MS OS 2.0 configuration subset uses a zero-based configuration index.
426 winusb_msos20_.cfg.bConfigurationValue = 0u;
427 winusb_msos20_.cfg.bReserved = 0;
428 winusb_msos20_.cfg.wTotalLength = static_cast<uint16_t>(
429 sizeof(winusb_msos20_) - offsetof(WinUsbMsOs20DescSet, cfg));
430
431 winusb_msos20_.func.wLength = static_cast<uint16_t>(sizeof(winusb_msos20_.func));
432 winusb_msos20_.func.wDescriptorType =
433 LibXR::USB::WinUsbMsOs20::MS_OS_20_SUBSET_HEADER_FUNCTION;
434 winusb_msos20_.func.bReserved = 0;
435 winusb_msos20_.func.wTotalLength = static_cast<uint16_t>(
436 sizeof(winusb_msos20_) - offsetof(WinUsbMsOs20DescSet, func));
437
438 winusb_msos20_.compat.wLength = static_cast<uint16_t>(sizeof(winusb_msos20_.compat));
439 winusb_msos20_.compat.wDescriptorType =
440 LibXR::USB::WinUsbMsOs20::MS_OS_20_FEATURE_COMPATIBLE_ID;
441
442 winusb_msos20_.prop.header.wDescriptorType =
443 LibXR::USB::WinUsbMsOs20::MS_OS_20_FEATURE_REG_PROPERTY;
444 winusb_msos20_.prop.header.wPropertyDataType = LibXR::USB::WinUsbMsOs20::REG_MULTI_SZ;
445 winusb_msos20_.prop.header.wPropertyNameLength =
446 LibXR::USB::WinUsbMsOs20::PROP_NAME_DEVICE_INTERFACE_GUIDS_BYTES;
447
448 Memory::FastCopy(winusb_msos20_.prop.name,
449 LibXR::USB::WinUsbMsOs20::PROP_NAME_DEVICE_INTERFACE_GUIDS_UTF16,
450 LibXR::USB::WinUsbMsOs20::PROP_NAME_DEVICE_INTERFACE_GUIDS_BYTES);
451
452 // DeviceInterfaceGUIDs: REG_MULTI_SZ UTF-16LE, include double-NUL terminator
453 // Single GUID plus double-NUL terminator for REG_MULTI_SZ.
454 const char GUID_STR[] = "{CDB3B5AD-293B-4663-AA36-1AAE46463776}";
455 const size_t GUID_LEN = sizeof(GUID_STR) - 1;
456
457 for (size_t i = 0; i < GUID_LEN; ++i)
458 {
459 winusb_msos20_.prop.data[i * 2] = static_cast<uint8_t>(GUID_STR[i]);
460 winusb_msos20_.prop.data[i * 2 + 1] = 0x00;
461 }
462
463 // Append UTF-16 NUL + extra UTF-16 NUL (REG_MULTI_SZ end)
464 winusb_msos20_.prop.data[GUID_LEN * 2 + 0] = 0x00;
465 winusb_msos20_.prop.data[GUID_LEN * 2 + 1] = 0x00;
466 winusb_msos20_.prop.data[GUID_LEN * 2 + 2] = 0x00;
467 winusb_msos20_.prop.data[GUID_LEN * 2 + 3] = 0x00;
468
469 winusb_msos20_.prop.wPropertyDataLength = static_cast<uint16_t>((GUID_LEN * 2) + 4);
470 winusb_msos20_.prop.header.wLength =
471 static_cast<uint16_t>(sizeof(winusb_msos20_.prop));
472
473 // Sync to BOS capability object
476 }
477
478 void UpdateWinUsbInterfaceFields()
479 {
480 // Function subset interface number
481 winusb_msos20_.func.bFirstInterface = interface_num_;
482
483 // Content changes but total size stays the same; resync for consistency.
485 }
486
487 private:
488 // ============================================================================
489 // USB callbacks
490 // ============================================================================
491
495 static void OnDataOutCompleteStatic(bool in_isr, DapLinkV2Class* self,
497 {
498 if (self && self->inited_)
499 {
500 self->OnDataOutComplete(in_isr, data);
501 }
502 }
503
507 static void OnDataInCompleteStatic(bool in_isr, DapLinkV2Class* self,
509 {
510 if (self && self->inited_)
511 {
512 self->OnDataInComplete(in_isr, data);
513 }
514 }
515
519 void OnDataOutComplete(bool in_isr, LibXR::ConstRawData& data)
520 {
521 (void)in_isr;
522
523 if (!inited_ || !ep_data_in_ || !ep_data_out_)
524 {
525 return;
526 }
527
528 const auto* req = static_cast<const uint8_t*>(data.addr_);
529 const uint16_t REQ_LEN = static_cast<uint16_t>(data.size_);
530
531 // Fast path: when IN is idle and no backlog exists, build directly
532 // in the IN endpoint buffer and submit without extra response copy.
533 if (!HasDeferredResponseInEpBuffer() && IsResponseQueueEmpty() &&
535 CanBuildResponseDirectlyInEpBuffer())
536 {
537 auto tx_buff = ep_data_in_->GetBuffer();
538 if (tx_buff.addr_ && tx_buff.size_ > 0u)
539 {
540 auto* tx_buf = static_cast<uint8_t*>(tx_buff.addr_);
541 uint16_t out_len = 0u;
542 auto ans = ProcessOneCommand(in_isr, req, REQ_LEN, tx_buf,
543 static_cast<uint16_t>(tx_buff.size_), out_len);
544 UNUSED(ans);
545
546 out_len = ClipResponseLength(out_len, static_cast<uint16_t>(tx_buff.size_));
547 if (StartInTransferFromCurrentBuffer(out_len))
548 {
549 return;
550 }
551
552 if (!EnqueueResponse(tx_buf, out_len))
553 {
554 (void)SubmitNextQueuedResponseIfIdle();
555 (void)EnqueueResponse(tx_buf, out_len);
556 }
557
558 (void)SubmitNextQueuedResponseIfIdle();
559 ArmOutTransferIfIdle();
560 return;
561 }
562 }
563
564 // Deferred fast path: when IN is busy and no backlog exists, build the next
565 // response in the alternate IN double buffer to avoid queue copy.
566 if (!HasDeferredResponseInEpBuffer() && IsResponseQueueEmpty() &&
568 CanBuildResponseDirectlyInEpBuffer())
569 {
570 auto tx_buff = ep_data_in_->GetBuffer();
571 if (tx_buff.addr_ && tx_buff.size_ > 0u)
572 {
573 auto* tx_buf = static_cast<uint8_t*>(tx_buff.addr_);
574 uint16_t out_len = 0u;
575 auto ans = ProcessOneCommand(in_isr, req, REQ_LEN, tx_buf,
576 static_cast<uint16_t>(tx_buff.size_), out_len);
577 UNUSED(ans);
578
579 out_len = ClipResponseLength(out_len, static_cast<uint16_t>(tx_buff.size_));
580 SetDeferredResponseInEpBuffer(out_len);
581 ArmOutTransferIfIdle();
582 return;
583 }
584 }
585
586 if (TryBuildAndEnqueueResponse(in_isr, req, REQ_LEN))
587 {
588 (void)SubmitDeferredResponseIfIdle();
589 (void)SubmitNextQueuedResponseIfIdle();
590 ArmOutTransferIfIdle();
591 return;
592 }
593
594 // Should not happen with proper backpressure; drain once and retry queue build.
595 (void)SubmitNextQueuedResponseIfIdle();
596 (void)TryBuildAndEnqueueResponse(in_isr, req, REQ_LEN);
597
598 (void)SubmitDeferredResponseIfIdle();
599 (void)SubmitNextQueuedResponseIfIdle();
600 ArmOutTransferIfIdle();
601 }
602
606 void OnDataInComplete(bool /*in_isr*/, LibXR::ConstRawData& /*data*/)
607 {
608 (void)SubmitDeferredResponseIfIdle();
609 (void)SubmitNextQueuedResponseIfIdle();
610 ArmOutTransferIfIdle();
611 }
612
613 private:
617 uint16_t GetDapPacketSize() const
618 {
619 constexpr uint16_t OPENOCD_SAFE_PS = static_cast<uint16_t>((255u * 5u) + 4u);
620 constexpr uint16_t RAW_PS =
621 (MaxDapPacketSize == 0u) ? DefaultDapPacketSize : MaxDapPacketSize;
622 return (RAW_PS > OPENOCD_SAFE_PS) ? OPENOCD_SAFE_PS : RAW_PS;
623 }
624 bool CanBuildResponseDirectlyInEpBuffer() const
625 {
626 if (!ep_data_in_)
627 {
628 return false;
629 }
630 auto tx_buff = ep_data_in_->GetBuffer();
631 if (!tx_buff.addr_ || tx_buff.size_ == 0u)
632 {
633 return false;
634 }
635 return GetDapPacketSize() <= static_cast<uint16_t>(tx_buff.size_);
636 }
637
638 bool StartInTransferFromCurrentBuffer(uint16_t len)
639 {
640 if (!ep_data_in_)
641 {
642 return false;
643 }
644 auto tx_buff = ep_data_in_->GetBuffer();
645 if (!tx_buff.addr_ || tx_buff.size_ == 0u)
646 {
647 return false;
648 }
649 uint16_t tx_len = len;
650 if (tx_len > tx_buff.size_)
651 {
652 tx_len = static_cast<uint16_t>(tx_buff.size_);
653 }
654 if (tx_len <= static_cast<uint16_t>(ep_data_in_->MaxTransferSize()))
655 {
656 return ep_data_in_->Transfer(tx_len) == ErrorCode::OK;
657 }
658 LibXR::RawData in_multi{tx_buff.addr_, tx_len};
659 return ep_data_in_->TransferMultiBulk(in_multi) == ErrorCode::OK;
660 }
661 bool StartInTransferFromPayload(const uint8_t* data, uint16_t len)
662 {
663 if (!ep_data_in_ || !data)
664 {
665 return false;
666 }
667 auto tx_buff = ep_data_in_->GetBuffer();
668 if (!tx_buff.addr_ || tx_buff.size_ == 0u)
669 {
670 return false;
671 }
672 uint16_t tx_len = len;
673 if (tx_len > MAX_DAP_PACKET_SIZE)
674 {
675 tx_len = MAX_DAP_PACKET_SIZE;
676 }
677 const uint16_t MAX_XFER = static_cast<uint16_t>(ep_data_in_->MaxTransferSize());
678 if (tx_len <= MAX_XFER && tx_len <= static_cast<uint16_t>(tx_buff.size_))
679 {
680 if (tx_len > 0u)
681 {
682 Memory::FastCopy(tx_buff.addr_, data, tx_len);
683 }
684 return ep_data_in_->Transfer(tx_len) == ErrorCode::OK;
685 }
686 if (tx_len > static_cast<uint16_t>(sizeof(in_tx_multi_storage_)))
687 {
688 tx_len = static_cast<uint16_t>(sizeof(in_tx_multi_storage_));
689 }
690 if (tx_len > 0u && data != in_tx_multi_storage_)
691 {
692 Memory::FastCopy(in_tx_multi_storage_, data, tx_len);
693 }
694 in_tx_multi_buf_.addr_ = in_tx_multi_storage_;
695 in_tx_multi_buf_.size_ = tx_len;
696 return ep_data_in_->TransferMultiBulk(in_tx_multi_buf_) == ErrorCode::OK;
697 }
698
702 uint16_t ClipResponseLength(uint16_t len, uint16_t cap) const
703 {
704 const uint16_t DAP_PS = GetDapPacketSize();
705 if (len > DAP_PS)
706 {
707 len = DAP_PS;
708 }
709 if (len > RESP_SLOT_SIZE)
710 {
711 len = RESP_SLOT_SIZE;
712 }
713 if (len > cap)
714 {
715 len = cap;
716 }
717 return len;
718 }
719
720 static constexpr uint8_t NextRespQueueIndex(uint8_t idx)
721 {
722 return static_cast<uint8_t>((idx + 1u) & (RESP_QUEUE_DEPTH - 1u));
723 }
724
725 void ResetResponseQueue()
726 {
727 resp_q_head_ = 0u;
728 resp_q_tail_ = 0u;
729 resp_q_count_ = 0u;
730 deferred_in_resp_valid_ = false;
731 deferred_in_resp_len_ = 0u;
732 }
733
734 bool HasDeferredResponseInEpBuffer() const { return deferred_in_resp_valid_; }
735
736 void SetDeferredResponseInEpBuffer(uint16_t len)
737 {
738 deferred_in_resp_len_ = len;
739 deferred_in_resp_valid_ = true;
740 }
741
742 bool SubmitDeferredResponseIfIdle()
743 {
744 if (!deferred_in_resp_valid_ || !ep_data_in_ ||
746 {
747 return false;
748 }
749
750 const uint16_t TX_LEN = deferred_in_resp_len_;
751 if (!StartInTransferFromCurrentBuffer(TX_LEN))
752 {
753 return false;
754 }
755
756 deferred_in_resp_valid_ = false;
757 deferred_in_resp_len_ = 0u;
758 return true;
759 }
760
761 bool IsResponseQueueEmpty() const { return resp_q_count_ == 0u; }
762
763 bool IsResponseQueueFull() const { return resp_q_count_ >= RESP_QUEUE_DEPTH; }
764
765 void ResetQueuedCommandState()
766 {
767 queued_request_length_ = 0u;
768 queued_command_count_ = 0u;
769 }
770
771 // ============================================================================
772 // Queued command helpers
773 // ============================================================================
774
783 bool ParseQueuedCommandLength(const uint8_t* req, uint16_t avail,
784 uint16_t& cmd_len) const
785 {
786 cmd_len = 0u;
787 if (!req || avail < 1u)
788 {
789 return false;
790 }
791
792 const uint8_t CMD = req[0];
793 switch (CMD)
794 {
795 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::INFO):
796 cmd_len = 2u;
797 return avail >= cmd_len;
798 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::HOST_STATUS):
799 cmd_len = 3u;
800 return avail >= cmd_len;
801 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::CONNECT):
802 cmd_len = 2u;
803 return avail >= cmd_len;
804 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::DISCONNECT):
805 cmd_len = 1u;
806 return avail >= cmd_len;
807 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::TRANSFER_CONFIGURE):
808 cmd_len = 6u;
809 return avail >= cmd_len;
810 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::TRANSFER_ABORT):
811 cmd_len = 1u;
812 return avail >= cmd_len;
813 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::WRITE_ABORT):
814 cmd_len = 6u;
815 return avail >= cmd_len;
816 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::DELAY):
817 cmd_len = 3u;
818 return avail >= cmd_len;
819 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::RESET_TARGET):
820 cmd_len = 1u;
821 return avail >= cmd_len;
822 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::SWJ_PINS):
823 cmd_len = 7u;
824 return avail >= cmd_len;
825 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::SWJ_CLOCK):
826 cmd_len = 5u;
827 return avail >= cmd_len;
828 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::SWD_CONFIGURE):
829 cmd_len = 2u;
830 return avail >= cmd_len;
831 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::SWJ_SEQUENCE):
832 {
833 if (avail < 2u)
834 {
835 return false;
836 }
837 const uint32_t BIT_COUNT = (req[1] == 0u) ? 256u : static_cast<uint32_t>(req[1]);
838 const uint32_t BYTE_COUNT = (BIT_COUNT + 7u) / 8u;
839 const uint32_t NEED = 2u + BYTE_COUNT;
840 if (NEED > avail)
841 {
842 return false;
843 }
844 cmd_len = static_cast<uint16_t>(NEED);
845 return true;
846 }
847 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::SWD_SEQUENCE):
848 {
849 if (avail < 2u)
850 {
851 return false;
852 }
853 const uint8_t SEQ_CNT = req[1];
854 uint32_t off = 2u;
855 for (uint32_t i = 0u; i < SEQ_CNT; ++i)
856 {
857 if (off >= avail)
858 {
859 return false;
860 }
861
862 const uint8_t INFO = req[off++];
863 uint32_t cycles = static_cast<uint32_t>(INFO & 0x3Fu);
864 if (cycles == 0u)
865 {
866 cycles = 64u;
867 }
868
869 const bool MODE_IN = ((INFO & 0x80u) != 0u);
870 const uint32_t BYTES = (cycles + 7u) / 8u;
871 if (!MODE_IN)
872 {
873 if (off + BYTES > avail)
874 {
875 return false;
876 }
877 off += BYTES;
878 }
879 }
880 cmd_len = static_cast<uint16_t>(off);
881 return true;
882 }
883 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::TRANSFER):
884 {
885 if (avail < 3u)
886 {
887 return false;
888 }
889 const uint8_t COUNT = req[2];
890 uint32_t off = 3u;
891 for (uint32_t i = 0u; i < COUNT; ++i)
892 {
893 if (off >= avail)
894 {
895 return false;
896 }
897
898 const uint8_t RQ = req[off++];
899 const bool RNW = LibXR::USB::DapLinkV2Def::req_is_read(RQ);
900 const bool MATCH_VALUE =
901 ((RQ & LibXR::USB::DapLinkV2Def::DAP_TRANSFER_MATCH_VALUE) != 0u);
902 if (!RNW || MATCH_VALUE)
903 {
904 if (off + 4u > avail)
905 {
906 return false;
907 }
908 off += 4u;
909 }
910 }
911 cmd_len = static_cast<uint16_t>(off);
912 return true;
913 }
914 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::TRANSFER_BLOCK):
915 {
916 if (avail < 5u)
917 {
918 return false;
919 }
920 uint16_t count = 0u;
921 Memory::FastCopy(&count, &req[2], sizeof(count));
922 const bool RNW = LibXR::USB::DapLinkV2Def::req_is_read(req[4]);
923 uint32_t need = 5u;
924 if (!RNW)
925 {
926 need += static_cast<uint32_t>(count) * 4u;
927 }
928 if (need > avail)
929 {
930 return false;
931 }
932 cmd_len = static_cast<uint16_t>(need);
933 return true;
934 }
935
936 // Reject nested queue/execute in queued stream.
937 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::QUEUE_COMMANDS):
938 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::EXECUTE_COMMANDS):
939 default:
940 return false;
941 }
942 }
943
953 bool TryExecuteQueuedCommandStream(bool in_isr, uint8_t* resp, uint16_t resp_cap,
954 uint16_t& out_len)
955 {
956 out_len = 0u;
957 if (!resp || resp_cap < 1u)
958 {
959 return false;
960 }
961
962 resp[0] = ToU8(LibXR::USB::DapLinkV2Def::CommandId::EXECUTE_COMMANDS);
963 out_len = 1u;
964
965 if (queued_command_count_ == 0u)
966 {
967 return true;
968 }
969
970 uint16_t req_off = 0u;
971 uint16_t resp_off = 1u;
972 for (uint32_t i = 0u; i < queued_command_count_; ++i)
973 {
974 if (req_off >= queued_request_length_)
975 {
976 return false;
977 }
978
979 uint16_t cmd_len = 0u;
981 &queued_request_buffer_[req_off],
982 static_cast<uint16_t>(queued_request_length_ - req_off), cmd_len) ||
983 cmd_len == 0u)
984 {
985 return false;
986 }
987
988 if (resp_off >= resp_cap)
989 {
990 return false;
991 }
992
993 uint16_t cmd_out = 0u;
994 const ErrorCode ans = ProcessOneCommand(
995 in_isr, &queued_request_buffer_[req_off], cmd_len, &resp[resp_off],
996 static_cast<uint16_t>(resp_cap - resp_off), cmd_out);
997 UNUSED(ans);
998
999 if (static_cast<uint32_t>(resp_off) + static_cast<uint32_t>(cmd_out) >
1000 static_cast<uint32_t>(resp_cap))
1001 {
1002 return false;
1003 }
1004
1005 req_off = static_cast<uint16_t>(req_off + cmd_len);
1006 resp_off = static_cast<uint16_t>(resp_off + cmd_out);
1007 }
1008
1009 if (req_off != queued_request_length_)
1010 {
1011 return false;
1012 }
1013
1014 out_len = resp_off;
1015 return true;
1016 }
1017
1018 bool TryBuildAndEnqueueResponse(bool in_isr, const uint8_t* req, uint16_t req_len)
1019 {
1020 if (!req || IsResponseQueueFull())
1021 {
1022 return false;
1023 }
1024
1025 auto& slot = resp_q_[resp_q_tail_];
1026 uint16_t out_len = 0u;
1027 auto ans =
1028 ProcessOneCommand(in_isr, req, req_len, slot.payload, RESP_SLOT_SIZE, out_len);
1029 UNUSED(ans);
1030 slot.len = ClipResponseLength(out_len, RESP_SLOT_SIZE);
1031
1032 resp_q_tail_ = NextRespQueueIndex(resp_q_tail_);
1033 ++resp_q_count_;
1034 return true;
1035 }
1036
1037 uint8_t OutstandingResponseCount() const
1038 {
1039 const uint8_t IN_FLIGHT =
1041 const uint8_t DEFERRED = deferred_in_resp_valid_ ? 1u : 0u;
1042 return static_cast<uint8_t>(resp_q_count_ + IN_FLIGHT + DEFERRED);
1043 }
1044
1045 bool EnqueueResponse(const uint8_t* data, uint16_t len)
1046 {
1047 if (!data || IsResponseQueueFull())
1048 {
1049 return false;
1050 }
1051
1052 auto& slot = resp_q_[resp_q_tail_];
1053 const uint16_t CLIPPED = ClipResponseLength(len, RESP_SLOT_SIZE);
1054 slot.len = CLIPPED;
1055 if (CLIPPED > 0u)
1056 {
1057 Memory::FastCopy(slot.payload, data, CLIPPED);
1058 }
1059
1060 resp_q_tail_ = NextRespQueueIndex(resp_q_tail_);
1061 ++resp_q_count_;
1062 return true;
1063 }
1064
1065 bool SubmitNextQueuedResponseIfIdle()
1066 {
1068 IsResponseQueueEmpty())
1069 {
1070 return false;
1071 }
1072 auto& slot = resp_q_[resp_q_head_];
1073 if (!StartInTransferFromPayload(slot.payload, slot.len))
1074 {
1075 return false;
1076 }
1077 resp_q_head_ = NextRespQueueIndex(resp_q_head_);
1078 --resp_q_count_;
1079 return true;
1080 }
1081
1082 void ArmOutTransferIfIdle()
1083 {
1084 if (!inited_ || ep_data_out_ == nullptr || ep_data_in_ == nullptr)
1085 {
1086 return;
1087 }
1088
1090 {
1091 return;
1092 }
1093
1094 // Backpressure on total outstanding responses (in-flight + queued).
1095 if (OutstandingResponseCount() >= MAX_OUTSTANDING_RESPONSES)
1096 {
1097 return;
1098 }
1099
1100 uint16_t out_rx_len = GetDapPacketSize();
1101 if (out_rx_len == 0u)
1102 {
1103 out_rx_len = DEFAULT_DAP_PACKET_SIZE;
1104 }
1105 if (out_rx_len > MAX_DAP_PACKET_SIZE)
1106 {
1107 out_rx_len = MAX_DAP_PACKET_SIZE;
1108 }
1109
1110 const uint16_t OUT_MAX_XFER = static_cast<uint16_t>(ep_data_out_->MaxTransferSize());
1111 if (OUT_MAX_XFER == 0u)
1112 {
1113 return;
1114 }
1115
1116 if (out_rx_len <= OUT_MAX_XFER)
1117 {
1118 (void)ep_data_out_->Transfer(out_rx_len);
1119 return;
1120 }
1121
1122 if (out_rx_len > static_cast<uint16_t>(sizeof(out_req_multi_storage_)))
1123 {
1124 out_rx_len = static_cast<uint16_t>(sizeof(out_req_multi_storage_));
1125 }
1126
1127 // Endpoint MPS is capped by hardware (HS bulk = 512), so larger DAP requests
1128 // must be received with multi-bulk reassembly.
1129 out_req_multi_buf_.addr_ = out_req_multi_storage_;
1130 out_req_multi_buf_.size_ = out_rx_len;
1131 (void)ep_data_out_->TransferMultiBulk(out_req_multi_buf_);
1132 }
1133
1134 private:
1135 // ============================================================================
1136 // Command dispatch
1137 // ============================================================================
1138
1150 ErrorCode ProcessOneCommand(bool in_isr, const uint8_t* req, uint16_t req_len,
1151 uint8_t* resp, uint16_t resp_cap, uint16_t& out_len)
1152 {
1153 out_len = 0;
1154
1155 if (!req || !resp || req_len < 1u || resp_cap < 1u)
1156 {
1157 if (resp && resp_cap >= 1u)
1158 {
1159 BuildNotSupportResponse(resp, resp_cap, out_len);
1160 }
1161 return ErrorCode::ARG_ERR;
1162 }
1163
1164 const uint8_t CMD = req[0];
1165
1166 switch (CMD)
1167 {
1168 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::INFO):
1169 return HandleInfo(in_isr, req, req_len, resp, resp_cap, out_len);
1170 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::HOST_STATUS):
1171 return HandleHostStatus(in_isr, req, req_len, resp, resp_cap, out_len);
1172 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::CONNECT):
1173 return HandleConnect(in_isr, req, req_len, resp, resp_cap, out_len);
1174 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::DISCONNECT):
1175 return HandleDisconnect(in_isr, req, req_len, resp, resp_cap, out_len);
1176 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::TRANSFER_CONFIGURE):
1177 return HandleTransferConfigure(in_isr, req, req_len, resp, resp_cap, out_len);
1178 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::TRANSFER):
1179 return HandleTransfer(in_isr, req, req_len, resp, resp_cap, out_len);
1180 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::TRANSFER_BLOCK):
1181 return HandleTransferBlock(in_isr, req, req_len, resp, resp_cap, out_len);
1182 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::TRANSFER_ABORT):
1183 return HandleTransferAbort(in_isr, req, req_len, resp, resp_cap, out_len);
1184 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::WRITE_ABORT):
1185 return HandleWriteABORT(in_isr, req, req_len, resp, resp_cap, out_len);
1186 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::DELAY):
1187 return HandleDelay(in_isr, req, req_len, resp, resp_cap, out_len);
1188 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::RESET_TARGET):
1189 return HandleResetTarget(in_isr, req, req_len, resp, resp_cap, out_len);
1190
1191 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::SWJ_PINS):
1192 return HandleSWJPins(in_isr, req, req_len, resp, resp_cap, out_len);
1193 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::SWJ_CLOCK):
1194 return HandleSWJClock(in_isr, req, req_len, resp, resp_cap, out_len);
1195 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::SWJ_SEQUENCE):
1196 return HandleSWJSequence(in_isr, req, req_len, resp, resp_cap, out_len);
1197 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::SWD_CONFIGURE):
1198 return HandleSWDConfigure(in_isr, req, req_len, resp, resp_cap, out_len);
1199 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::SWD_SEQUENCE):
1200 return HandleSWDSequence(in_isr, req, req_len, resp, resp_cap, out_len);
1201
1202 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::JTAG_SEQUENCE):
1203 if constexpr (JTAG_ENABLED)
1204 {
1205 return HandleJTAGSequence(in_isr, req, req_len, resp, resp_cap, out_len);
1206 }
1207 (void)BuildUnknownCmdResponse(resp, resp_cap, out_len);
1209 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::JTAG_CONFIGURE):
1210 if constexpr (JTAG_ENABLED)
1211 {
1212 return HandleJTAGConfigure(in_isr, req, req_len, resp, resp_cap, out_len);
1213 }
1214 (void)BuildUnknownCmdResponse(resp, resp_cap, out_len);
1216 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::JTAG_IDCODE):
1217 if constexpr (JTAG_ENABLED)
1218 {
1219 return HandleJTAGIdCode(in_isr, req, req_len, resp, resp_cap, out_len);
1220 }
1221 (void)BuildUnknownCmdResponse(resp, resp_cap, out_len);
1223
1224 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::QUEUE_COMMANDS):
1225 return HandleQueueCommands(in_isr, req, req_len, resp, resp_cap, out_len);
1226 case ToU8(LibXR::USB::DapLinkV2Def::CommandId::EXECUTE_COMMANDS):
1227 return HandleExecuteCommands(in_isr, req, req_len, resp, resp_cap, out_len);
1228
1229 default:
1230 (void)BuildUnknownCmdResponse(resp, resp_cap, out_len);
1232 }
1233 }
1234
1242 void BuildNotSupportResponse(uint8_t* resp, uint16_t resp_cap, uint16_t& out_len)
1243 {
1244 if (!resp || resp_cap < 1u)
1245 {
1246 out_len = 0u;
1247 return;
1248 }
1249 resp[0] = 0xFFu;
1250 out_len = 1u;
1251 }
1252
1253 private:
1254 // ============================================================================
1255 // DAP_Info
1256 // ============================================================================
1257
1258 ErrorCode HandleInfo(bool /*in_isr*/, const uint8_t* req, uint16_t req_len,
1259 uint8_t* resp, uint16_t resp_cap, uint16_t& out_len)
1260 {
1261 if (req_len < 2u)
1262 {
1263 resp[0] = ToU8(LibXR::USB::DapLinkV2Def::CommandId::INFO);
1264 resp[1] = 0u;
1265 out_len = 2u;
1266 return ErrorCode::ARG_ERR;
1267 }
1268
1269 const uint8_t INFO_ID = req[1];
1270
1271 resp[0] = ToU8(LibXR::USB::DapLinkV2Def::CommandId::INFO);
1272
1273 switch (INFO_ID)
1274 {
1275 case ToU8(LibXR::USB::DapLinkV2Def::InfoId::VENDOR):
1276 return BuildInfoStringResponse(resp[0], info_.vendor, resp, resp_cap, out_len);
1277 case ToU8(LibXR::USB::DapLinkV2Def::InfoId::PRODUCT):
1278 return BuildInfoStringResponse(resp[0], info_.product, resp, resp_cap, out_len);
1279 case ToU8(LibXR::USB::DapLinkV2Def::InfoId::SERIAL_NUMBER):
1280 return BuildInfoStringResponse(resp[0], info_.serial, resp, resp_cap, out_len);
1281 case ToU8(LibXR::USB::DapLinkV2Def::InfoId::FIRMWARE_VERSION):
1282 return BuildInfoStringResponse(resp[0], info_.firmware_ver, resp, resp_cap,
1283 out_len);
1284
1285 case ToU8(LibXR::USB::DapLinkV2Def::InfoId::DEVICE_VENDOR):
1286 return BuildInfoStringResponse(resp[0], info_.device_vendor, resp, resp_cap,
1287 out_len);
1288 case ToU8(LibXR::USB::DapLinkV2Def::InfoId::DEVICE_NAME):
1289 return BuildInfoStringResponse(resp[0], info_.device_name, resp, resp_cap,
1290 out_len);
1291 case ToU8(LibXR::USB::DapLinkV2Def::InfoId::BOARD_VENDOR):
1292 return BuildInfoStringResponse(resp[0], info_.board_vendor, resp, resp_cap,
1293 out_len);
1294 case ToU8(LibXR::USB::DapLinkV2Def::InfoId::BOARD_NAME):
1295 return BuildInfoStringResponse(resp[0], info_.board_name, resp, resp_cap,
1296 out_len);
1297 case ToU8(LibXR::USB::DapLinkV2Def::InfoId::PRODUCT_FIRMWARE_VERSION):
1298 return BuildInfoStringResponse(resp[0], info_.product_fw_ver, resp, resp_cap,
1299 out_len);
1300
1301 case ToU8(LibXR::USB::DapLinkV2Def::InfoId::CAPABILITIES):
1302 {
1304 if constexpr (JTAG_ENABLED)
1305 {
1306 if (jtag_ != nullptr)
1307 {
1308 caps = static_cast<uint8_t>(caps | LibXR::USB::DapLinkV2Def::DAP_CAP_JTAG);
1309 }
1310 }
1311 return BuildInfoU8Response(resp[0], caps, resp, resp_cap, out_len);
1312 }
1313 case ToU8(LibXR::USB::DapLinkV2Def::InfoId::PACKET_COUNT):
1314 return BuildInfoU8Response(resp[0], PACKET_COUNT_EFFECTIVE, resp, resp_cap,
1315 out_len);
1316 case ToU8(LibXR::USB::DapLinkV2Def::InfoId::PACKET_SIZE):
1317 {
1318 const uint16_t DAP_PS = GetDapPacketSize();
1319 return BuildInfoU16Response(resp[0], DAP_PS, resp, resp_cap, out_len);
1320 }
1321 case ToU8(LibXR::USB::DapLinkV2Def::InfoId::TIMESTAMP_CLOCK):
1322 return BuildInfoU32Response(resp[0], 1000000U, resp, resp_cap, out_len);
1323
1324 default:
1325 resp[1] = 0u;
1326 out_len = 2u;
1327 return ErrorCode::OK;
1328 }
1329 }
1330
1331 ErrorCode BuildInfoStringResponse(uint8_t cmd, const char* str, uint8_t* resp,
1332 uint16_t resp_cap, uint16_t& out_len)
1333 {
1334 resp[0] = cmd;
1335 resp[1] = 0u;
1336
1337 if (!str)
1338 {
1339 out_len = 2u;
1340 return ErrorCode::OK;
1341 }
1342
1343 const size_t N_WITH_NUL = std::strlen(str) + 1; // include '\0'
1344 const size_t MAX_PAYLOAD = (resp_cap >= 2u) ? (resp_cap - 2u) : 0u;
1345 if (MAX_PAYLOAD == 0u)
1346 {
1347 out_len = 2u;
1348 return ErrorCode::OK;
1349 }
1350
1351 const size_t COPY_N = (N_WITH_NUL > MAX_PAYLOAD) ? MAX_PAYLOAD : N_WITH_NUL;
1352 Memory::FastCopy(&resp[2], str, COPY_N);
1353
1354 // Ensure termination even when truncated
1355 resp[2 + COPY_N - 1] = 0x00;
1356
1357 resp[1] = static_cast<uint8_t>(COPY_N);
1358 out_len = static_cast<uint16_t>(2u + COPY_N);
1359 return ErrorCode::OK;
1360 }
1361
1362 ErrorCode BuildInfoU8Response(uint8_t cmd, uint8_t val, uint8_t* resp,
1363 uint16_t resp_cap, uint16_t& out_len)
1364 {
1365 if (resp_cap < 3u)
1366 {
1367 out_len = 0;
1368 return ErrorCode::NOT_FOUND;
1369 }
1370 resp[0] = cmd;
1371 resp[1] = 1u;
1372 resp[2] = val;
1373 out_len = 3u;
1374 return ErrorCode::OK;
1375 }
1376
1377 ErrorCode BuildInfoU16Response(uint8_t cmd, uint16_t val, uint8_t* resp,
1378 uint16_t resp_cap, uint16_t& out_len)
1379 {
1380 if (resp_cap < 4u)
1381 {
1382 out_len = 0;
1383 return ErrorCode::NOT_FOUND;
1384 }
1385 resp[0] = cmd;
1386 resp[1] = 2u;
1387
1388 // Little-endian device only: direct memcpy to payload (alignment-safe).
1389 Memory::FastCopy(&resp[2], &val, sizeof(val));
1390
1391 out_len = 4u;
1392 return ErrorCode::OK;
1393 }
1394
1395 ErrorCode BuildInfoU32Response(uint8_t cmd, uint32_t val, uint8_t* resp,
1396 uint16_t resp_cap, uint16_t& out_len)
1397 {
1398 if (resp_cap < 6u)
1399 {
1400 out_len = 0;
1401 return ErrorCode::NOT_FOUND;
1402 }
1403 resp[0] = cmd;
1404 resp[1] = 4u;
1405
1406 // Little-endian device only: direct memcpy to payload (alignment-safe).
1407 Memory::FastCopy(&resp[2], &val, sizeof(val));
1408
1409 out_len = 6u;
1410 return ErrorCode::OK;
1411 }
1412
1413 private:
1414 // ============================================================================
1415 // Simple control handlers
1416 // ============================================================================
1417
1418 ErrorCode HandleHostStatus(bool /*in_isr*/, const uint8_t* /*req*/,
1419 uint16_t /*req_len*/, uint8_t* resp, uint16_t resp_cap,
1420 uint16_t& out_len)
1421 {
1422 if (resp_cap < 2u)
1423 {
1424 out_len = 0;
1425 return ErrorCode::NOT_FOUND;
1426 }
1427 resp[0] = ToU8(LibXR::USB::DapLinkV2Def::CommandId::HOST_STATUS);
1428 resp[1] = ToU8(LibXR::USB::DapLinkV2Def::Status::OK);
1429 out_len = 2u;
1430 return ErrorCode::OK;
1431 }
1432
1433 ErrorCode HandleConnect(bool /*in_isr*/, const uint8_t* req, uint16_t req_len,
1434 uint8_t* resp, uint16_t resp_cap, uint16_t& out_len)
1435 {
1436 if (resp_cap < 2u)
1437 {
1438 out_len = 0;
1439 return ErrorCode::NOT_FOUND;
1440 }
1441
1442 resp[0] = ToU8(LibXR::USB::DapLinkV2Def::CommandId::CONNECT);
1443
1444 uint8_t port = 0u;
1445 if (req_len >= 2u)
1446 {
1447 port = req[1];
1448 }
1449
1450 if (port == 0u || port == ToU8(LibXR::USB::DapLinkV2Def::Port::SWD))
1451 {
1452 (void)swd_.EnterSwd();
1453 (void)swd_.SetClockHz(swj_clock_hz_);
1454
1455 dap_state_.debug_port = LibXR::USB::DapLinkV2Def::DebugPort::SWD;
1456 dap_state_.transfer_abort = false;
1457 ResetQueuedCommandState();
1458
1459 resp[1] = ToU8(LibXR::USB::DapLinkV2Def::Port::SWD);
1460 }
1461 else if (port == ToU8(LibXR::USB::DapLinkV2Def::Port::JTAG))
1462 {
1463 if constexpr (!JTAG_ENABLED)
1464 {
1465 resp[1] = ToU8(LibXR::USB::DapLinkV2Def::Port::DISABLED);
1466 }
1467 else
1468 {
1469 if (jtag_ == nullptr)
1470 {
1471 resp[1] = ToU8(LibXR::USB::DapLinkV2Def::Port::DISABLED);
1472 }
1473 else
1474 {
1475 static constexpr uint8_t SWD_TO_JTAG_SEQUENCE[2] = {0x3Cu, 0xE7u};
1476 (void)swd_.SetClockHz(swj_clock_hz_);
1477 (void)swd_.LineReset();
1478 (void)swd_.SeqWriteBits(16u, SWD_TO_JTAG_SEQUENCE);
1479 (void)swd_.LineReset();
1481 (void)jtag_->ResetTap();
1482
1483 dap_state_.debug_port = LibXR::USB::DapLinkV2Def::DebugPort::JTAG;
1484 dap_state_.transfer_abort = false;
1485 ResetQueuedCommandState();
1486 ResetJtagChainState();
1487 resp[1] = ToU8(LibXR::USB::DapLinkV2Def::Port::JTAG);
1488 }
1489 }
1490 }
1491 else
1492 {
1493 resp[1] = ToU8(LibXR::USB::DapLinkV2Def::Port::DISABLED);
1494 }
1495
1496 out_len = 2u;
1497 return ErrorCode::OK;
1498 }
1499
1500 ErrorCode HandleDisconnect(bool /*in_isr*/, const uint8_t* /*req*/,
1501 uint16_t /*req_len*/, uint8_t* resp, uint16_t resp_cap,
1502 uint16_t& out_len)
1503 {
1504 if (resp_cap < 2u)
1505 {
1506 out_len = 0;
1507 return ErrorCode::NOT_FOUND;
1508 }
1509
1510 swd_.Close();
1511 if constexpr (JTAG_ENABLED)
1512 {
1513 if (jtag_ != nullptr)
1514 {
1515 jtag_->Close();
1516 }
1517 }
1518 dap_state_.debug_port = LibXR::USB::DapLinkV2Def::DebugPort::DISABLED;
1519 dap_state_.transfer_abort = false;
1520 ResetQueuedCommandState();
1521
1522 resp[0] = ToU8(LibXR::USB::DapLinkV2Def::CommandId::DISCONNECT);
1523 resp[1] = ToU8(LibXR::USB::DapLinkV2Def::Status::OK);
1524 out_len = 2u;
1525 return ErrorCode::OK;
1526 }
1527
1528 ErrorCode HandleTransferConfigure(bool /*in_isr*/, const uint8_t* req, uint16_t req_len,
1529 uint8_t* resp, uint16_t resp_cap, uint16_t& out_len)
1530 {
1531 if (resp_cap < 2u)
1532 {
1533 out_len = 0;
1534 return ErrorCode::NOT_FOUND;
1535 }
1536
1537 resp[0] = ToU8(LibXR::USB::DapLinkV2Def::CommandId::TRANSFER_CONFIGURE);
1538
1539 // Req: [0]=0x04 [1]=idle_cycles [2..3]=wait_retry [4..5]=match_retry
1540 if (req_len < 6u)
1541 {
1542 resp[1] = ToU8(LibXR::USB::DapLinkV2Def::Status::ERROR);
1543 out_len = 2u;
1544 return ErrorCode::ARG_ERR;
1545 }
1546
1547 const uint8_t IDLE = req[1];
1548
1549 uint16_t wait_retry = 0u;
1550 uint16_t match_retry = 0u;
1551 Memory::FastCopy(&wait_retry, &req[2], sizeof(wait_retry));
1552 Memory::FastCopy(&match_retry, &req[4], sizeof(match_retry));
1553
1555 dap_state_.transfer_cfg.retry_count = wait_retry;
1556 dap_state_.transfer_cfg.match_retry = match_retry;
1557
1558 // Map to SWD transaction policy
1559 Debug::Swd::TransferPolicy pol = swd_.GetTransferPolicy();
1560 pol.idle_cycles = IDLE;
1561 pol.wait_retry = wait_retry;
1562 swd_.SetTransferPolicy(pol);
1563
1564 resp[1] = ToU8(LibXR::USB::DapLinkV2Def::Status::OK);
1565 out_len = 2u;
1566 return ErrorCode::OK;
1567 }
1568
1569 ErrorCode HandleTransferAbort(bool /*in_isr*/, const uint8_t* /*req*/,
1570 uint16_t /*req_len*/, uint8_t* resp, uint16_t resp_cap,
1571 uint16_t& out_len)
1572 {
1573 if (resp_cap < 2u)
1574 {
1575 out_len = 0;
1576 return ErrorCode::NOT_FOUND;
1577 }
1578
1579 SetTransferAbortFlag(true);
1580
1581 resp[0] = ToU8(LibXR::USB::DapLinkV2Def::CommandId::TRANSFER_ABORT);
1582 resp[1] = ToU8(LibXR::USB::DapLinkV2Def::Status::OK);
1583 out_len = 2u;
1584 return ErrorCode::OK;
1585 }
1586
1587 ErrorCode HandleWriteABORT(bool in_isr, const uint8_t* req, uint16_t req_len,
1588 uint8_t* resp, uint16_t resp_cap, uint16_t& out_len)
1589 {
1590 if (resp_cap < 2u)
1591 {
1592 out_len = 0;
1593 return ErrorCode::NOT_FOUND;
1594 }
1595
1596 if constexpr (JTAG_ENABLED)
1597 {
1598 if (dap_state_.debug_port == LibXR::USB::DapLinkV2Def::DebugPort::JTAG)
1599 {
1600 return HandleJtagWriteAbort(in_isr, req, req_len, resp, resp_cap, out_len);
1601 }
1602 }
1603
1604 resp[0] = ToU8(LibXR::USB::DapLinkV2Def::CommandId::WRITE_ABORT);
1605
1606 if (req_len < 6u)
1607 {
1608 resp[1] = ToU8(LibXR::USB::DapLinkV2Def::Status::ERROR);
1609 out_len = 2u;
1610 return ErrorCode::ARG_ERR;
1611 }
1612
1613 uint32_t flags = 0u;
1614 Memory::FastCopy(&flags, &req[2], sizeof(flags));
1615
1616 LibXR::Debug::SwdProtocol::Ack ack = LibXR::Debug::SwdProtocol::Ack::PROTOCOL;
1617
1618 const ErrorCode EC = swd_.WriteAbortTxn(flags, ack);
1619 resp[1] = (EC == ErrorCode::OK && ack == LibXR::Debug::SwdProtocol::Ack::OK)
1620 ? ToU8(LibXR::USB::DapLinkV2Def::Status::OK)
1621 : ToU8(LibXR::USB::DapLinkV2Def::Status::ERROR);
1622
1623 out_len = 2u;
1624 return ErrorCode::OK;
1625 }
1626
1627 ErrorCode HandleDelay(bool /*in_isr*/, const uint8_t* req, uint16_t req_len,
1628 uint8_t* resp, uint16_t resp_cap, uint16_t& out_len)
1629 {
1630 if (resp_cap < 2u)
1631 {
1632 out_len = 0;
1633 return ErrorCode::NOT_FOUND;
1634 }
1635
1636 resp[0] = ToU8(LibXR::USB::DapLinkV2Def::CommandId::DELAY);
1637
1638 if (req_len < 3u)
1639 {
1640 resp[1] = ToU8(LibXR::USB::DapLinkV2Def::Status::ERROR);
1641 out_len = 2u;
1642 return ErrorCode::ARG_ERR;
1643 }
1644
1645 uint16_t us = 0u;
1646 Memory::FastCopy(&us, &req[1], sizeof(us));
1647
1649
1650 resp[1] = ToU8(LibXR::USB::DapLinkV2Def::Status::OK);
1651 out_len = 2u;
1652 return ErrorCode::OK;
1653 }
1654
1655 ErrorCode HandleResetTarget(bool in_isr, const uint8_t* /*req*/, uint16_t /*req_len*/,
1656 uint8_t* resp, uint16_t resp_cap, uint16_t& out_len)
1657 {
1658 if (!resp || resp_cap < 3u)
1659 {
1660 out_len = 0u;
1661 return ErrorCode::NOT_FOUND;
1662 }
1663
1664 resp[0] = ToU8(LibXR::USB::DapLinkV2Def::CommandId::RESET_TARGET);
1665
1666 uint8_t execute = 0u;
1667
1668 if (nreset_gpio_ != nullptr)
1669 {
1670 DriveReset(false);
1671 DelayUsIfAllowed(in_isr, 1000u);
1672 DriveReset(true);
1673 DelayUsIfAllowed(in_isr, 1000u);
1674 execute = 1u;
1675 }
1676
1677 // Always return DAP_OK; if reset is not implemented, Execute=0.
1678 resp[1] = DAP_OK;
1679 resp[2] = execute;
1680 out_len = 3u;
1681 return ErrorCode::OK;
1682 }
1683
1684 private:
1685 // ============================================================================
1686 // SWJ / SWD handlers
1687 // ============================================================================
1688 ErrorCode HandleSWJPins(bool /*in_isr*/, const uint8_t* req, uint16_t req_len,
1689 uint8_t* resp, uint16_t resp_cap, uint16_t& out_len)
1690 {
1691 if (!resp || resp_cap < 2u)
1692 {
1693 out_len = 0u;
1694 return ErrorCode::NOT_FOUND;
1695 }
1696
1697 resp[0] = ToU8(LibXR::USB::DapLinkV2Def::CommandId::SWJ_PINS);
1698
1699 // Req: [0]=0x10 [1]=PinOut [2]=PinSelect [3..6]=PinWait(us)
1700 if (!req || req_len < 7u)
1701 {
1702 resp[1] = 0u;
1703 out_len = 2u;
1704 return ErrorCode::ARG_ERR;
1705 }
1706
1707 const uint8_t PIN_OUT = req[1];
1708 const uint8_t PIN_SEL = req[2];
1709
1710 uint32_t wait_us = 0u;
1711 Memory::FastCopy(&wait_us, &req[3], sizeof(wait_us));
1712
1713 // 0) Latch requested states into shadow for ALL selected pins (even if unsupported)
1714 swj_shadow_ = static_cast<uint8_t>((swj_shadow_ & static_cast<uint8_t>(~PIN_SEL)) |
1715 (PIN_OUT & PIN_SEL));
1716
1717 // 1) Only physically support nRESET (best-effort)
1718 if ((PIN_SEL & LibXR::USB::DapLinkV2Def::DAP_SWJ_NRESET) != 0u)
1719 {
1720 const bool LEVEL_HIGH =
1721 ((PIN_OUT & LibXR::USB::DapLinkV2Def::DAP_SWJ_NRESET) != 0u);
1722 // DriveReset updates last_nreset_level_high_ and shadow, and writes GPIO if
1723 // present.
1724 DriveReset(LEVEL_HIGH);
1725 }
1726
1727 // Read helper: start from shadow; override nRESET with physical level if wired.
1728 auto read_pins = [&]() -> uint8_t
1729 {
1730 uint8_t pin_in = swj_shadow_;
1731
1732 if (nreset_gpio_ != nullptr)
1733 {
1734 if (nreset_gpio_->Read())
1735 {
1736 pin_in |= LibXR::USB::DapLinkV2Def::DAP_SWJ_NRESET;
1737 }
1738 else
1739 {
1740 pin_in = static_cast<uint8_t>(
1741 pin_in & static_cast<uint8_t>(~LibXR::USB::DapLinkV2Def::DAP_SWJ_NRESET));
1742 }
1743 }
1744
1745 return pin_in;
1746 };
1747
1748 // 2) PinWait: wait until (PinInput & PinSelect) matches (PinOut & PinSelect), or
1749 // timeout. Since SWCLK/SWDIO are shadow-only now, their selected bits will already
1750 // match immediately.
1751 uint8_t pin_in = 0u;
1752
1753 if (wait_us == 0u || PIN_SEL == 0u)
1754 {
1755 pin_in = read_pins();
1756 }
1757 else
1758 {
1759 const uint64_t START = LibXR::Timebase::GetMicroseconds();
1760 const uint8_t EXPECT = static_cast<uint8_t>(PIN_OUT & PIN_SEL);
1761
1762 do
1763 {
1764 pin_in = read_pins();
1765 if ((pin_in & PIN_SEL) == EXPECT)
1766 {
1767 break;
1768 }
1769 } while ((static_cast<uint64_t>(LibXR::Timebase::GetMicroseconds()) - START) <
1770 wait_us);
1771 }
1772
1773 resp[1] = pin_in;
1774 out_len = 2u;
1775 return ErrorCode::OK;
1776 }
1777
1778 ErrorCode HandleSWJClock(bool /*in_isr*/, const uint8_t* req, uint16_t req_len,
1779 uint8_t* resp, uint16_t resp_cap, uint16_t& out_len)
1780 {
1781 if (resp_cap < 2u)
1782 {
1783 out_len = 0;
1784 return ErrorCode::NOT_FOUND;
1785 }
1786
1787 resp[0] = ToU8(LibXR::USB::DapLinkV2Def::CommandId::SWJ_CLOCK);
1788
1789 if (req_len < 5u)
1790 {
1791 resp[1] = ToU8(LibXR::USB::DapLinkV2Def::Status::ERROR);
1792 out_len = 2u;
1793 return ErrorCode::ARG_ERR;
1794 }
1795
1796 uint32_t hz = 0u;
1797 Memory::FastCopy(&hz, &req[1], sizeof(hz));
1798
1799 swj_clock_hz_ = hz;
1800 (void)swd_.SetClockHz(hz);
1801 if constexpr (JTAG_ENABLED)
1802 {
1803 if (jtag_ != nullptr)
1804 {
1805 (void)jtag_->SetClockHz(hz);
1806 }
1807 }
1808
1809 resp[1] = ToU8(LibXR::USB::DapLinkV2Def::Status::OK);
1810 out_len = 2u;
1811 return ErrorCode::OK;
1812 }
1813
1814 ErrorCode HandleSWJSequence(bool /*in_isr*/, const uint8_t* req, uint16_t req_len,
1815 uint8_t* resp, uint16_t resp_cap, uint16_t& out_len)
1816 {
1817 if (!resp || resp_cap < 2u)
1818 {
1819 out_len = 0u;
1820 return ErrorCode::NOT_FOUND;
1821 }
1822
1823 resp[0] = ToU8(LibXR::USB::DapLinkV2Def::CommandId::SWJ_SEQUENCE);
1824 resp[1] = ToU8(LibXR::USB::DapLinkV2Def::Status::OK);
1825 out_len = 2u;
1826
1827 // Req: [0]=0x12 [1]=bit_count(0=>256) [2..]=data (LSB-first)
1828 if (!req || req_len < 2u)
1829 {
1830 resp[1] = ToU8(LibXR::USB::DapLinkV2Def::Status::ERROR);
1831 return ErrorCode::ARG_ERR;
1832 }
1833
1834 const uint8_t RAW_COUNT = req[1];
1835 const uint32_t BIT_COUNT =
1836 (RAW_COUNT == 0u) ? 256u : static_cast<uint32_t>(RAW_COUNT);
1837 const uint32_t BYTE_COUNT = (BIT_COUNT + 7u) / 8u;
1838
1839 if (2u + BYTE_COUNT > req_len)
1840 {
1841 resp[1] = ToU8(LibXR::USB::DapLinkV2Def::Status::ERROR);
1842 return ErrorCode::ARG_ERR;
1843 }
1844
1845 const uint8_t* data = &req[2];
1846
1847 // Delegate to SwdPort implementation (no RawMode / no pin-level control here)
1848 const ErrorCode EC = swd_.SeqWriteBits(BIT_COUNT, data);
1849 if (EC != ErrorCode::OK)
1850 {
1851 resp[1] = ToU8(LibXR::USB::DapLinkV2Def::Status::ERROR);
1852 // Keep transport-level OK so host still gets a valid response.
1853 return ErrorCode::OK;
1854 }
1855
1856 // Maintain shadow semantics: keep SWCLK=0, SWDIO=last bit
1857 swj_shadow_ = static_cast<uint8_t>(
1858 swj_shadow_ & static_cast<uint8_t>(~LibXR::USB::DapLinkV2Def::DAP_SWJ_SWCLK_TCK));
1859
1860 bool last_swdio = false;
1861 if (BIT_COUNT != 0u)
1862 {
1863 const uint32_t LAST_I = BIT_COUNT - 1u;
1864 last_swdio = (((data[LAST_I / 8u] >> (LAST_I & 7u)) & 0x01u) != 0u);
1865 }
1866
1867 if (last_swdio)
1868 {
1869 swj_shadow_ |= LibXR::USB::DapLinkV2Def::DAP_SWJ_SWDIO_TMS;
1870 }
1871 else
1872 {
1873 swj_shadow_ = static_cast<uint8_t>(
1874 swj_shadow_ &
1875 static_cast<uint8_t>(~LibXR::USB::DapLinkV2Def::DAP_SWJ_SWDIO_TMS));
1876 }
1877
1878 return ErrorCode::OK;
1879 }
1880
1881 ErrorCode HandleSWDConfigure(bool /*in_isr*/, const uint8_t* req, uint16_t req_len,
1882 uint8_t* resp, uint16_t resp_cap, uint16_t& out_len)
1883 {
1884 if (resp_cap < 2u)
1885 {
1886 out_len = 0;
1887 return ErrorCode::NOT_FOUND;
1888 }
1889
1890 resp[0] = ToU8(LibXR::USB::DapLinkV2Def::CommandId::SWD_CONFIGURE);
1891
1892 if (req == nullptr || req_len < 2u)
1893 {
1894 resp[1] = ToU8(LibXR::USB::DapLinkV2Def::Status::ERROR);
1895 out_len = 2u;
1896 return ErrorCode::ARG_ERR;
1897 }
1898
1899 const uint8_t cfg = req[1];
1900 dap_state_.swd_cfg.turnaround = static_cast<uint8_t>((cfg & 0x03u) + 1u);
1901 dap_state_.swd_cfg.data_phase = ((cfg & 0x04u) != 0u);
1902
1903 resp[1] = ToU8(LibXR::USB::DapLinkV2Def::Status::OK);
1904 out_len = 2u;
1905 return ErrorCode::OK;
1906 }
1907
1908 ErrorCode HandleSWDSequence(bool /*in_isr*/, const uint8_t* req, uint16_t req_len,
1909 uint8_t* resp, uint16_t resp_cap, uint16_t& out_len)
1910 {
1911 if (!req || !resp || resp_cap < 2u)
1912 {
1913 out_len = 0u;
1914 return ErrorCode::ARG_ERR;
1915 }
1916
1917 resp[0] = ToU8(LibXR::USB::DapLinkV2Def::CommandId::SWD_SEQUENCE);
1918 resp[1] = DAP_OK;
1919 out_len = 2u;
1920
1921 // Req: [0]=0x1D [1]=SequenceCount [ ... sequences ... ]
1922 // Each sequence:
1923 // INFO: [7]=Direction (1=input,0=output), [5:0]=cycles (0=>64)
1924 // If output: followed by ceil(cycles/8) bytes data (LSB-first)
1925 // If input : no data in request; response appends ceil(cycles/8) bytes data
1926 // (LSB-first)
1927 if (req_len < 2u)
1928 {
1929 resp[1] = DAP_ERROR;
1930 out_len = 2u;
1931 return ErrorCode::ARG_ERR;
1932 }
1933
1934 const uint8_t SEQ_CNT = req[1];
1935 uint16_t req_off = 2u;
1936 uint16_t resp_off = 2u;
1937
1938 for (uint32_t s = 0; s < SEQ_CNT; ++s)
1939 {
1940 if (req_off >= req_len)
1941 {
1942 resp[1] = DAP_ERROR;
1943 out_len = 2u;
1944 return ErrorCode::ARG_ERR;
1945 }
1946
1947 const uint8_t INFO = req[req_off++];
1948
1949 uint32_t cycles = static_cast<uint32_t>(INFO & 0x3Fu);
1950 if (cycles == 0u)
1951 {
1952 cycles = 64u;
1953 }
1954
1955 const bool MODE_IN = ((INFO & 0x80u) != 0u);
1956 const uint16_t BYTES = static_cast<uint16_t>((cycles + 7u) / 8u);
1957
1958 if (!MODE_IN)
1959 {
1960 // Output: data bytes are in request
1961 if (req_off + BYTES > req_len)
1962 {
1963 resp[1] = DAP_ERROR;
1964 out_len = 2u;
1965 return ErrorCode::ARG_ERR;
1966 }
1967
1968 const uint8_t* data = &req[req_off];
1969 req_off = static_cast<uint16_t>(req_off + BYTES);
1970
1971 const ErrorCode EC = swd_.SeqWriteBits(cycles, data);
1972 if (EC != ErrorCode::OK)
1973 {
1974 resp[1] = DAP_ERROR;
1975 out_len = 2u;
1976 // Return OK so host gets a valid response packet
1977 return ErrorCode::OK;
1978 }
1979 }
1980 else
1981 {
1982 // Input: captured data is appended to response
1983 if (resp_off + BYTES > resp_cap)
1984 {
1985 resp[1] = DAP_ERROR;
1986 out_len = 2u;
1987 return ErrorCode::NOT_FOUND;
1988 }
1989
1990 Memory::FastSet(&resp[resp_off], 0, BYTES);
1991
1992 const ErrorCode EC = swd_.SeqReadBits(cycles, &resp[resp_off]);
1993 if (EC != ErrorCode::OK)
1994 {
1995 resp[1] = DAP_ERROR;
1996 out_len = 2u;
1997 return ErrorCode::OK;
1998 }
1999
2000 resp_off = static_cast<uint16_t>(resp_off + BYTES);
2001 }
2002 }
2003
2004 out_len = resp_off;
2005 return ErrorCode::OK;
2006 }
2007
2008 ErrorCode HandleJTAGSequence(bool /*in_isr*/, const uint8_t* req, uint16_t req_len,
2009 uint8_t* resp, uint16_t resp_cap, uint16_t& out_len)
2010 {
2011 if (!req || !resp || resp_cap < 2u)
2012 {
2013 out_len = 0u;
2014 return ErrorCode::ARG_ERR;
2015 }
2016
2017 resp[0] = ToU8(LibXR::USB::DapLinkV2Def::CommandId::JTAG_SEQUENCE);
2018 resp[1] = DAP_OK;
2019 out_len = 2u;
2020
2021 if (jtag_ == nullptr)
2022 {
2023 resp[1] = DAP_ERROR;
2024 return ErrorCode::OK;
2025 }
2026
2027 if (req_len < 2u)
2028 {
2029 resp[1] = DAP_ERROR;
2030 return ErrorCode::ARG_ERR;
2031 }
2032
2033 const uint8_t SEQ_CNT = req[1];
2034 uint16_t req_off = 2u;
2035 uint16_t resp_off = 2u;
2036
2037 for (uint32_t s = 0; s < SEQ_CNT; ++s)
2038 {
2039 if (req_off >= req_len)
2040 {
2041 resp[1] = DAP_ERROR;
2042 out_len = 2u;
2043 return ErrorCode::ARG_ERR;
2044 }
2045
2046 const uint8_t INFO = req[req_off++];
2047 uint32_t cycles = static_cast<uint32_t>(INFO & 0x3Fu);
2048 if (cycles == 0u)
2049 {
2050 cycles = 64u;
2051 }
2052
2053 const bool TMS = ((INFO & LibXR::Debug::JtagProtocol::JTAG_SEQUENCE_TMS) != 0u);
2054 const bool CAPTURE = ((INFO & LibXR::Debug::JtagProtocol::JTAG_SEQUENCE_TDO) != 0u);
2055 const uint16_t BYTES = static_cast<uint16_t>((cycles + 7u) / 8u);
2056
2057 if (req_off + BYTES > req_len)
2058 {
2059 resp[1] = DAP_ERROR;
2060 out_len = 2u;
2061 return ErrorCode::ARG_ERR;
2062 }
2063 if (CAPTURE && (resp_off + BYTES > resp_cap))
2064 {
2065 resp[1] = DAP_ERROR;
2066 out_len = 2u;
2067 return ErrorCode::NOT_FOUND;
2068 }
2069
2070 const uint8_t* data = &req[req_off];
2071 uint8_t* out = CAPTURE ? &resp[resp_off] : nullptr;
2072 if (CAPTURE)
2073 {
2074 Memory::FastSet(out, 0, BYTES);
2075 }
2076
2077 const ErrorCode ec = jtag_->Sequence(cycles, TMS, data, out);
2078 if (ec != ErrorCode::OK)
2079 {
2080 resp[1] = DAP_ERROR;
2081 out_len = 2u;
2082 return ErrorCode::OK;
2083 }
2084
2085 req_off = static_cast<uint16_t>(req_off + BYTES);
2086 if (CAPTURE)
2087 {
2088 resp_off = static_cast<uint16_t>(resp_off + BYTES);
2089 }
2090 }
2091
2092 out_len = resp_off;
2093 return ErrorCode::OK;
2094 }
2095
2096 ErrorCode HandleJTAGConfigure(bool /*in_isr*/, const uint8_t* req, uint16_t req_len,
2097 uint8_t* resp, uint16_t resp_cap, uint16_t& out_len)
2098 {
2099 if (!req || !resp || resp_cap < 2u)
2100 {
2101 out_len = 0u;
2102 return ErrorCode::ARG_ERR;
2103 }
2104
2105 resp[0] = ToU8(LibXR::USB::DapLinkV2Def::CommandId::JTAG_CONFIGURE);
2106 resp[1] = DAP_OK;
2107 out_len = 2u;
2108
2109 if (jtag_ == nullptr)
2110 {
2111 resp[1] = DAP_ERROR;
2112 return ErrorCode::OK;
2113 }
2114
2115 if (req_len < 2u)
2116 {
2117 resp[1] = DAP_ERROR;
2118 return ErrorCode::ARG_ERR;
2119 }
2120
2121 const uint8_t count = req[1];
2122 if (count > JTAG_MAX_DEVICES || req_len < static_cast<uint16_t>(2u + count))
2123 {
2124 resp[1] = DAP_ERROR;
2125 return ErrorCode::ARG_ERR;
2126 }
2127
2129
2130 uint32_t bits = 0u;
2131 for (uint32_t i = 0; i < count; ++i)
2132 {
2133 const uint8_t len = req[static_cast<uint16_t>(2u + i)];
2134 jtag_ir_len_[i] = len;
2135 bits += len;
2136 }
2137
2138 jtag_chain_.count = count;
2140 {
2141 jtag_chain_.index = 0u;
2142 }
2147 return ErrorCode::OK;
2148 }
2149
2150 ErrorCode HandleJTAGIdCode(bool /*in_isr*/, const uint8_t* req, uint16_t req_len,
2151 uint8_t* resp, uint16_t resp_cap, uint16_t& out_len)
2152 {
2153 if (!req || !resp || resp_cap < 6u)
2154 {
2155 out_len = 0u;
2156 return ErrorCode::ARG_ERR;
2157 }
2158
2159 resp[0] = ToU8(LibXR::USB::DapLinkV2Def::CommandId::JTAG_IDCODE);
2160 resp[1] = DAP_ERROR;
2161 out_len = 2u;
2162
2163 if (jtag_ == nullptr ||
2164 dap_state_.debug_port != LibXR::USB::DapLinkV2Def::DebugPort::JTAG)
2165 {
2166 return ErrorCode::OK;
2167 }
2168
2169 if (req_len < 2u)
2170 {
2171 return ErrorCode::ARG_ERR;
2172 }
2173
2174 const uint8_t index = req[1];
2175 if (index >= jtag_chain_.count)
2176 {
2177 return ErrorCode::OK;
2178 }
2179
2180 jtag_chain_.index = index;
2181 LibXR::Debug::JtagProtocol::UpdateChainCache(jtag_chain_);
2182
2184 uint32_t idcode = 0u;
2185 ErrorCode ec = dp.ReadIdCode(idcode);
2186 if (ec == ErrorCode::OK &&
2187 (idcode == 0u || idcode == 0xFFFF'FFFFu || ((idcode & 0x1u) == 0u)) &&
2188 jtag_ir_len_[index] != 4u)
2189 {
2190 uint32_t fallback_idcode = 0u;
2191 ec = dp.ReadIdCodeWithIr(0x01u, fallback_idcode);
2192 if (ec != ErrorCode::OK)
2193 {
2194 return ec;
2195 }
2196 if (fallback_idcode != 0u && fallback_idcode != 0xFFFF'FFFFu &&
2197 ((fallback_idcode & 0x1u) != 0u))
2198 {
2199 idcode = fallback_idcode;
2200 }
2201 }
2202 if (ec != ErrorCode::OK)
2203 {
2204 return ec;
2205 }
2206
2207 resp[1] = DAP_OK;
2208 Memory::FastCopy(&resp[2], &idcode, sizeof(idcode));
2209 out_len = 6u;
2210 return ErrorCode::OK;
2211 }
2212
2216 ErrorCode HandleQueueCommands(bool /*in_isr*/, const uint8_t* req, uint16_t req_len,
2217 uint8_t* resp, uint16_t resp_cap, uint16_t& out_len)
2218 {
2219 if (!req || req_len < 2u)
2220 {
2221 return BuildCmdStatusResponse(
2222 ToU8(LibXR::USB::DapLinkV2Def::CommandId::QUEUE_COMMANDS), DAP_ERROR, resp,
2223 resp_cap, out_len);
2224 }
2225
2226 const uint8_t NUM = req[1];
2227 if (NUM == 0u)
2228 {
2229 return BuildCmdStatusResponse(
2230 ToU8(LibXR::USB::DapLinkV2Def::CommandId::QUEUE_COMMANDS), DAP_OK, resp,
2231 resp_cap, out_len);
2232 }
2233
2234 uint16_t req_off = 2u;
2235 for (uint32_t i = 0u; i < NUM; ++i)
2236 {
2237 if (req_off >= req_len)
2238 {
2239 return BuildCmdStatusResponse(
2240 ToU8(LibXR::USB::DapLinkV2Def::CommandId::QUEUE_COMMANDS), DAP_ERROR, resp,
2241 resp_cap, out_len);
2242 }
2243
2244 uint16_t cmd_len = 0u;
2245 if (!ParseQueuedCommandLength(&req[req_off],
2246 static_cast<uint16_t>(req_len - req_off), cmd_len) ||
2247 cmd_len == 0u)
2248 {
2249 return BuildCmdStatusResponse(
2250 ToU8(LibXR::USB::DapLinkV2Def::CommandId::QUEUE_COMMANDS), DAP_ERROR, resp,
2251 resp_cap, out_len);
2252 }
2253 req_off = static_cast<uint16_t>(req_off + cmd_len);
2254 }
2255
2256 if (req_off != req_len)
2257 {
2258 return BuildCmdStatusResponse(
2259 ToU8(LibXR::USB::DapLinkV2Def::CommandId::QUEUE_COMMANDS), DAP_ERROR, resp,
2260 resp_cap, out_len);
2261 }
2262
2263 if (static_cast<uint32_t>(queued_request_length_) +
2264 static_cast<uint32_t>(req_len - 2u) >
2265 static_cast<uint32_t>(QUEUED_REQ_BUFFER_SIZE) ||
2266 static_cast<uint32_t>(queued_command_count_) + static_cast<uint32_t>(NUM) >
2267 static_cast<uint32_t>(QUEUED_CMD_COUNT_MAX))
2268 {
2269 return BuildCmdStatusResponse(
2270 ToU8(LibXR::USB::DapLinkV2Def::CommandId::QUEUE_COMMANDS), DAP_ERROR, resp,
2271 resp_cap, out_len);
2272 }
2273
2274 Memory::FastCopy(&queued_request_buffer_[queued_request_length_], &req[2],
2275 req_len - 2u);
2276 queued_request_length_ =
2277 static_cast<uint16_t>(queued_request_length_ + (req_len - 2u));
2278 queued_command_count_ = static_cast<uint16_t>(queued_command_count_ + NUM);
2279
2280 return BuildCmdStatusResponse(
2281 ToU8(LibXR::USB::DapLinkV2Def::CommandId::QUEUE_COMMANDS), DAP_OK, resp, resp_cap,
2282 out_len);
2283 }
2284
2288 ErrorCode HandleExecuteCommands(bool in_isr, const uint8_t* /*req*/,
2289 uint16_t /*req_len*/, uint8_t* resp, uint16_t resp_cap,
2290 uint16_t& out_len)
2291 {
2292 const bool ok = TryExecuteQueuedCommandStream(in_isr, resp, resp_cap, out_len);
2293 ResetQueuedCommandState();
2294
2295 if (!ok)
2296 {
2297 return BuildCmdStatusResponse(
2298 ToU8(LibXR::USB::DapLinkV2Def::CommandId::EXECUTE_COMMANDS), DAP_ERROR, resp,
2299 resp_cap, out_len);
2300 }
2301
2302 return ErrorCode::OK;
2303 }
2304
2305 private:
2306 // ============================================================================
2307 // Transfer helpers
2308 // ============================================================================
2309
2310 uint8_t MapAckToDapResp(LibXR::Debug::SwdProtocol::Ack ack) const
2311 {
2312 static constexpr uint8_t ACK_MAP[8] = {7u, 1u, 2u, 7u, 4u, 7u, 7u, 7u};
2313 return ACK_MAP[static_cast<uint8_t>(ack) & 0x07u];
2314 }
2315
2316 uint8_t MapAckToDapResp(LibXR::Debug::JtagProtocol::Ack ack) const
2317 {
2318 switch (ack)
2319 {
2320 case LibXR::Debug::JtagProtocol::Ack::OK:
2321 return 1u;
2322 case LibXR::Debug::JtagProtocol::Ack::WAIT:
2323 return 2u;
2324 case LibXR::Debug::JtagProtocol::Ack::FAULT:
2325 return 4u;
2326 case LibXR::Debug::JtagProtocol::Ack::NO_ACK:
2327 case LibXR::Debug::JtagProtocol::Ack::PROTOCOL:
2328 default:
2329 return 7u;
2330 }
2331 }
2332
2333 static inline uint16_t LoadU16Le(const uint8_t* p)
2334 {
2335 return static_cast<uint16_t>(
2336 static_cast<uint16_t>(p[0]) |
2337 static_cast<uint16_t>(static_cast<uint16_t>(p[1]) << 8u));
2338 }
2339
2340 static inline void StoreU16Le(uint8_t* p, uint16_t v)
2341 {
2342 p[0] = static_cast<uint8_t>(v & 0xFFu);
2343 p[1] = static_cast<uint8_t>((v >> 8u) & 0xFFu);
2344 }
2345
2346 static inline uint32_t LoadU32Le(const uint8_t* p)
2347 {
2348 return static_cast<uint32_t>(
2349 static_cast<uint32_t>(p[0]) | (static_cast<uint32_t>(p[1]) << 8u) |
2350 (static_cast<uint32_t>(p[2]) << 16u) | (static_cast<uint32_t>(p[3]) << 24u));
2351 }
2352
2353 static inline void StoreU32Le(uint8_t* p, uint32_t v)
2354 {
2355 p[0] = static_cast<uint8_t>(v & 0xFFu);
2356 p[1] = static_cast<uint8_t>((v >> 8u) & 0xFFu);
2357 p[2] = static_cast<uint8_t>((v >> 16u) & 0xFFu);
2358 p[3] = static_cast<uint8_t>((v >> 24u) & 0xFFu);
2359 }
2360
2361 ErrorCode TransferTxnFast(const LibXR::Debug::SwdProtocol::Request& req,
2363 {
2364 const ErrorCode EC0 = swd_.Transfer(req, resp);
2365 if (EC0 != ErrorCode::OK)
2366 {
2367 return EC0;
2368 }
2369
2370 if (resp.ack == LibXR::Debug::SwdProtocol::Ack::WAIT)
2371 {
2372 return swd_.TransferWithRetry(req, resp);
2373 }
2374
2375 if (resp.ack == LibXR::Debug::SwdProtocol::Ack::FAULT)
2376 {
2377 const auto POL = swd_.GetTransferPolicy();
2378 if (POL.clear_sticky_on_fault)
2379 {
2380 LibXR::Debug::SwdProtocol::Ack abort_ack =
2381 LibXR::Debug::SwdProtocol::Ack::PROTOCOL;
2382 (void)swd_.WriteAbort(LibXR::Debug::SwdProtocol::DP_ABORT_STKCMPCLR |
2383 LibXR::Debug::SwdProtocol::DP_ABORT_STKERRCLR |
2384 LibXR::Debug::SwdProtocol::DP_ABORT_WDERRCLR |
2385 LibXR::Debug::SwdProtocol::DP_ABORT_ORUNERRCLR,
2386 abort_ack);
2387 }
2388 }
2389
2390 return ErrorCode::OK;
2391 }
2392
2393 ErrorCode DpReadRdbuffFast(uint32_t& val, LibXR::Debug::SwdProtocol::Ack& ack_out)
2394 {
2396 const auto req = LibXR::Debug::SwdProtocol::make_dp_read_req(
2397 LibXR::Debug::SwdProtocol::DpReadReg::RDBUFF);
2398 const ErrorCode ec = TransferTxnFast(req, swd_resp);
2399 ack_out = swd_resp.ack;
2400 if (ec != ErrorCode::OK)
2401 {
2402 return ec;
2403 }
2404 if (swd_resp.ack != LibXR::Debug::SwdProtocol::Ack::OK || !swd_resp.parity_ok)
2405 {
2406 return ErrorCode::FAILED;
2407 }
2408 val = swd_resp.rdata;
2409 return ErrorCode::OK;
2410 }
2411
2412 ErrorCode CompletePendingApReadFast(uint32_t& val,
2413 LibXR::Debug::SwdProtocol::Ack& ack_out)
2414 {
2415 return DpReadRdbuffFast(val, ack_out);
2416 }
2417
2418 ErrorCode CheckPostedApWriteFast(LibXR::Debug::SwdProtocol::Ack& ack_out)
2419 {
2421 const auto req = LibXR::Debug::SwdProtocol::make_dp_read_req(
2422 LibXR::Debug::SwdProtocol::DpReadReg::CTRL_STAT);
2423 const ErrorCode ec = TransferTxnFast(req, swd_resp);
2424 ack_out = swd_resp.ack;
2425 if (ec != ErrorCode::OK)
2426 {
2427 return ec;
2428 }
2429 if (swd_resp.ack != LibXR::Debug::SwdProtocol::Ack::OK || !swd_resp.parity_ok)
2430 {
2431 return ErrorCode::FAILED;
2432 }
2433 return ErrorCode::OK;
2434 }
2435
2436 ErrorCode ApReadPostedFast(uint8_t addr2b, uint32_t& posted,
2437 LibXR::Debug::SwdProtocol::Ack& ack_out)
2438 {
2440 const auto req = LibXR::Debug::SwdProtocol::make_ap_read_req(addr2b);
2441 const ErrorCode ec = TransferTxnFast(req, swd_resp);
2442 ack_out = swd_resp.ack;
2443 if (ec != ErrorCode::OK)
2444 {
2445 return ec;
2446 }
2447 if (swd_resp.ack != LibXR::Debug::SwdProtocol::Ack::OK || !swd_resp.parity_ok)
2448 {
2449 return ErrorCode::FAILED;
2450 }
2451 posted = swd_resp.rdata;
2452 return ErrorCode::OK;
2453 }
2454
2455 void SetTransferAbortFlag(bool on) { dap_state_.transfer_abort = on; }
2456
2457 private:
2458 // ============================================================================
2459 // DAP_Transfer / DAP_TransferBlock
2460 // ============================================================================
2461
2462 // The following long functions are kept as-is; API docs live at the header boundary.
2463
2464 ErrorCode HandleTransfer(bool in_isr, const uint8_t* req, uint16_t req_len,
2465 uint8_t* resp, uint16_t resp_cap, uint16_t& out_len)
2466 {
2467 out_len = 0u;
2468 if (!req || !resp || resp_cap < 3u)
2469 {
2470 return ErrorCode::ARG_ERR;
2471 }
2472
2473 if constexpr (JTAG_ENABLED)
2474 {
2475 if (dap_state_.debug_port == LibXR::USB::DapLinkV2Def::DebugPort::JTAG)
2476 {
2477 return HandleJtagTransfer(in_isr, req, req_len, resp, resp_cap, out_len);
2478 }
2479 }
2480
2481 resp[0] = ToU8(LibXR::USB::DapLinkV2Def::CommandId::TRANSFER);
2482 resp[1] = 0u; // response_count = #successful transfers
2483 resp[2] = 0u; // response_value (ACK bits / ERROR / MISMATCH)
2484 uint16_t resp_off = 3u;
2485
2486 // Req: [0]=CMD [1]=DAP index [2]=count [3..]=transfers...
2487 if (req_len < 3u)
2488 {
2489 resp[2] = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
2490 out_len = 3u;
2491 return ErrorCode::ARG_ERR;
2492 }
2493
2495 {
2496 dap_state_.transfer_abort = false;
2497 resp[2] = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
2498 out_len = 3u;
2499 return ErrorCode::OK;
2500 }
2501
2502 const uint8_t COUNT = req[2];
2503 uint16_t req_off = 3u;
2504
2505 auto push_u32 = [&](uint32_t v) -> bool
2506 {
2507 if (resp_off + 4u > resp_cap)
2508 {
2509 return false;
2510 }
2511 Memory::FastCopy(&resp[resp_off], &v, sizeof(v));
2512 resp_off = static_cast<uint16_t>(resp_off + 4u);
2513 return true;
2514 };
2515
2516 auto push_timestamp = [&]() -> bool
2517 {
2518 const uint32_t T = static_cast<uint32_t>(LibXR::Timebase::GetMicroseconds());
2519 return push_u32(T);
2520 };
2521
2522 auto ensure_space = [&](uint16_t bytes) -> bool
2523 { return (resp_off + bytes) <= resp_cap; };
2524
2525 auto bytes_for_read = [&](bool need_ts) -> uint16_t
2526 { return static_cast<uint16_t>(need_ts ? 8u : 4u); };
2527
2528 uint8_t response_count = 0u;
2529 // Keep reference behavior: if no transfer executes, response_value remains 0.
2530 uint8_t response_value = 0u;
2531
2532 // AP writes are posted by the target. Keep the write batch fast and check
2533 // it once at a transfer boundary with DP CTRL/STAT, not DP RDBUFF.
2534 bool pending_ap_write = false;
2535
2536 // -------- posted-read pipeline state (AP read only) --------
2537 struct PendingApRead
2538 {
2539 bool valid = false;
2540 bool need_ts = false; // Whether this AP read transfer needs timestamp.
2541 } pending;
2542
2543 auto emit_read_with_ts = [&](bool need_ts, uint32_t data) -> bool
2544 {
2545 if (need_ts)
2546 {
2547 if (!push_timestamp())
2548 {
2549 return false;
2550 }
2551 }
2552 if (!push_u32(data))
2553 {
2554 return false;
2555 }
2556 response_count++;
2557 return true;
2558 };
2559
2560 // Complete a pending AP read by DP RDBUFF.
2561 // RDBUFF is the AP read-result pipe outlet, not the AP-write checker.
2562 auto complete_pending_ap_read = [&]() -> bool
2563 {
2564 if (!pending.valid)
2565 {
2566 return true;
2567 }
2568
2569 if (!ensure_space(bytes_for_read(pending.need_ts)))
2570 {
2571 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
2572 return false;
2573 }
2574
2575 uint32_t rdata = 0u;
2576 LibXR::Debug::SwdProtocol::Ack ack = LibXR::Debug::SwdProtocol::Ack::PROTOCOL;
2577 const ErrorCode EC = CompletePendingApReadFast(rdata, ack);
2578
2579 const uint8_t V = MapAckToDapResp(ack);
2580 if (V != LibXR::USB::DapLinkV2Def::DAP_TRANSFER_OK)
2581 {
2582 response_value = V;
2583 return false;
2584 }
2585 if (EC != ErrorCode::OK)
2586 {
2587 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
2588 return false;
2589 }
2590
2591 if (!emit_read_with_ts(pending.need_ts, rdata))
2592 {
2593 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
2594 return false;
2595 }
2596
2597 pending.valid = false;
2598 pending.need_ts = false;
2599
2600 // Successful path keeps OK.
2601 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_OK;
2602 return true;
2603 };
2604
2605 auto check_posted_ap_write_if_pending = [&]() -> bool
2606 {
2607 if (!pending_ap_write)
2608 {
2609 return true;
2610 }
2611 LibXR::Debug::SwdProtocol::Ack check_ack = LibXR::Debug::SwdProtocol::Ack::PROTOCOL;
2612 const ErrorCode check_ec = CheckPostedApWriteFast(check_ack);
2613 response_value = MapAckToDapResp(check_ack);
2614 if (response_value != LibXR::USB::DapLinkV2Def::DAP_TRANSFER_OK)
2615 {
2616 return false;
2617 }
2618 if (check_ec != ErrorCode::OK)
2619 {
2620 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
2621 return false;
2622 }
2623 pending_ap_write = false;
2624 return true;
2625 };
2626
2627 // Complete pending AP read before non-AP operations to keep response order.
2628 auto complete_pending_ap_read_if_any = [&]() -> bool
2629 { return pending.valid ? complete_pending_ap_read() : true; };
2630
2631 auto close_posted_state = [&]() -> bool
2632 { return complete_pending_ap_read_if_any() && check_posted_ap_write_if_pending(); };
2633
2634 // -------- main loop --------
2635 for (uint32_t i = 0; i < COUNT; ++i)
2636 {
2637 if (req_off >= req_len)
2638 {
2639 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
2640 break;
2641 }
2642
2643 const uint8_t RQ = req[req_off++];
2644
2645 const bool AP = LibXR::USB::DapLinkV2Def::req_is_ap(RQ);
2646 const bool RNW = LibXR::USB::DapLinkV2Def::req_is_read(RQ);
2647 const uint8_t ADDR2B = LibXR::USB::DapLinkV2Def::req_addr2b(RQ);
2648
2650 const bool MATCH_VALUE =
2651 ((RQ & LibXR::USB::DapLinkV2Def::DAP_TRANSFER_MATCH_VALUE) != 0u);
2652 const bool MATCH_MASK =
2653 ((RQ & LibXR::USB::DapLinkV2Def::DAP_TRANSFER_MATCH_MASK) != 0u);
2654
2655 // Spec rule: timestamp cannot be combined with match bits.
2656 if (TS && (MATCH_VALUE || MATCH_MASK))
2657 {
2658 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
2659 break;
2660 }
2661
2662 LibXR::Debug::SwdProtocol::Ack ack = LibXR::Debug::SwdProtocol::Ack::PROTOCOL;
2664
2665 if (!RNW)
2666 {
2667 // ---------------- WRITE ----------------
2668 // A write can follow previous AP writes without forcing a recovery.
2669 // Only close an AP-read pipeline before consuming write data.
2670 if (!complete_pending_ap_read_if_any())
2671 {
2672 break;
2673 }
2674
2675 if (req_off + 4u > req_len)
2676 {
2677 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
2678 break;
2679 }
2680
2681 uint32_t wdata = LoadU32Le(&req[req_off]);
2682 req_off = static_cast<uint16_t>(req_off + 4u);
2683
2684 if (MATCH_MASK)
2685 {
2686 match_mask_ = wdata;
2687 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_OK;
2688 response_count++; // MATCH_MASK counts as a successful transfer.
2689 continue;
2690 }
2691 if (AP)
2692 {
2693 ec = swd_.ApWriteTxn(ADDR2B, wdata, ack);
2694 }
2695 else
2696 {
2697 ec = swd_.DpWriteTxn(static_cast<LibXR::Debug::SwdProtocol::DpWriteReg>(ADDR2B),
2698 wdata, ack);
2699 }
2700
2701 response_value = MapAckToDapResp(ack);
2702 if (response_value != LibXR::USB::DapLinkV2Def::DAP_TRANSFER_OK)
2703 {
2704 break;
2705 }
2706 if (ec != ErrorCode::OK)
2707 {
2708 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
2709 break;
2710 }
2711
2712 if (AP)
2713 {
2714 pending_ap_write = true;
2715 }
2716
2717 if (TS)
2718 {
2719 if (!push_timestamp())
2720 {
2721 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
2722 break;
2723 }
2724 }
2725
2726 response_count++;
2727 }
2728 else
2729 {
2730 // ---------------- READ ----------------
2731
2732 if (MATCH_VALUE)
2733 {
2734 // MATCH_VALUE performs real reads and can observe earlier AP writes,
2735 // so close both posted read and posted AP-write state first.
2736 if (!close_posted_state())
2737 {
2738 break;
2739 }
2740
2741 if (req_off + 4u > req_len)
2742 {
2743 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
2744 break;
2745 }
2746
2747 uint32_t match_val = LoadU32Le(&req[req_off]);
2748 req_off = static_cast<uint16_t>(req_off + 4u);
2749
2750 uint32_t rdata = 0u;
2751 uint32_t retry = dap_state_.transfer_cfg.match_retry;
2752 bool matched = false;
2753
2754 while (true)
2755 {
2756 if (AP)
2757 {
2758 ec = swd_.ApReadTxn(ADDR2B, rdata, ack); // Includes RDBUFF.
2759 if (ec == ErrorCode::OK && ack == LibXR::Debug::SwdProtocol::Ack::OK)
2760 {
2761 // ApReadTxn completes the AP read pipeline only.
2762 }
2763 }
2764 else
2765 {
2766 ec = swd_.DpReadTxn(
2767 static_cast<LibXR::Debug::SwdProtocol::DpReadReg>(ADDR2B), rdata, ack);
2768 }
2769
2770 response_value = MapAckToDapResp(ack);
2771 if (response_value != LibXR::USB::DapLinkV2Def::DAP_TRANSFER_OK)
2772 {
2773 break;
2774 }
2775 if (ec != ErrorCode::OK)
2776 {
2777 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
2778 break;
2779 }
2780
2781 if ((rdata & match_mask_) == (match_val & match_mask_))
2782 {
2783 matched = true;
2784 break;
2785 }
2786
2787 if (retry == 0u)
2788 {
2789 break;
2790 }
2791 --retry;
2792 }
2793
2794 if (response_value != LibXR::USB::DapLinkV2Def::DAP_TRANSFER_OK)
2795 {
2796 break;
2797 }
2798
2799 if (!matched)
2800 {
2801 response_value =
2802 static_cast<uint8_t>(LibXR::USB::DapLinkV2Def::DAP_TRANSFER_OK |
2803 LibXR::USB::DapLinkV2Def::DAP_TRANSFER_MISMATCH);
2804 // MISMATCH does not increase response_count.
2805 break;
2806 }
2807
2808 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_OK;
2809 response_count++;
2810 continue;
2811 }
2812
2813 // ---- Normal read ----
2814 if (!AP)
2815 {
2816 // DP read does not participate in posted pipelines.
2817 if (!close_posted_state())
2818 {
2819 break;
2820 }
2821
2822 uint32_t rdata = 0u;
2823 ec = swd_.DpReadTxn(static_cast<LibXR::Debug::SwdProtocol::DpReadReg>(ADDR2B),
2824 rdata, ack);
2825
2826 response_value = MapAckToDapResp(ack);
2827 if (response_value != LibXR::USB::DapLinkV2Def::DAP_TRANSFER_OK)
2828 {
2829 break;
2830 }
2831 if (ec != ErrorCode::OK)
2832 {
2833 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
2834 break;
2835 }
2836
2837 if (!ensure_space(bytes_for_read(TS)))
2838 {
2839 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
2840 break;
2841 }
2842
2843 if (!emit_read_with_ts(TS, rdata))
2844 {
2845 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
2846 break;
2847 }
2848
2849 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_OK;
2850 continue;
2851 }
2852
2853 // AP reads can observe previous AP writes, so close posted writes
2854 // before starting or extending the posted-read pipeline.
2855 if (!check_posted_ap_write_if_pending())
2856 {
2857 break;
2858 }
2859
2860 // AP normal read: posted-read pipeline.
2861 if (!pending.valid)
2862 {
2863 // First AP read in this contiguous AP-read segment:
2864 // start one posted AP read and discard returned posted data.
2865 uint32_t dummy_posted = 0u;
2866 ec = ApReadPostedFast(ADDR2B, dummy_posted, ack);
2867
2868 response_value = MapAckToDapResp(ack);
2869 if (response_value != LibXR::USB::DapLinkV2Def::DAP_TRANSFER_OK)
2870 {
2871 break;
2872 }
2873 if (ec != ErrorCode::OK)
2874 {
2875 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
2876 {
2877 break;
2878 }
2879 }
2880
2881 pending.valid = true;
2882 pending.need_ts = TS;
2883
2884 // Transfer is not "complete" yet.
2885 // Data will be produced by next AP read or tail RDBUFF.
2886 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_OK;
2887 }
2888 else
2889 {
2890 // Pending exists: current AP read returns posted data
2891 // from the previous AP read.
2892 if (!ensure_space(bytes_for_read(pending.need_ts)))
2893 {
2894 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
2895 break;
2896 }
2897
2898 uint32_t posted_prev = 0u;
2899 ec = ApReadPostedFast(ADDR2B, posted_prev, ack);
2900
2901 const uint8_t CUR_V = MapAckToDapResp(ack);
2902 if (CUR_V != LibXR::USB::DapLinkV2Def::DAP_TRANSFER_OK || ec != ErrorCode::OK)
2903 {
2904 // Current AP read failed: try best effort to complete pending AP read.
2905 // Otherwise, response_count may miss one and pipeline may remain dirty.
2906 const uint8_t PROOR_FAIL =
2907 (CUR_V != LibXR::USB::DapLinkV2Def::DAP_TRANSFER_OK)
2908 ? CUR_V
2909 : LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
2910
2911 if (!complete_pending_ap_read())
2912 {
2913 // Pending itself failed: return earlier failure
2914 // (complete_pending_ap_read already wrote response_value).
2915 break;
2916 }
2917
2918 // Pending completion succeeded: keep current failure.
2919 response_value = PROOR_FAIL;
2920 break;
2921 }
2922
2923 // Current AP read succeeded: emit pending first (using posted_prev),
2924 // then mark current read as new pending.
2925 if (!emit_read_with_ts(pending.need_ts, posted_prev))
2926 {
2927 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
2928 break;
2929 }
2930
2931 pending.valid = true;
2932 pending.need_ts = TS;
2933
2934 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_OK;
2935 }
2936 }
2937
2939 {
2940 dap_state_.transfer_abort = false;
2941 break;
2942 }
2943 }
2944
2945 // If pending AP read still exists at tail:
2946 // - when response_value == OK: normal tail by one RDBUFF;
2947 // - when response_value != OK: try pending completion first; if completion
2948 // succeeds, keep original failure; otherwise use pending failure.
2949 if (pending.valid)
2950 {
2951 const uint8_t PRIOR_FAIL = response_value;
2952
2953 if (!complete_pending_ap_read())
2954 {
2955 // Pending failure wins here (response_value already written).
2956 }
2957 else
2958 {
2959 // Pending completion succeeded: keep original failure
2960 // (if original was OK, keep OK).
2961 if (PRIOR_FAIL != 0u && PRIOR_FAIL != LibXR::USB::DapLinkV2Def::DAP_TRANSFER_OK)
2962 {
2963 response_value = PRIOR_FAIL;
2964 }
2965 }
2966 }
2967
2968 if (response_value == LibXR::USB::DapLinkV2Def::DAP_TRANSFER_OK &&
2969 !check_posted_ap_write_if_pending())
2970 {
2971 // response_value is already set by the recovery helper.
2972 }
2973 resp[1] = response_count;
2974 resp[2] = response_value;
2975 out_len = resp_off;
2976 return ErrorCode::OK;
2977 }
2978 ErrorCode HandleTransferBlock(bool in_isr, const uint8_t* req, uint16_t req_len,
2979 uint8_t* resp, uint16_t resp_cap, uint16_t& out_len)
2980 {
2981 if constexpr (JTAG_ENABLED)
2982 {
2983 if (dap_state_.debug_port == LibXR::USB::DapLinkV2Def::DebugPort::JTAG)
2984 {
2985 return HandleJtagTransferBlock(in_isr, req, req_len, resp, resp_cap, out_len);
2986 }
2987 }
2988
2989 // Req: [0]=0x06 [1]=index [2..3]=count [4]=request [5..]=data(write)
2990 // Resp: [0]=0x06 [1..2]=done [3]=resp [4..]=data(read)
2991 if (!resp || resp_cap < 4u)
2992 {
2993 out_len = 0u;
2994 return ErrorCode::NOT_FOUND;
2995 }
2996
2997 resp[0] = ToU8(LibXR::USB::DapLinkV2Def::CommandId::TRANSFER_BLOCK);
2998 resp[1] = 0u;
2999 resp[2] = 0u;
3000 resp[3] = 0u;
3001 out_len = 4u;
3002
3003 if (!req || req_len < 5u)
3004 {
3005 resp[3] = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
3006 return ErrorCode::ARG_ERR;
3007 }
3008
3010 {
3011 dap_state_.transfer_abort = false;
3012 resp[3] = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
3013 return ErrorCode::OK;
3014 }
3015
3016 uint16_t count = 0u;
3017 count = LoadU16Le(&req[2]);
3018
3019 const uint8_t DAP_RQ = req[4];
3020
3021 // TransferBlock does not support match or timestamp
3022 if ((DAP_RQ & (LibXR::USB::DapLinkV2Def::DAP_TRANSFER_MATCH_VALUE |
3023 LibXR::USB::DapLinkV2Def::DAP_TRANSFER_MATCH_MASK)) != 0u)
3024 {
3025 resp[3] = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
3027 }
3029 {
3030 resp[3] = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
3032 }
3033
3034 // Count==0: return OK
3035 if (count == 0u)
3036 {
3037 const uint16_t DONE0 = 0u;
3038 StoreU16Le(&resp[1], DONE0);
3039 resp[3] = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_OK;
3040 out_len = 4u;
3041 return ErrorCode::OK;
3042 }
3043
3044 const bool AP = LibXR::USB::DapLinkV2Def::req_is_ap(DAP_RQ);
3045 const bool RNW = LibXR::USB::DapLinkV2Def::req_is_read(DAP_RQ);
3046 const uint8_t ADDR2B = LibXR::USB::DapLinkV2Def::req_addr2b(DAP_RQ);
3047
3048 uint16_t done = 0u;
3049 uint8_t xresp = 0u;
3050
3051 uint16_t req_off = 5u;
3052 uint16_t resp_off = 4u;
3053
3054 // WRITE path: keep original behavior
3055 if (!RNW)
3056 {
3057 const uint32_t REQ_NEED =
3058 static_cast<uint32_t>(req_off) + (static_cast<uint32_t>(count) * 4u);
3059 if (REQ_NEED > req_len)
3060 {
3061 xresp |= LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
3062 StoreU16Le(&resp[1], done);
3063 resp[3] = xresp;
3064 out_len = resp_off;
3065 return ErrorCode::OK;
3066 }
3067 if (AP)
3068 {
3069 auto swd_req = LibXR::Debug::SwdProtocol::make_ap_write_req(ADDR2B, 0u);
3071 for (uint32_t i = 0; i < count; ++i)
3072 {
3073 uint32_t wdata = LoadU32Le(&req[req_off]);
3074 req_off = static_cast<uint16_t>(req_off + 4u);
3075 swd_req.wdata = wdata;
3076 const ErrorCode ec = TransferTxnFast(swd_req, swd_resp);
3077 xresp = MapAckToDapResp(swd_resp.ack);
3078 if (swd_resp.ack != LibXR::Debug::SwdProtocol::Ack::OK)
3079 {
3080 break;
3081 }
3082 if (ec != ErrorCode::OK)
3083 {
3084 xresp |= LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
3085 break;
3086 }
3087 done = static_cast<uint16_t>(i + 1u);
3088 }
3089 if (xresp == LibXR::USB::DapLinkV2Def::DAP_TRANSFER_OK && done != 0u)
3090 {
3091 LibXR::Debug::SwdProtocol::Ack check_ack =
3092 LibXR::Debug::SwdProtocol::Ack::PROTOCOL;
3093 const ErrorCode check_ec = CheckPostedApWriteFast(check_ack);
3094 xresp = MapAckToDapResp(check_ack);
3095 if (check_ack == LibXR::Debug::SwdProtocol::Ack::OK &&
3096 check_ec != ErrorCode::OK)
3097 {
3098 xresp |= LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
3099 }
3100 }
3101 }
3102 else
3103 {
3104 for (uint32_t i = 0; i < count; ++i)
3105 {
3106 LibXR::Debug::SwdProtocol::Ack ack = LibXR::Debug::SwdProtocol::Ack::PROTOCOL;
3108 uint32_t wdata = LoadU32Le(&req[req_off]);
3109 req_off = static_cast<uint16_t>(req_off + 4u);
3110 ec = swd_.DpWriteTxn(static_cast<LibXR::Debug::SwdProtocol::DpWriteReg>(ADDR2B),
3111 wdata, ack);
3112 xresp = MapAckToDapResp(ack);
3113 if (ack != LibXR::Debug::SwdProtocol::Ack::OK)
3114 {
3115 break;
3116 }
3117 if (ec != ErrorCode::OK)
3118 {
3119 xresp |= LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
3120 break;
3121 }
3122 done = static_cast<uint16_t>(i + 1u);
3123 }
3124 }
3125 StoreU16Le(&resp[1], done);
3126 resp[3] = xresp;
3127 out_len = resp_off;
3128 return ErrorCode::OK;
3129 }
3130
3131 // READ path
3132 if (!AP)
3133 {
3134 const uint32_t RESP_NEED =
3135 static_cast<uint32_t>(resp_off) + (static_cast<uint32_t>(count) * 4u);
3136 if (RESP_NEED > resp_cap)
3137 {
3138 xresp |= LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
3139 StoreU16Le(&resp[1], done);
3140 resp[3] = xresp;
3141 out_len = resp_off;
3142 return ErrorCode::OK;
3143 }
3144
3145 // DP read: keep original behavior
3146 for (uint32_t i = 0; i < count; ++i)
3147 {
3148 LibXR::Debug::SwdProtocol::Ack ack = LibXR::Debug::SwdProtocol::Ack::PROTOCOL;
3150 uint32_t rdata = 0u;
3151 ec = swd_.DpReadTxn(static_cast<LibXR::Debug::SwdProtocol::DpReadReg>(ADDR2B),
3152 rdata, ack);
3153 xresp = MapAckToDapResp(ack);
3154 if (ack != LibXR::Debug::SwdProtocol::Ack::OK)
3155 {
3156 break;
3157 }
3158 if (ec != ErrorCode::OK)
3159 {
3160 xresp |= LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
3161 break;
3162 }
3163 StoreU32Le(&resp[resp_off], rdata);
3164 resp_off = static_cast<uint16_t>(resp_off + 4u);
3165 done = static_cast<uint16_t>(i + 1u);
3166 }
3167 StoreU16Le(&resp[1], done);
3168 resp[3] = xresp;
3169 out_len = resp_off;
3170 return ErrorCode::OK;
3171 }
3172
3173 // AP read: posted-read pipeline
3174 {
3175 const uint32_t RESP_NEED =
3176 static_cast<uint32_t>(resp_off) + (static_cast<uint32_t>(count) * 4u);
3177 if (RESP_NEED > resp_cap)
3178 {
3179 xresp |= LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
3180 StoreU16Le(&resp[1], done);
3181 resp[3] = xresp;
3182 out_len = resp_off;
3183 return ErrorCode::OK;
3184 }
3185
3186 auto ap_read_req = LibXR::Debug::SwdProtocol::make_ap_read_req(ADDR2B);
3187 LibXR::Debug::SwdProtocol::Response ap_read_resp = {};
3188 ErrorCode ec = TransferTxnFast(ap_read_req, ap_read_resp);
3189 xresp = MapAckToDapResp(ap_read_resp.ack);
3190 if (ap_read_resp.ack != LibXR::Debug::SwdProtocol::Ack::OK)
3191 {
3192 goto out_ap_read; // NOLINT
3193 }
3194 if (ec != ErrorCode::OK || !ap_read_resp.parity_ok)
3195 {
3196 xresp |= LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
3197 goto out_ap_read; // NOLINT
3198 }
3199
3200 // i=1..COUNT-1: each AP read returns previous posted data.
3201 for (uint32_t i = 1; i < count; ++i)
3202 {
3203 ec = TransferTxnFast(ap_read_req, ap_read_resp);
3204 const uint8_t CUR = MapAckToDapResp(ap_read_resp.ack);
3205
3206 if (ap_read_resp.ack != LibXR::Debug::SwdProtocol::Ack::OK ||
3207 ec != ErrorCode::OK || !ap_read_resp.parity_ok)
3208 {
3209 // Current AP read failed; try to complete the previous AP read result.
3210 if (resp_off + 4u <= resp_cap)
3211 {
3212 uint32_t rdbuff_data = 0u;
3213 LibXR::Debug::SwdProtocol::Ack rdbuff_ack =
3214 LibXR::Debug::SwdProtocol::Ack::PROTOCOL;
3215 const ErrorCode ec2 = CompletePendingApReadFast(rdbuff_data, rdbuff_ack);
3216 const uint8_t v2 = MapAckToDapResp(rdbuff_ack);
3217
3218 if (v2 == LibXR::USB::DapLinkV2Def::DAP_TRANSFER_OK && ec2 == ErrorCode::OK)
3219 {
3220 StoreU32Le(&resp[resp_off], rdbuff_data);
3221 resp_off = static_cast<uint16_t>(resp_off + 4u);
3222 done = static_cast<uint16_t>(i); // done includes transfer [0..i-1]
3223 }
3224 else
3225 {
3226 xresp = v2;
3227 if (ec2 != ErrorCode::OK)
3228 {
3229 xresp |= LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
3230 }
3231 goto out_ap_read; // NOLINT
3232 }
3233 }
3234
3235 xresp = CUR;
3236 if (ec != ErrorCode::OK)
3237 {
3238 xresp |= LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
3239 }
3240 goto out_ap_read; // NOLINT
3241 }
3242
3243 StoreU32Le(&resp[resp_off], ap_read_resp.rdata);
3244 resp_off = static_cast<uint16_t>(resp_off + 4u);
3245 done = static_cast<uint16_t>(i); // completed [0..i-1]
3246 xresp = CUR;
3247 }
3248
3249 // Complete the final posted AP read by DP RDBUFF.
3250 {
3251 uint32_t rdbuff_data = 0u;
3252 LibXR::Debug::SwdProtocol::Ack rdbuff_ack =
3253 LibXR::Debug::SwdProtocol::Ack::PROTOCOL;
3254 const ErrorCode ec2 = CompletePendingApReadFast(rdbuff_data, rdbuff_ack);
3255 const uint8_t v2 = MapAckToDapResp(rdbuff_ack);
3256
3257 xresp = v2;
3258 if (v2 != LibXR::USB::DapLinkV2Def::DAP_TRANSFER_OK)
3259 {
3260 goto out_ap_read; // NOLINT
3261 }
3262 if (ec2 != ErrorCode::OK)
3263 {
3264 xresp |= LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
3265 goto out_ap_read; // NOLINT
3266 }
3267
3268 StoreU32Le(&resp[resp_off], rdbuff_data);
3269 resp_off = static_cast<uint16_t>(resp_off + 4u);
3270 done = count;
3271 }
3272
3273 out_ap_read:
3274 StoreU16Le(&resp[1], done);
3275 resp[3] = xresp;
3276 out_len = resp_off;
3277 return ErrorCode::OK;
3278 }
3279 }
3280
3281 ErrorCode HandleJtagTransfer(bool /*in_isr*/, const uint8_t* req, uint16_t req_len,
3282 uint8_t* resp, uint16_t resp_cap, uint16_t& out_len)
3283 {
3284 out_len = 0u;
3285 if (!req || !resp || resp_cap < 3u)
3286 {
3287 return ErrorCode::ARG_ERR;
3288 }
3289
3290 resp[0] = ToU8(LibXR::USB::DapLinkV2Def::CommandId::TRANSFER);
3291 resp[1] = 0u;
3292 resp[2] = 0u;
3293 uint16_t resp_off = 3u;
3294
3295 if (req_len < 3u || jtag_ == nullptr || jtag_chain_.count == 0u)
3296 {
3297 resp[2] = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
3298 out_len = 3u;
3299 return ErrorCode::OK;
3300 }
3301
3303 {
3304 dap_state_.transfer_abort = false;
3305 resp[2] = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
3306 out_len = 3u;
3307 return ErrorCode::OK;
3308 }
3309
3310 const uint8_t TAP_INDEX = req[1];
3311 if (TAP_INDEX >= jtag_chain_.count)
3312 {
3313 resp[2] = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
3314 out_len = 3u;
3315 return ErrorCode::OK;
3316 }
3317
3318 jtag_chain_.index = TAP_INDEX;
3319 LibXR::Debug::JtagProtocol::UpdateChainCache(jtag_chain_);
3321
3322 const uint8_t COUNT = req[2];
3323 uint16_t req_off = 3u;
3324
3325 auto push_u32 = [&](uint32_t v) -> bool
3326 {
3327 if (resp_off + 4u > resp_cap)
3328 {
3329 return false;
3330 }
3331 Memory::FastCopy(&resp[resp_off], &v, sizeof(v));
3332 resp_off = static_cast<uint16_t>(resp_off + 4u);
3333 return true;
3334 };
3335
3336 auto push_timestamp = [&]() -> bool
3337 {
3338 const uint32_t t = static_cast<uint32_t>(LibXR::Timebase::GetMicroseconds());
3339 return push_u32(t);
3340 };
3341
3342 auto ensure_space = [&](uint16_t bytes) -> bool
3343 { return (resp_off + bytes) <= resp_cap; };
3344
3345 auto bytes_for_read = [&](bool need_ts) -> uint16_t
3346 { return static_cast<uint16_t>(need_ts ? 8u : 4u); };
3347
3348 auto idle_after_attempt = [&]()
3349 {
3351 {
3353 }
3354 };
3355
3356 auto dp_read_retry = [&](uint8_t addr2b, uint32_t& val,
3357 LibXR::Debug::JtagProtocol::Ack& ack) -> ErrorCode
3358 {
3359 uint32_t retry = dap_state_.transfer_cfg.retry_count;
3360 while (true)
3361 {
3362 const ErrorCode ec = dp.DpReadTxn(addr2b, val, ack);
3363 idle_after_attempt();
3364 if (ack != LibXR::Debug::JtagProtocol::Ack::WAIT || retry == 0u ||
3366 {
3367 return ec;
3368 }
3369 --retry;
3370 }
3371 };
3372
3373 auto dp_write_retry = [&](uint8_t addr2b, uint32_t val,
3374 LibXR::Debug::JtagProtocol::Ack& ack) -> ErrorCode
3375 {
3376 uint32_t retry = dap_state_.transfer_cfg.retry_count;
3377 while (true)
3378 {
3379 const ErrorCode ec = dp.DpWriteTxn(addr2b, val, ack);
3380 idle_after_attempt();
3381 if (ack != LibXR::Debug::JtagProtocol::Ack::WAIT || retry == 0u ||
3383 {
3384 return ec;
3385 }
3386 --retry;
3387 }
3388 };
3389
3390 auto ap_read_retry = [&](uint8_t addr2b, uint32_t& val,
3391 LibXR::Debug::JtagProtocol::Ack& ack) -> ErrorCode
3392 {
3393 uint32_t retry = dap_state_.transfer_cfg.retry_count;
3394 while (true)
3395 {
3396 const ErrorCode ec = dp.ApReadTxn(addr2b, val, ack);
3397 idle_after_attempt();
3398 if (ack != LibXR::Debug::JtagProtocol::Ack::WAIT || retry == 0u ||
3400 {
3401 return ec;
3402 }
3403 --retry;
3404 }
3405 };
3406
3407 auto ap_write_retry = [&](uint8_t addr2b, uint32_t val,
3408 LibXR::Debug::JtagProtocol::Ack& ack) -> ErrorCode
3409 {
3410 uint32_t retry = dap_state_.transfer_cfg.retry_count;
3411 while (true)
3412 {
3413 const ErrorCode ec = dp.ApWriteTxn(addr2b, val, ack);
3414 idle_after_attempt();
3415 if (ack != LibXR::Debug::JtagProtocol::Ack::WAIT || retry == 0u ||
3417 {
3418 return ec;
3419 }
3420 --retry;
3421 }
3422 };
3423
3424 auto check_posted_ap_write_jtag =
3425 [&](LibXR::Debug::JtagProtocol::Ack& ack) -> ErrorCode
3426 {
3427 uint32_t ctrl_stat = 0u;
3428 return dp_read_retry(
3429 static_cast<uint8_t>(LibXR::Debug::SwdProtocol::DpReadReg::CTRL_STAT),
3430 ctrl_stat, ack);
3431 };
3432
3433 uint8_t response_count = 0u;
3434 uint8_t response_value = 0u;
3435 bool pending_ap_write = false;
3436
3437 auto emit_read_with_ts = [&](bool need_ts, uint32_t data) -> bool
3438 {
3439 if (need_ts)
3440 {
3441 if (!push_timestamp())
3442 {
3443 return false;
3444 }
3445 }
3446 if (!push_u32(data))
3447 {
3448 return false;
3449 }
3450 response_count++;
3451 return true;
3452 };
3453
3454 auto check_posted_ap_write_if_pending = [&]() -> bool
3455 {
3456 if (!pending_ap_write)
3457 {
3458 return true;
3459 }
3460
3461 LibXR::Debug::JtagProtocol::Ack ack = LibXR::Debug::JtagProtocol::Ack::PROTOCOL;
3462 const ErrorCode ec = check_posted_ap_write_jtag(ack);
3463 const uint8_t v = MapAckToDapResp(ack);
3464
3465 if (v != LibXR::USB::DapLinkV2Def::DAP_TRANSFER_OK)
3466 {
3467 response_value = v;
3468 return false;
3469 }
3470 if (ec != ErrorCode::OK)
3471 {
3472 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
3473 return false;
3474 }
3475
3476 pending_ap_write = false;
3477 return true;
3478 };
3479
3480 auto should_check_pending_ap_write_at_tail = [&]() -> bool
3481 {
3482 return response_value == LibXR::USB::DapLinkV2Def::DAP_TRANSFER_OK ||
3483 response_value ==
3484 static_cast<uint8_t>(LibXR::USB::DapLinkV2Def::DAP_TRANSFER_OK |
3485 LibXR::USB::DapLinkV2Def::DAP_TRANSFER_MISMATCH);
3486 };
3487
3488 for (uint32_t i = 0; i < COUNT; ++i)
3489 {
3490 if (req_off >= req_len)
3491 {
3492 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
3493 break;
3494 }
3495
3496 const uint8_t RQ = req[req_off++];
3497 const bool AP = LibXR::USB::DapLinkV2Def::req_is_ap(RQ);
3498 const bool RNW = LibXR::USB::DapLinkV2Def::req_is_read(RQ);
3499 const uint8_t ADDR2B = LibXR::USB::DapLinkV2Def::req_addr2b(RQ);
3501 const bool MATCH_VALUE =
3502 ((RQ & LibXR::USB::DapLinkV2Def::DAP_TRANSFER_MATCH_VALUE) != 0u);
3503 const bool MATCH_MASK =
3504 ((RQ & LibXR::USB::DapLinkV2Def::DAP_TRANSFER_MATCH_MASK) != 0u);
3505
3506 if (TS && (MATCH_VALUE || MATCH_MASK))
3507 {
3508 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
3509 break;
3510 }
3511
3512 LibXR::Debug::JtagProtocol::Ack ack = LibXR::Debug::JtagProtocol::Ack::PROTOCOL;
3514
3515 if (!RNW)
3516 {
3517 if (req_off + 4u > req_len)
3518 {
3519 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
3520 break;
3521 }
3522
3523 uint32_t wdata = 0u;
3524 Memory::FastCopy(&wdata, &req[req_off], sizeof(wdata));
3525 req_off = static_cast<uint16_t>(req_off + 4u);
3526
3527 if (MATCH_MASK)
3528 {
3529 match_mask_ = wdata;
3530 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_OK;
3531 response_count++;
3532 continue;
3533 }
3534
3535 if (AP)
3536 {
3537 ec = ap_write_retry(ADDR2B, wdata, ack);
3538 }
3539 else
3540 {
3541 ec = dp_write_retry(ADDR2B, wdata, ack);
3542 }
3543
3544 response_value = MapAckToDapResp(ack);
3545 if (response_value != LibXR::USB::DapLinkV2Def::DAP_TRANSFER_OK)
3546 {
3547 break;
3548 }
3549 if (ec != ErrorCode::OK)
3550 {
3551 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
3552 break;
3553 }
3554
3555 if (TS)
3556 {
3557 if (!push_timestamp())
3558 {
3559 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
3560 break;
3561 }
3562 }
3563
3564 response_count++;
3565 if (AP)
3566 {
3567 pending_ap_write = true;
3568 }
3569 }
3570 else
3571 {
3572 if (MATCH_VALUE)
3573 {
3574 if (!check_posted_ap_write_if_pending())
3575 {
3576 break;
3577 }
3578
3579 if (req_off + 4u > req_len)
3580 {
3581 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
3582 break;
3583 }
3584
3585 uint32_t match_val = 0u;
3586 Memory::FastCopy(&match_val, &req[req_off], sizeof(match_val));
3587 req_off = static_cast<uint16_t>(req_off + 4u);
3588
3589 uint32_t rdata = 0u;
3590 uint32_t retry = dap_state_.transfer_cfg.match_retry;
3591 bool matched = false;
3592
3593 while (true)
3594 {
3595 if (AP)
3596 {
3597 ec = ap_read_retry(ADDR2B, rdata, ack);
3598 }
3599 else
3600 {
3601 ec = dp_read_retry(ADDR2B, rdata, ack);
3602 }
3603
3604 response_value = MapAckToDapResp(ack);
3605 if (response_value != LibXR::USB::DapLinkV2Def::DAP_TRANSFER_OK)
3606 {
3607 break;
3608 }
3609 if (ec != ErrorCode::OK)
3610 {
3611 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
3612 break;
3613 }
3614
3615 if ((rdata & match_mask_) == (match_val & match_mask_))
3616 {
3617 matched = true;
3618 break;
3619 }
3620
3621 if (retry == 0u)
3622 {
3623 break;
3624 }
3625 --retry;
3626 }
3627
3628 if (response_value != LibXR::USB::DapLinkV2Def::DAP_TRANSFER_OK)
3629 {
3630 break;
3631 }
3632
3633 if (!matched)
3634 {
3635 response_value =
3636 static_cast<uint8_t>(LibXR::USB::DapLinkV2Def::DAP_TRANSFER_OK |
3637 LibXR::USB::DapLinkV2Def::DAP_TRANSFER_MISMATCH);
3638 break;
3639 }
3640
3641 response_count++;
3642 continue;
3643 }
3644
3645 if (!AP)
3646 {
3647 if (!check_posted_ap_write_if_pending())
3648 {
3649 break;
3650 }
3651
3652 uint32_t rdata = 0u;
3653 ec = dp_read_retry(ADDR2B, rdata, ack);
3654
3655 response_value = MapAckToDapResp(ack);
3656 if (response_value != LibXR::USB::DapLinkV2Def::DAP_TRANSFER_OK)
3657 {
3658 break;
3659 }
3660 if (ec != ErrorCode::OK)
3661 {
3662 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
3663 break;
3664 }
3665
3666 if (!ensure_space(bytes_for_read(TS)))
3667 {
3668 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
3669 break;
3670 }
3671
3672 if (!emit_read_with_ts(TS, rdata))
3673 {
3674 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
3675 break;
3676 }
3677
3678 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_OK;
3679 continue;
3680 }
3681
3682 uint32_t rdata = 0u;
3683 if (!check_posted_ap_write_if_pending())
3684 {
3685 break;
3686 }
3687
3688 ec = ap_read_retry(ADDR2B, rdata, ack);
3689
3690 response_value = MapAckToDapResp(ack);
3691 if (response_value != LibXR::USB::DapLinkV2Def::DAP_TRANSFER_OK)
3692 {
3693 break;
3694 }
3695 if (ec != ErrorCode::OK)
3696 {
3697 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
3698 break;
3699 }
3700
3701 if (!ensure_space(bytes_for_read(TS)))
3702 {
3703 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
3704 break;
3705 }
3706
3707 if (!emit_read_with_ts(TS, rdata))
3708 {
3709 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
3710 break;
3711 }
3712
3713 response_value = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_OK;
3714 }
3715
3717 {
3718 dap_state_.transfer_abort = false;
3719 break;
3720 }
3721 }
3722
3723 if (pending_ap_write && should_check_pending_ap_write_at_tail())
3724 {
3725 const uint8_t PRIOR_RESPONSE = response_value;
3726 if (check_posted_ap_write_if_pending())
3727 {
3728 response_value = PRIOR_RESPONSE;
3729 }
3730 }
3731
3732 resp[1] = response_count;
3733 resp[2] = response_value;
3734 out_len = resp_off;
3735 return ErrorCode::OK;
3736 }
3737
3738 ErrorCode HandleJtagTransferBlock(bool /*in_isr*/, const uint8_t* req, uint16_t req_len,
3739 uint8_t* resp, uint16_t resp_cap, uint16_t& out_len)
3740 {
3741 if (!req || !resp || resp_cap < 4u)
3742 {
3743 out_len = 0u;
3744 return ErrorCode::ARG_ERR;
3745 }
3746
3747 resp[0] = ToU8(LibXR::USB::DapLinkV2Def::CommandId::TRANSFER_BLOCK);
3748 resp[1] = 0u;
3749 resp[2] = 0u;
3750 resp[3] = 0u;
3751 out_len = 4u;
3752
3753 if (req_len < 5u || jtag_ == nullptr || jtag_chain_.count == 0u)
3754 {
3755 resp[3] = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
3756 return ErrorCode::OK;
3757 }
3758
3760 {
3761 dap_state_.transfer_abort = false;
3762 resp[3] = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
3763 return ErrorCode::OK;
3764 }
3765
3766 const uint8_t TAP_INDEX = req[1];
3767 if (TAP_INDEX >= jtag_chain_.count)
3768 {
3769 resp[3] = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
3770 return ErrorCode::OK;
3771 }
3772
3773 jtag_chain_.index = TAP_INDEX;
3774 LibXR::Debug::JtagProtocol::UpdateChainCache(jtag_chain_);
3775
3776 uint16_t count = 0u;
3777 Memory::FastCopy(&count, &req[2], sizeof(count));
3778 const uint8_t DAP_RQ = req[4];
3779
3780 if ((DAP_RQ & (LibXR::USB::DapLinkV2Def::DAP_TRANSFER_MATCH_VALUE |
3781 LibXR::USB::DapLinkV2Def::DAP_TRANSFER_MATCH_MASK)) != 0u)
3782 {
3783 resp[3] = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
3785 }
3787 {
3788 resp[3] = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
3790 }
3791
3792 if (count == 0u)
3793 {
3794 const uint16_t DONE0 = 0u;
3795 Memory::FastCopy(&resp[1], &DONE0, sizeof(DONE0));
3796 resp[3] = LibXR::USB::DapLinkV2Def::DAP_TRANSFER_OK;
3797 out_len = 4u;
3798 return ErrorCode::OK;
3799 }
3800
3802 auto idle_after_attempt = [&]()
3803 {
3805 {
3807 }
3808 };
3809
3810 auto dp_read_retry = [&](uint8_t addr2b, uint32_t& val,
3811 LibXR::Debug::JtagProtocol::Ack& ack) -> ErrorCode
3812 {
3813 uint32_t retry = dap_state_.transfer_cfg.retry_count;
3814 while (true)
3815 {
3816 const ErrorCode ec = dp.DpReadTxn(addr2b, val, ack);
3817 idle_after_attempt();
3818 if (ack != LibXR::Debug::JtagProtocol::Ack::WAIT || retry == 0u ||
3820 {
3821 return ec;
3822 }
3823 --retry;
3824 }
3825 };
3826
3827 auto dp_write_retry = [&](uint8_t addr2b, uint32_t val,
3828 LibXR::Debug::JtagProtocol::Ack& ack) -> ErrorCode
3829 {
3830 uint32_t retry = dap_state_.transfer_cfg.retry_count;
3831 while (true)
3832 {
3833 const ErrorCode ec = dp.DpWriteTxn(addr2b, val, ack);
3834 idle_after_attempt();
3835 if (ack != LibXR::Debug::JtagProtocol::Ack::WAIT || retry == 0u ||
3837 {
3838 return ec;
3839 }
3840 --retry;
3841 }
3842 };
3843
3844 auto ap_read_retry = [&](uint8_t addr2b, uint32_t& val,
3845 LibXR::Debug::JtagProtocol::Ack& ack) -> ErrorCode
3846 {
3847 uint32_t retry = dap_state_.transfer_cfg.retry_count;
3848 while (true)
3849 {
3850 const ErrorCode ec = dp.ApReadTxn(addr2b, val, ack);
3851 idle_after_attempt();
3852 if (ack != LibXR::Debug::JtagProtocol::Ack::WAIT || retry == 0u ||
3854 {
3855 return ec;
3856 }
3857 --retry;
3858 }
3859 };
3860
3861 auto ap_write_retry = [&](uint8_t addr2b, uint32_t val,
3862 LibXR::Debug::JtagProtocol::Ack& ack) -> ErrorCode
3863 {
3864 uint32_t retry = dap_state_.transfer_cfg.retry_count;
3865 while (true)
3866 {
3867 const ErrorCode ec = dp.ApWriteTxn(addr2b, val, ack);
3868 idle_after_attempt();
3869 if (ack != LibXR::Debug::JtagProtocol::Ack::WAIT || retry == 0u ||
3871 {
3872 return ec;
3873 }
3874 --retry;
3875 }
3876 };
3877
3878 auto check_posted_ap_write_jtag =
3879 [&](LibXR::Debug::JtagProtocol::Ack& ack) -> ErrorCode
3880 {
3881 uint32_t ctrl_stat = 0u;
3882 return dp_read_retry(
3883 static_cast<uint8_t>(LibXR::Debug::SwdProtocol::DpReadReg::CTRL_STAT),
3884 ctrl_stat, ack);
3885 };
3886
3887 const bool AP = LibXR::USB::DapLinkV2Def::req_is_ap(DAP_RQ);
3888 const bool RNW = LibXR::USB::DapLinkV2Def::req_is_read(DAP_RQ);
3889 const uint8_t ADDR2B = LibXR::USB::DapLinkV2Def::req_addr2b(DAP_RQ);
3890
3891 uint16_t done = 0u;
3892 uint8_t xresp = 0u;
3893 uint16_t req_off = 5u;
3894 uint16_t resp_off = 4u;
3895
3896 if (!RNW)
3897 {
3898 for (uint32_t i = 0; i < count; ++i)
3899 {
3900 if (req_off + 4u > req_len)
3901 {
3902 xresp |= LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
3903 break;
3904 }
3905
3906 uint32_t wdata = 0u;
3907 Memory::FastCopy(&wdata, &req[req_off], sizeof(wdata));
3908 req_off = static_cast<uint16_t>(req_off + 4u);
3909
3910 LibXR::Debug::JtagProtocol::Ack ack = LibXR::Debug::JtagProtocol::Ack::PROTOCOL;
3911 ErrorCode ec =
3912 AP ? ap_write_retry(ADDR2B, wdata, ack) : dp_write_retry(ADDR2B, wdata, ack);
3913
3914 xresp = MapAckToDapResp(ack);
3915 if (xresp == 0u)
3916 {
3917 xresp |= LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
3918 break;
3919 }
3920
3921 if (ack != LibXR::Debug::JtagProtocol::Ack::OK)
3922 {
3923 break;
3924 }
3925
3926 if (ec != ErrorCode::OK)
3927 {
3928 xresp |= LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
3929 break;
3930 }
3931
3932 done = static_cast<uint16_t>(i + 1u);
3933 }
3934
3935 if (AP && xresp == LibXR::USB::DapLinkV2Def::DAP_TRANSFER_OK && done > 0u)
3936 {
3937 LibXR::Debug::JtagProtocol::Ack ack = LibXR::Debug::JtagProtocol::Ack::PROTOCOL;
3938 const ErrorCode ec = check_posted_ap_write_jtag(ack);
3939 const uint8_t v = MapAckToDapResp(ack);
3940 if (v != LibXR::USB::DapLinkV2Def::DAP_TRANSFER_OK)
3941 {
3942 xresp = v;
3943 }
3944 else if (ec != ErrorCode::OK)
3945 {
3946 xresp |= LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
3947 }
3948 }
3949
3950 Memory::FastCopy(&resp[1], &done, sizeof(done));
3951 resp[3] = xresp;
3952 out_len = resp_off;
3953 return ErrorCode::OK;
3954 }
3955
3956 for (uint32_t i = 0; i < count; ++i)
3957 {
3958 if (resp_off + 4u > resp_cap)
3959 {
3960 xresp |= LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
3961 break;
3962 }
3963
3964 LibXR::Debug::JtagProtocol::Ack ack = LibXR::Debug::JtagProtocol::Ack::PROTOCOL;
3966 uint32_t rdata = 0u;
3967
3968 if (AP)
3969 {
3970 ec = ap_read_retry(ADDR2B, rdata, ack);
3971 }
3972 else
3973 {
3974 ec = dp_read_retry(ADDR2B, rdata, ack);
3975 }
3976
3977 xresp = MapAckToDapResp(ack);
3978 if (xresp == 0u)
3979 {
3980 xresp |= LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
3981 break;
3982 }
3983
3984 if (ack != LibXR::Debug::JtagProtocol::Ack::OK)
3985 {
3986 break;
3987 }
3988
3989 if (ec != ErrorCode::OK)
3990 {
3991 xresp |= LibXR::USB::DapLinkV2Def::DAP_TRANSFER_ERROR;
3992 break;
3993 }
3994
3995 Memory::FastCopy(&resp[resp_off], &rdata, sizeof(rdata));
3996 resp_off = static_cast<uint16_t>(resp_off + 4u);
3997 done = static_cast<uint16_t>(i + 1u);
3998 }
3999
4000 Memory::FastCopy(&resp[1], &done, sizeof(done));
4001 resp[3] = xresp;
4002 out_len = resp_off;
4003 return ErrorCode::OK;
4004 }
4005
4006 ErrorCode HandleJtagWriteAbort(bool /*in_isr*/, const uint8_t* req, uint16_t req_len,
4007 uint8_t* resp, uint16_t resp_cap, uint16_t& out_len)
4008 {
4009 if (!req || !resp || resp_cap < 2u)
4010 {
4011 out_len = 0u;
4012 return ErrorCode::ARG_ERR;
4013 }
4014
4015 resp[0] = ToU8(LibXR::USB::DapLinkV2Def::CommandId::WRITE_ABORT);
4016 resp[1] = DAP_ERROR;
4017 out_len = 2u;
4018
4019 if (req_len < 6u || jtag_ == nullptr || jtag_chain_.count == 0u)
4020 {
4021 return ErrorCode::ARG_ERR;
4022 }
4023
4024 const uint8_t TAP_INDEX = req[1];
4025 if (TAP_INDEX >= jtag_chain_.count)
4026 {
4027 return ErrorCode::OK;
4028 }
4029
4030 jtag_chain_.index = TAP_INDEX;
4031 LibXR::Debug::JtagProtocol::UpdateChainCache(jtag_chain_);
4032
4033 uint32_t flags = 0u;
4034 Memory::FastCopy(&flags, &req[2], sizeof(flags));
4035
4037 LibXR::Debug::JtagProtocol::Ack ack = LibXR::Debug::JtagProtocol::Ack::PROTOCOL;
4038 const ErrorCode ec = dp.WriteAbort(flags, ack);
4039 if (ec == ErrorCode::OK && ack == LibXR::Debug::JtagProtocol::Ack::OK)
4040 {
4041 resp[1] = DAP_OK;
4042 }
4043 return ErrorCode::OK;
4044 }
4045
4046 private:
4047 // ============================================================================
4048 // Reset helpers
4049 // ============================================================================
4050
4051 void DriveReset(bool release)
4052 {
4053 last_nreset_level_high_ = release;
4054
4055 // Update shadow regardless of whether GPIO exists
4056 if (release)
4057 {
4058 swj_shadow_ |= LibXR::USB::DapLinkV2Def::DAP_SWJ_NRESET;
4059 }
4060 else
4061 {
4062 swj_shadow_ = static_cast<uint8_t>(
4063 swj_shadow_ & static_cast<uint8_t>(~LibXR::USB::DapLinkV2Def::DAP_SWJ_NRESET));
4064 }
4065
4066 if (nreset_gpio_ != nullptr)
4067 {
4068 (void)nreset_gpio_->Write(release);
4069 }
4070 }
4071
4072 void ResetJtagChainState()
4073 {
4074 if constexpr (JTAG_ENABLED)
4075 {
4077 jtag_chain_.count = 0u;
4078 jtag_chain_.index = 0u;
4084 }
4085 }
4086
4087 void DelayUsIfAllowed(bool /*in_isr*/, uint32_t us)
4088 {
4090 }
4091
4092 private:
4093 static constexpr uint16_t DEFAULT_DAP_PACKET_SIZE = DefaultDapPacketSize;
4094 static constexpr uint8_t PACKET_COUNT_ADVERTISED = AdvertisedPacketCount;
4095 static constexpr uint8_t PACKET_COUNT_EFFECTIVE =
4096 (PACKET_COUNT_ADVERTISED > 4u) ? 4u : PACKET_COUNT_ADVERTISED;
4097 static constexpr uint8_t MAX_OUTSTANDING_RESPONSES = PACKET_COUNT_EFFECTIVE;
4098 // OpenOCD 0.12 computes pending_queue_len = (packet_size - 4) / 5 for CMD_DAP_TFER.
4099 // CMD_DAP_TFER transfer_count is u8, so cap host-visible packet size to avoid
4100 // transfer_count > 255 and "expected X, got Y" mismatch.
4101 static constexpr uint16_t OPENOCD_SAFE_DAP_PACKET_SIZE =
4102 static_cast<uint16_t>((255u * 5u) + 4u);
4103 static constexpr uint8_t JTAG_MAX_DEVICES = 16u;
4104 // Host-visible CMSIS-DAP packet size; endpoint MPS limits are handled by
4105 // TransferMultiBulk segmentation/reassembly.
4106 static constexpr uint16_t MAX_DAP_PACKET_SIZE = MaxDapPacketSize;
4107 static constexpr uint16_t QUEUED_REQ_BUFFER_SIZE = QueuedRequestBufferSize;
4108 static constexpr uint16_t QUEUED_CMD_COUNT_MAX = QueuedCommandCountMax;
4109 static constexpr uint16_t RESP_SLOT_SIZE = MAX_DAP_PACKET_SIZE;
4110 static constexpr uint8_t RESP_QUEUE_DEPTH = PACKET_COUNT_EFFECTIVE;
4111 static constexpr uint16_t QUEUED_REQ_BUFFER_ALLOC_SIZE = QUEUED_REQ_BUFFER_SIZE;
4112 static_assert(PACKET_COUNT_ADVERTISED > 0u, "PACKET_COUNT_ADVERTISED must be > 0");
4113 static_assert(PACKET_COUNT_EFFECTIVE > 0u, "PACKET_COUNT_EFFECTIVE must be > 0");
4114 static_assert(MAX_DAP_PACKET_SIZE >= DEFAULT_DAP_PACKET_SIZE,
4115 "MAX_DAP_PACKET_SIZE must be >= DEFAULT_DAP_PACKET_SIZE");
4116 static_assert(MAX_DAP_PACKET_SIZE <= OPENOCD_SAFE_DAP_PACKET_SIZE,
4117 "MAX_DAP_PACKET_SIZE exceeds OpenOCD-safe limit");
4118 static_assert(((OPENOCD_SAFE_DAP_PACKET_SIZE - 4u) / 5u) <= 255u,
4119 "OPENOCD_SAFE_DAP_PACKET_SIZE too large for CMD_DAP_TFER u8 count");
4120 static_assert(QUEUED_REQ_BUFFER_SIZE > 0u, "QUEUED_REQ_BUFFER_SIZE must be > 0");
4121 static_assert(QUEUED_CMD_COUNT_MAX > 0u, "QUEUED_CMD_COUNT_MAX must be > 0");
4122 static_assert(RESP_SLOT_SIZE >= DEFAULT_DAP_PACKET_SIZE,
4123 "RESP_SLOT_SIZE must cover FS bulk packet size");
4124 static_assert((RESP_QUEUE_DEPTH & (RESP_QUEUE_DEPTH - 1u)) == 0u,
4125 "Response queue depth must be power-of-two");
4126
4127 static constexpr uint8_t WINUSB_VENDOR_CODE =
4128 0x20;
4129
4130 // REG_MULTI_SZ: "<GUID>\0\0" (UTF-16LE). GUID_STR_UTF16_BYTES should already include
4131 // the first UTF-16 NUL.
4132 static constexpr uint16_t GUID_MULTI_SZ_UTF_16_BYTES =
4133 static_cast<uint16_t>(LibXR::USB::WinUsbMsOs20::GUID_STR_UTF16_BYTES +
4134 2);
4135
4137 {
4138 uint16_t len = 0u;
4139 uint8_t payload[RESP_SLOT_SIZE] = {};
4140 };
4141
4142 ResponseSlot resp_q_[RESP_QUEUE_DEPTH] = {};
4143 uint8_t resp_q_head_ = 0u;
4144 uint8_t resp_q_tail_ = 0u;
4145 uint8_t resp_q_count_ = 0u;
4146 bool deferred_in_resp_valid_ = false;
4147 uint16_t deferred_in_resp_len_ = 0u;
4148
4149 uint8_t queued_request_buffer_[QUEUED_REQ_BUFFER_ALLOC_SIZE] = {};
4150 uint16_t queued_request_length_ = 0u;
4151 uint16_t queued_command_count_ = 0u;
4152
4153 uint8_t out_req_multi_storage_[MAX_DAP_PACKET_SIZE] = {};
4154 LibXR::RawData out_req_multi_buf_{out_req_multi_storage_, DEFAULT_DAP_PACKET_SIZE};
4155 uint8_t in_tx_multi_storage_[MAX_DAP_PACKET_SIZE] = {};
4156 LibXR::RawData in_tx_multi_buf_{in_tx_multi_storage_, DEFAULT_DAP_PACKET_SIZE};
4157
4158 LIBXR_PACKED_BEGIN
4186 LIBXR_PACKED_END
4187
4188 private:
4189 SwdPort& swd_;
4190
4193 uint8_t jtag_ir_len_[JTAG_MAX_DEVICES] = {};
4194
4196
4197 uint8_t swj_shadow_ = static_cast<uint8_t>(
4198 DapLinkV2Def::DAP_SWJ_SWDIO_TMS |
4199 DapLinkV2Def::DAP_SWJ_NRESET);
4200
4202
4204 InfoStrings info_{"XRobot", "DAPLinkV2", "00000001", "2.0.0", "XRUSB",
4205 "XRDAP", "XRobot", "DAP_DEMO", "0.1.0"};
4206
4207 uint32_t swj_clock_hz_ = 1000000u;
4208
4209 const char* interface_string_ = nullptr;
4210
4213
4216
4217 bool inited_ = false;
4218 uint8_t interface_num_ = 0;
4219
4220 LIBXR_PACKED_BEGIN
4231 LIBXR_PACKED_END
4232
4233 private:
4237
4238 uint32_t match_mask_ = 0xFFFFFFFFu;
4239
4242
4245};
4246
4247} // namespace LibXR::USB
通用回调包装,支持动态参数传递 / Generic callback wrapper supporting dynamic argument passing
Definition libxr_cb.hpp:143
static Callback Create(CallableType fun, BoundArgType arg)
创建回调对象并绑定回调函数与参数 / Create a callback instance with bound function and argument
Definition libxr_cb.hpp:166
只读原始数据视图 / Immutable raw data view
size_t size_
数据字节数 / Data size in bytes
const void * addr_
数据起始地址 / Data start address
JTAG-DP 事务层封装(DP/AP 访问与 IDCODE/ABORT)。
Definition jtag_dp.hpp:20
Abstract JTAG base class providing TAP control and IR/DR shifting.
Definition jtag.hpp:37
virtual void Close()=0
Close JTAG and release resources.
virtual ErrorCode ResetTap()=0
Reset TAP to Test-Logic-Reset.
virtual ErrorCode Sequence(uint32_t cycles, bool tms, const uint8_t *tdi_lsb_first, uint8_t *tdo_lsb_first)=0
Shift a fixed-TMS sequence, LSB first.
virtual ErrorCode SetClockHz(uint32_t hz)=0
Set TCK frequency, if supported.
virtual void IdleClocks(uint32_t cycles)=0
Insert idle clock cycles in Run-Test/Idle.
通用输入输出(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
可写原始数据视图 / 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.
static void DelayMicroseconds(uint32_t us)
微秒级延时 / Delay in microseconds
Definition timebase.hpp:65
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
uint8_t GetAddress() const
获取端点地址(方向 + 号) / Get endpoint address (dir + num)
Definition ep.hpp:194
@ IN
输入方向 / IN direction
@ OUT
输出方向 / OUT direction
virtual ErrorCode TransferMultiBulk(RawData &data)
Bulk 多包传输辅助接口 / Helper for multi-packet bulk transfer.
Definition ep.hpp:320
void SetActiveLength(uint16_t len)
设置当前活动缓冲区有效长度 / Set active buffer valid length
Definition ep.hpp:270
virtual size_t MaxTransferSize() const
返回当前最大可传输字节数 / Return maximum transferable size at this time
Definition ep.hpp:282
void SetOnTransferCompleteCallback(Callback< ConstRawData & > cb)
设置传输完成回调 / Set transfer complete callback
Definition ep.hpp:261
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:225
State GetState() const
获取端点状态 / Get endpoint state
Definition ep.hpp:207
virtual ErrorCode Transfer(size_t size)=0
启动一次传输 / Start a transfer
RawData GetBuffer() const
获取当前可用于传输的缓冲区 / Get current transfer buffer
Definition ep.hpp:245
USB端点池类 / USB endpoint pool class.
Definition ep_pool.hpp:29
ErrorCode Release(Endpoint *ep_info)
回收端点 / Release endpoint
Definition ep_pool.cpp:93
ErrorCode Get(Endpoint *&ep_info, Endpoint::Direction direction, Endpoint::EPNumber ep_num)
分配端点 / Allocate endpoint
Definition ep_pool.cpp:52
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
JTAG 设备链配置 / JTAG device chain configuration.
const uint8_t * ir_length
各设备 IR 长度数组 / IR length array
uint8_t count
设备数(TDO 端为 index=0)/ Device count (TDO side index=0)
uint32_t ir_before_bits_len
前面设备 IR 总位数 / IR bits before
uint32_t ir_after_bits_len
后面设备 IR 总位数 / IR bits after
uint32_t dr_after_bits_len
后面设备 DR 总位数 / DR bits after
uint8_t index
当前设备索引 / Current device index
uint32_t dr_before_bits_len
前面设备 DR 总位数 / DR bits before
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