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