1mod commands;
3mod tools;
4
5use crate::{
6 CoreStatus,
7 architecture::{
8 arm::{
9 ArmCommunicationInterface, ArmDebugInterface, ArmError, DapError, Pins, RawDapAccess,
10 RegisterAddress, SwoAccess, SwoConfig, SwoMode,
11 communication_interface::DapProbe,
12 dp::{Abort, Ctrl, DpRegister},
13 sequences::ArmDebugSequence,
14 swo::poll_interval_from_buf_size,
15 },
16 riscv::{
17 communication_interface::{RiscvError, RiscvInterfaceBuilder},
18 dtm::jtag_dtm::JtagDtmBuilder,
19 },
20 xtensa::communication_interface::{
21 XtensaCommunicationInterface, XtensaDebugInterfaceState, XtensaError,
22 },
23 },
24 probe::{
25 AutoImplementJtagAccess, BatchCommand, DebugProbe, DebugProbeError, DebugProbeInfo,
26 DebugProbeSelector, JtagAccess, JtagDriverState, ProbeFactory, WireProtocol,
27 cmsisdap::commands::{
28 CmsisDapError, RequestError,
29 general::info::{CapabilitiesCommand, PacketCountCommand, SWOTraceBufferSizeCommand},
30 },
31 },
32};
33
34use commands::{
35 CmsisDapDevice, Status,
36 general::{
37 connect::{ConnectRequest, ConnectResponse},
38 disconnect::{DisconnectRequest, DisconnectResponse},
39 host_status::{HostStatusRequest, HostStatusResponse},
40 info::Capabilities,
41 reset::{ResetRequest, ResetResponse},
42 },
43 jtag::{
44 JtagBuffer,
45 configure::ConfigureRequest as JtagConfigureRequest,
46 sequence::{
47 Sequence as JtagSequence, SequenceRequest as JtagSequenceRequest,
48 SequenceResponse as JtagSequenceResponse,
49 },
50 },
51 swd,
52 swj::{
53 clock::SWJClockRequest,
54 pins::{SWJPinsRequest, SWJPinsRequestBuilder, SWJPinsResponse},
55 sequence::{SequenceRequest, SequenceResponse},
56 },
57 swo,
58 transfer::{
59 Ack, TransferBlockRequest, TransferBlockResponse, TransferRequest,
60 configure::ConfigureRequest,
61 },
62};
63use probe_rs_target::ScanChainElement;
64
65use std::{fmt::Write, sync::Arc, time::Duration};
66
67use bitvec::prelude::*;
68
69use super::common::{ScanChainError, extract_idcodes, extract_ir_lengths};
70
71#[derive(Debug)]
73pub struct CmsisDapFactory;
74
75impl std::fmt::Display for CmsisDapFactory {
76 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
77 f.write_str("CMSIS-DAP")
78 }
79}
80
81impl ProbeFactory for CmsisDapFactory {
82 fn open(&self, selector: &DebugProbeSelector) -> Result<Box<dyn DebugProbe>, DebugProbeError> {
83 CmsisDap::new_from_device(tools::open_device_from_selector(selector)?)
84 .map(Box::new)
85 .map(DebugProbe::into_probe)
86 }
87
88 fn list_probes(&self) -> Vec<DebugProbeInfo> {
89 tools::list_cmsisdap_devices()
90 }
91}
92
93pub struct CmsisDap {
95 device: CmsisDapDevice,
96 _hw_version: u8,
97 _jtag_version: u8,
98 protocol: Option<WireProtocol>,
99
100 packet_size: u16,
101 packet_count: u8,
102 capabilities: Capabilities,
103 swo_buffer_size: Option<usize>,
104 swo_active: bool,
105 swo_streaming: bool,
106 connected: bool,
107
108 speed_khz: u32,
110
111 batch: Vec<BatchCommand>,
112
113 jtag_state: JtagDriverState,
114 jtag_buffer: JtagBuffer,
115}
116
117impl std::fmt::Debug for CmsisDap {
118 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
119 fmt.debug_struct("CmsisDap")
120 .field("protocol", &self.protocol)
121 .field("packet_size", &self.packet_size)
122 .field("packet_count", &self.packet_count)
123 .field("capabilities", &self.capabilities)
124 .field("swo_buffer_size", &self.swo_buffer_size)
125 .field("swo_active", &self.swo_active)
126 .field("swo_streaming", &self.swo_streaming)
127 .field("speed_khz", &self.speed_khz)
128 .finish()
129 }
130}
131
132impl CmsisDap {
133 fn new_from_device(mut device: CmsisDapDevice) -> Result<Self, DebugProbeError> {
134 device.drain();
137
138 let packet_size = device.find_packet_size()? as u16;
141
142 let packet_count = commands::send_command(&mut device, &PacketCountCommand {})?;
144 let caps: Capabilities = commands::send_command(&mut device, &CapabilitiesCommand {})?;
145 tracing::debug!("Detected probe capabilities: {:?}", caps);
146 let mut swo_buffer_size = None;
147 if caps.swo_uart_implemented || caps.swo_manchester_implemented {
148 let swo_size = commands::send_command(&mut device, &SWOTraceBufferSizeCommand {})?;
149 swo_buffer_size = Some(swo_size as usize);
150 tracing::debug!("Probe SWO buffer size: {}", swo_size);
151 }
152
153 Ok(Self {
154 device,
155 _hw_version: 0,
156 _jtag_version: 0,
157 protocol: None,
158 packet_count,
159 packet_size,
160 capabilities: caps,
161 swo_buffer_size,
162 swo_active: false,
163 swo_streaming: false,
164 connected: false,
165 speed_khz: 1_000,
166 batch: Vec::new(),
167 jtag_state: JtagDriverState::default(),
168 jtag_buffer: JtagBuffer::new(packet_size - 1),
169 })
170 }
171
172 fn set_swj_clock(&mut self, clock_speed_hz: u32) -> Result<(), CmsisDapError> {
176 let request = SWJClockRequest { clock_speed_hz };
177 commands::send_command(&mut self.device, &request).and_then(|v| match v.status {
178 Status::DapOk => Ok(()),
179 Status::DapError => Err(CmsisDapError::ErrorResponse(RequestError::SWJClock {
180 request,
181 })),
182 })
183 }
184
185 fn transfer_configure(&mut self, request: ConfigureRequest) -> Result<(), CmsisDapError> {
186 commands::send_command(&mut self.device, &request).and_then(|v| match v.status {
187 Status::DapOk => Ok(()),
188 Status::DapError => Err(CmsisDapError::ErrorResponse(
189 RequestError::TransferConfigure { request },
190 )),
191 })
192 }
193
194 fn configure_swd(
195 &mut self,
196 request: swd::configure::ConfigureRequest,
197 ) -> Result<(), CmsisDapError> {
198 commands::send_command(&mut self.device, &request).and_then(|v| match v.status {
199 Status::DapOk => Ok(()),
200 Status::DapError => Err(CmsisDapError::ErrorResponse(RequestError::SwdConfigure {
201 request,
202 })),
203 })
204 }
205
206 fn jtag_ensure_test_logic_reset(&mut self) -> Result<(), CmsisDapError> {
208 let sequence = JtagSequence::no_capture(true, bits![0; 6])?;
209 let sequences = vec![sequence];
210
211 self.send_jtag_sequences(JtagSequenceRequest::new(sequences)?)?;
212
213 Ok(())
214 }
215
216 fn jtag_ensure_run_test_idle(&mut self) -> Result<(), CmsisDapError> {
218 self.jtag_ensure_test_logic_reset()?;
222
223 let sequence = JtagSequence::no_capture(false, bits![0; 1])?;
225 let sequences = vec![sequence];
226 self.send_jtag_sequences(JtagSequenceRequest::new(sequences)?)?;
227
228 Ok(())
229 }
230
231 fn jtag_scan(
237 &mut self,
238 ir_lengths: Option<&[usize]>,
239 ) -> Result<Vec<ScanChainElement>, CmsisDapError> {
240 let (ir, dr) = self.jtag_reset_scan()?;
241 let idcodes = extract_idcodes(&dr)?;
242 let ir_lens = extract_ir_lengths(&ir, idcodes.len(), ir_lengths)?;
243
244 Ok(idcodes
245 .into_iter()
246 .zip(ir_lens)
247 .map(|(idcode, irlen)| ScanChainElement {
248 ir_len: Some(irlen as u8),
249 name: idcode.map(|i| i.to_string()),
250 })
251 .collect())
252 }
253
254 fn jtag_reset_scan(&mut self) -> Result<(BitVec, BitVec), CmsisDapError> {
258 let dr = self.jtag_scan_dr()?;
259 let ir = self.jtag_scan_ir()?;
260
261 self.jtag_ensure_run_test_idle()?;
263
264 Ok((ir, dr))
265 }
266
267 fn jtag_scan_ir(&mut self) -> Result<BitVec, CmsisDapError> {
272 self.jtag_ensure_shift_ir()?;
273 let data = self.jtag_scan_inner("IR")?;
274 Ok(data)
275 }
276
277 fn jtag_scan_dr(&mut self) -> Result<BitVec, CmsisDapError> {
282 self.jtag_ensure_shift_dr()?;
283 let data = self.jtag_scan_inner("DR")?;
284 Ok(data)
285 }
286
287 fn jtag_scan_inner(&mut self, name: &'static str) -> Result<BitVec, CmsisDapError> {
290 const MAX_LENGTH: usize = 128;
292 const BYTES_PER_REQUEST: usize = 16;
294 const REQUESTS: usize = MAX_LENGTH.div_ceil(BYTES_PER_REQUEST * 8);
296
297 let mut tdo_bytes: BitVec = BitVec::with_capacity(REQUESTS * BYTES_PER_REQUEST * 8);
299 for _ in 0..REQUESTS {
300 let sequences = vec![
301 JtagSequence::capture(false, bits![0; 64])?,
302 JtagSequence::capture(false, bits![0; 64])?,
303 ];
304
305 tdo_bytes.extend_from_bitslice(
306 &self.send_jtag_sequences(JtagSequenceRequest::new(sequences)?)?,
307 );
308 }
309 let d0 = tdo_bytes;
310
311 let mut tdo_bytes: BitVec<u8> = BitVec::with_capacity(REQUESTS * BYTES_PER_REQUEST * 8);
313 for _ in 0..REQUESTS {
314 let sequences = vec![
315 JtagSequence::capture(false, bits![1; 64])?,
316 JtagSequence::capture(false, bits![1; 64])?,
317 ];
318
319 tdo_bytes.extend_from_bitslice(
320 &self.send_jtag_sequences(JtagSequenceRequest::new(sequences)?)?,
321 );
322 }
323 let d1 = tdo_bytes;
324
325 let n = match d1.first_one() {
327 Some(n) => {
328 tracing::info!("JTAG {name} scan chain detected as {n} bits long");
329 n
330 }
331 None => {
332 let expected_bit = 1;
333 tracing::error!(
334 "JTAG {name} scan chain either broken or too long: did not detect {expected_bit}"
335 );
336 return Err(CmsisDapError::ErrorResponse(
337 RequestError::BrokenScanChain { name, expected_bit },
338 ));
339 }
340 };
341
342 if n == 0 {
344 tracing::error!("JTAG {name} scan chain is empty");
345 return Err(CmsisDapError::ErrorResponse(RequestError::EmptyScanChain {
346 name,
347 }));
348 }
349
350 if d0[n..].any() {
352 let expected_bit = 0;
353 tracing::error!(
354 "JTAG {name} scan chain either broken or too long: did not detect {expected_bit}"
355 );
356 return Err(CmsisDapError::ErrorResponse(
357 RequestError::BrokenScanChain { name, expected_bit },
358 ));
359 }
360
361 let data = d0[..n].to_bitvec();
363
364 Ok(data)
365 }
366
367 fn jtag_ensure_shift_dr(&mut self) -> Result<(), CmsisDapError> {
368 self.jtag_ensure_test_logic_reset()?;
370
371 let sequences = vec![
373 JtagSequence::no_capture(false, bits![0; 1])?,
374 JtagSequence::no_capture(true, bits![0; 1])?,
375 JtagSequence::no_capture(false, bits![0; 2])?,
376 ];
377 self.send_jtag_sequences(JtagSequenceRequest::new(sequences)?)?;
378
379 Ok(())
380 }
381
382 fn jtag_ensure_shift_ir(&mut self) -> Result<(), CmsisDapError> {
383 self.jtag_ensure_test_logic_reset()?;
385
386 let sequences = vec![
388 JtagSequence::no_capture(false, bits![0; 1])?,
389 JtagSequence::no_capture(true, bits![0; 2])?,
390 JtagSequence::no_capture(false, bits![0; 2])?,
391 ];
392 self.send_jtag_sequences(JtagSequenceRequest::new(sequences)?)?;
393
394 Ok(())
395 }
396
397 fn send_jtag_configure(&mut self, request: JtagConfigureRequest) -> Result<(), CmsisDapError> {
398 commands::send_command(&mut self.device, &request).and_then(|v| match v.status {
399 Status::DapOk => Ok(()),
400 Status::DapError => Err(CmsisDapError::ErrorResponse(RequestError::JtagConfigure {
401 request,
402 })),
403 })
404 }
405
406 fn send_jtag_sequences(
407 &mut self,
408 request: JtagSequenceRequest,
409 ) -> Result<BitVec, CmsisDapError> {
410 commands::send_command(&mut self.device, &request).and_then(|v| match v {
411 JtagSequenceResponse(Status::DapOk, tdo) => Ok(tdo),
412 JtagSequenceResponse(Status::DapError, _) => {
413 Err(CmsisDapError::ErrorResponse(RequestError::JtagSequence {
414 request,
415 }))
416 }
417 })
418 }
419
420 fn send_swj_sequences(&mut self, request: SequenceRequest) -> Result<(), CmsisDapError> {
421 commands::send_command(&mut self.device, &request).and_then(|v| match v {
425 SequenceResponse(Status::DapOk) => Ok(()),
426 SequenceResponse(Status::DapError) => {
427 Err(CmsisDapError::ErrorResponse(RequestError::SwjSequence {
428 request,
429 }))
430 }
431 })
432 }
433
434 fn read_ctrl_register(&mut self) -> Result<Ctrl, ArmError> {
443 let mut request = TransferRequest::read(Ctrl::ADDRESS);
444 request.dap_index = self.jtag_state.chain_params.index as u8;
445 let response =
446 commands::send_command(&mut self.device, &request).map_err(DebugProbeError::from)?;
447
448 if response.last_transfer_response.protocol_error {
452 Err(DapError::Protocol(
455 self.protocol
456 .expect("A wire protocol should have been selected by now"),
457 )
458 .into())
459 } else {
460 if response.last_transfer_response.ack != Ack::Ok {
461 tracing::debug!(
462 "Error reading debug port CTRL register: {:?}. This should never fail!",
463 response.last_transfer_response.ack
464 );
465 }
466
467 match response.last_transfer_response.ack {
468 Ack::Ok => {
469 Ok(Ctrl(response.transfers[0].data.expect(
470 "CMSIS-DAP probe should always return data for a read.",
471 )))
472 }
473 Ack::Wait => Err(DapError::WaitResponse.into()),
474 Ack::Fault => Err(DapError::FaultResponse.into()),
475 Ack::NoAck => Err(DapError::NoAcknowledge.into()),
476 }
477 }
478 }
479
480 fn write_abort(&mut self, abort: Abort) -> Result<(), ArmError> {
481 let mut request = TransferRequest::write(Abort::ADDRESS, abort.into());
482 request.dap_index = self.jtag_state.chain_params.index as u8;
483 let response =
484 commands::send_command(&mut self.device, &request).map_err(DebugProbeError::from)?;
485
486 if response.last_transfer_response.protocol_error {
490 Err(DapError::Protocol(
493 self.protocol
494 .expect("A wire protocol should have been selected by now"),
495 )
496 .into())
497 } else {
498 match response.last_transfer_response.ack {
499 Ack::Ok => Ok(()),
500 Ack::Wait => Err(DapError::WaitResponse.into()),
501 Ack::Fault => Err(DapError::FaultResponse.into()),
502 Ack::NoAck => Err(DapError::NoAcknowledge.into()),
503 }
504 }
505 }
506
507 #[tracing::instrument(skip(self))]
515 fn process_batch(&mut self) -> Result<Option<u32>, ArmError> {
516 let batch = std::mem::take(&mut self.batch);
517 if batch.is_empty() {
518 return Ok(None);
519 }
520
521 tracing::debug!("{} items in batch", batch.len());
522
523 let mut transfers = TransferRequest::empty();
524 transfers.dap_index = self.jtag_state.chain_params.index as u8;
525 for command in batch.iter().cloned() {
526 match command {
527 BatchCommand::Read(port) => {
528 transfers.add_read(port);
529 }
530 BatchCommand::Write(port, value) => {
531 transfers.add_write(port, value);
532 }
533 }
534 }
535
536 let response =
537 commands::send_command(&mut self.device, &transfers).map_err(DebugProbeError::from)?;
538
539 let count = response.transfers.len();
540
541 tracing::debug!("{} of batch of {} items executed", count, batch.len());
542
543 if response.last_transfer_response.protocol_error {
544 tracing::warn!(
545 "Protocol error in response to command {}",
546 batch[count.saturating_sub(1)]
547 );
548
549 return Err(DapError::Protocol(
550 self.protocol
551 .expect("A wire protocol should have been selected by now"),
552 )
553 .into());
554 }
555
556 match response.last_transfer_response.ack {
557 Ack::Ok => {
558 if count < batch.len() {
566 tracing::warn!(
567 "CMSIS_DAP: Only {}/{} transfers were executed, but no error was reported.",
568 count,
569 batch.len()
570 );
571 return Err(ArmError::Other(format!(
572 "Possible error in CMSIS-DAP probe: Only {}/{} transfers were executed, but no error was reported.",
573 count,
574 batch.len()
575 )));
576 }
577
578 tracing::trace!("Last transfer status: ACK");
579 Ok(response.transfers[count - 1].data)
580 }
581 Ack::NoAck => {
582 tracing::debug!(
583 "Transfer status for batch item {}/{}: NACK",
584 count,
585 batch.len()
586 );
587 Err(DapError::NoAcknowledge.into())
589 }
590 Ack::Fault => {
591 tracing::debug!(
592 "Transfer status for batch item {}/{}: FAULT",
593 count,
594 batch.len()
595 );
596
597 let ctrl = self.read_ctrl_register()?;
601
602 tracing::trace!("Ctrl/Stat register value is: {:?}", ctrl);
603
604 if ctrl.sticky_err() {
605 self.write_abort({
607 let mut abort = Abort(0);
608 abort.set_stkerrclr(ctrl.sticky_err());
609 abort
610 })?;
611 }
612
613 Err(DapError::FaultResponse.into())
614 }
615 Ack::Wait => {
616 tracing::debug!(
617 "Transfer status for batch item {}/{}: WAIT",
618 count,
619 batch.len()
620 );
621
622 self.write_abort({
623 let mut abort = Abort(0);
624 abort.set_dapabort(true);
625 abort
626 })?;
627
628 Err(DapError::WaitResponse.into())
629 }
630 }
631 }
632
633 fn batch_add(&mut self, command: BatchCommand) -> Result<Option<u32>, ArmError> {
640 tracing::debug!("Adding command to batch: {}", command);
641
642 let command_is_read = matches!(command, BatchCommand::Read(_));
643 self.batch.push(command);
644
645 let max_writes = (self.packet_size as usize - 3) / (1 + 4);
649 if command_is_read || self.batch.len() == max_writes {
650 self.process_batch()
651 } else {
652 Ok(None)
653 }
654 }
655
656 fn set_swo_transport(
660 &mut self,
661 transport: swo::TransportRequest,
662 ) -> Result<(), DebugProbeError> {
663 let response = commands::send_command(&mut self.device, &transport)?;
664 match response.status {
665 Status::DapOk => Ok(()),
666 Status::DapError => {
667 Err(CmsisDapError::ErrorResponse(RequestError::SwoTransport { transport }).into())
668 }
669 }
670 }
671
672 fn set_swo_mode(&mut self, mode: swo::ModeRequest) -> Result<(), DebugProbeError> {
676 let response = commands::send_command(&mut self.device, &mode)?;
677 match response.status {
678 Status::DapOk => Ok(()),
679 Status::DapError => {
680 Err(CmsisDapError::ErrorResponse(RequestError::SwoMode { mode }).into())
681 }
682 }
683 }
684
685 fn set_swo_baudrate(&mut self, request: swo::BaudrateRequest) -> Result<u32, DebugProbeError> {
692 let response = commands::send_command(&mut self.device, &request)?;
693 tracing::debug!("Requested baud {}, got {}", request.baudrate, response);
694 if response == 0 {
695 Err(CmsisDapError::SwoBaudrateNotConfigured.into())
696 } else {
697 Ok(response)
698 }
699 }
700
701 fn start_swo_capture(&mut self) -> Result<(), DebugProbeError> {
703 let command = swo::ControlRequest::Start;
704 let response = commands::send_command(&mut self.device, &command)?;
705 match response.status {
706 Status::DapOk => Ok(()),
707 Status::DapError => {
708 Err(CmsisDapError::ErrorResponse(RequestError::SwoControl { command }).into())
709 }
710 }
711 }
712
713 fn stop_swo_capture(&mut self) -> Result<(), DebugProbeError> {
715 let command = swo::ControlRequest::Stop;
716 let response = commands::send_command(&mut self.device, &command)?;
717 match response.status {
718 Status::DapOk => Ok(()),
719 Status::DapError => {
720 Err(CmsisDapError::ErrorResponse(RequestError::SwoControl { command }).into())
721 }
722 }
723 }
724
725 #[expect(dead_code)]
727 fn get_swo_status(&mut self) -> Result<swo::StatusResponse, DebugProbeError> {
728 Ok(commands::send_command(
729 &mut self.device,
730 &swo::StatusRequest,
731 )?)
732 }
733
734 #[expect(dead_code)]
740 fn get_swo_extended_status(
741 &mut self,
742 request: swo::ExtendedStatusRequest,
743 ) -> Result<swo::ExtendedStatusResponse, DebugProbeError> {
744 Ok(commands::send_command(&mut self.device, &request)?)
745 }
746
747 fn get_swo_data(&mut self) -> Result<Vec<u8>, DebugProbeError> {
749 match self.swo_buffer_size {
750 Some(swo_buffer_size) => {
751 let n = usize::min(swo_buffer_size, self.packet_size as usize) as u16;
755
756 let response: swo::DataResponse =
757 commands::send_command(&mut self.device, &swo::DataRequest { max_count: n })?;
758 if response.status.error {
759 Err(CmsisDapError::SwoTraceStreamError.into())
760 } else {
761 Ok(response.data)
762 }
763 }
764 None => Ok(Vec::new()),
765 }
766 }
767
768 fn connect_if_needed(&mut self) -> Result<(), DebugProbeError> {
769 if self.connected {
770 return Ok(());
771 }
772
773 let protocol: ConnectRequest = if let Some(protocol) = self.protocol {
774 match protocol {
775 WireProtocol::Swd => ConnectRequest::Swd,
776 WireProtocol::Jtag => ConnectRequest::Jtag,
777 }
778 } else {
779 ConnectRequest::DefaultPort
780 };
781
782 let used_protocol =
783 commands::send_command(&mut self.device, &protocol).and_then(|v| match v {
784 ConnectResponse::SuccessfulInitForSWD => Ok(WireProtocol::Swd),
785 ConnectResponse::SuccessfulInitForJTAG => Ok(WireProtocol::Jtag),
786 ConnectResponse::InitFailed => {
787 Err(CmsisDapError::ErrorResponse(RequestError::InitFailed {
788 protocol: self.protocol,
789 }))
790 }
791 })?;
792
793 tracing::info!("Using protocol {}", used_protocol);
795 self.protocol = Some(used_protocol);
796
797 if matches!(self.protocol, Some(WireProtocol::Jtag)) {
800 commands::send_command(
801 &mut self.device,
802 &SWJPinsRequestBuilder::new().ntrst(true).build(),
803 )
804 .ok();
805 }
806 self.connected = true;
807
808 Ok(())
809 }
810}
811
812impl DebugProbe for CmsisDap {
813 fn get_name(&self) -> &str {
814 match &self.device {
815 CmsisDapDevice::V2 { handle, .. } => format!(
816 "CMSIS-DAP V2 IF: {} DESC: {:?}",
817 handle.interface_number(),
818 handle.descriptor()
819 )
820 .leak(),
821
822 #[cfg(feature = "cmsisdap_v1")]
823 _ => "CMSIS-DAP V1",
824 }
825 }
826
827 fn speed_khz(&self) -> u32 {
831 self.speed_khz
832 }
833
834 fn set_speed(&mut self, speed_khz: u32) -> Result<u32, DebugProbeError> {
838 self.set_swj_clock(speed_khz * 1_000)?;
839 self.speed_khz = speed_khz;
840
841 Ok(speed_khz)
842 }
843
844 #[tracing::instrument(skip(self))]
846 fn attach(&mut self) -> Result<(), DebugProbeError> {
847 tracing::debug!("Attaching to target system (clock = {}kHz)", self.speed_khz);
848
849 self.connect_if_needed()?;
851
852 self.set_speed(self.speed_khz)?;
854
855 self.transfer_configure(ConfigureRequest {
856 idle_cycles: 0,
857 wait_retry: 0xffff,
858 match_retry: 0,
859 })?;
860
861 if self.active_protocol() == Some(WireProtocol::Jtag) {
862 } else {
868 self.configure_swd(swd::configure::ConfigureRequest {})?;
869 }
870
871 let _: Result<HostStatusResponse, _> =
873 commands::send_command(&mut self.device, &HostStatusRequest::connected(true));
874
875 Ok(())
876 }
877
878 fn detach(&mut self) -> Result<(), crate::Error> {
880 self.process_batch()?;
881
882 if self.swo_active {
883 self.disable_swo()?;
884 }
885
886 let response = commands::send_command(&mut self.device, &DisconnectRequest {})
887 .map_err(DebugProbeError::from)?;
888
889 let request = HostStatusRequest::connected(false);
891 let _: Result<HostStatusResponse, _> = commands::send_command(&mut self.device, &request);
892
893 self.connected = false;
894
895 match response {
896 DisconnectResponse(Status::DapOk) => Ok(()),
897 DisconnectResponse(Status::DapError) => Err(crate::Error::Probe(
898 CmsisDapError::ErrorResponse(RequestError::HostStatus { request }).into(),
899 )),
900 }
901 }
902
903 fn select_protocol(&mut self, protocol: WireProtocol) -> Result<(), DebugProbeError> {
904 match protocol {
905 WireProtocol::Jtag if self.capabilities.jtag_implemented => {
906 self.protocol = Some(WireProtocol::Jtag);
907 Ok(())
908 }
909 WireProtocol::Swd if self.capabilities.swd_implemented => {
910 self.protocol = Some(WireProtocol::Swd);
911 Ok(())
912 }
913 _ => Err(DebugProbeError::UnsupportedProtocol(protocol)),
914 }
915 }
916
917 fn active_protocol(&self) -> Option<WireProtocol> {
918 self.protocol
919 }
920
921 fn target_reset(&mut self) -> Result<(), DebugProbeError> {
923 commands::send_command(&mut self.device, &ResetRequest).map(|v: ResetResponse| {
924 tracing::info!("Target reset response: {:?}", v);
925 })?;
926 Ok(())
927 }
928
929 fn target_reset_assert(&mut self) -> Result<(), DebugProbeError> {
930 let request = SWJPinsRequestBuilder::new().nreset(false).build();
931
932 commands::send_command(&mut self.device, &request).map(|v: SWJPinsResponse| {
933 tracing::info!("Pin response: {:?}", v);
934 })?;
935 Ok(())
936 }
937
938 fn target_reset_deassert(&mut self) -> Result<(), DebugProbeError> {
939 let request = SWJPinsRequestBuilder::new().nreset(true).build();
940
941 commands::send_command(&mut self.device, &request).map(|v: SWJPinsResponse| {
942 tracing::info!("Pin response: {:?}", v);
943 })?;
944 Ok(())
945 }
946
947 fn get_swo_interface(&self) -> Option<&dyn SwoAccess> {
948 Some(self as _)
949 }
950
951 fn get_swo_interface_mut(&mut self) -> Option<&mut dyn SwoAccess> {
952 Some(self as _)
953 }
954
955 fn try_get_arm_debug_interface<'probe>(
956 self: Box<Self>,
957 sequence: Arc<dyn ArmDebugSequence>,
958 ) -> Result<Box<dyn ArmDebugInterface + 'probe>, (Box<dyn DebugProbe>, ArmError)> {
959 Ok(ArmCommunicationInterface::create(self, sequence, false))
960 }
961
962 fn has_arm_interface(&self) -> bool {
963 true
964 }
965
966 fn into_probe(self: Box<Self>) -> Box<dyn DebugProbe> {
967 self
968 }
969
970 fn try_as_jtag_probe(&mut self) -> Option<&mut dyn JtagAccess> {
971 Some(self)
972 }
973
974 fn try_as_dap_probe(&mut self) -> Option<&mut dyn DapProbe> {
975 Some(self)
976 }
977
978 fn has_riscv_interface(&self) -> bool {
979 true
981 }
982
983 fn try_get_riscv_interface_builder<'probe>(
984 &'probe mut self,
985 ) -> Result<Box<dyn RiscvInterfaceBuilder<'probe> + 'probe>, RiscvError> {
986 Ok(Box::new(JtagDtmBuilder::new(self)))
987 }
988
989 fn try_get_xtensa_interface<'probe>(
990 &'probe mut self,
991 state: &'probe mut XtensaDebugInterfaceState,
992 ) -> Result<XtensaCommunicationInterface<'probe>, XtensaError> {
993 Ok(XtensaCommunicationInterface::new(self, state))
994 }
995
996 fn has_xtensa_interface(&self) -> bool {
997 true
998 }
999}
1000
1001impl AutoImplementJtagAccess for CmsisDap {}
1003
1004impl RawDapAccess for CmsisDap {
1005 fn core_status_notification(&mut self, status: CoreStatus) -> Result<(), DebugProbeError> {
1006 let running = status.is_running();
1007 commands::send_command(&mut self.device, &HostStatusRequest::running(running))?;
1008 Ok(())
1009 }
1010
1011 fn raw_read_register(&mut self, address: RegisterAddress) -> Result<u32, ArmError> {
1013 let res = self.batch_add(BatchCommand::Read(address))?;
1014
1015 Ok(res.unwrap())
1018 }
1019
1020 fn raw_write_register(&mut self, address: RegisterAddress, value: u32) -> Result<(), ArmError> {
1022 self.batch_add(BatchCommand::Write(address, value))
1023 .map(|_| ())
1024 }
1025
1026 fn raw_write_block(
1027 &mut self,
1028 address: RegisterAddress,
1029 values: &[u32],
1030 ) -> Result<(), ArmError> {
1031 self.process_batch()?;
1032
1033 let max_packet_size_words = (self.packet_size - 6) / 4;
1044
1045 let data_chunk_len = max_packet_size_words as usize;
1046
1047 for (i, chunk) in values.chunks(data_chunk_len).enumerate() {
1048 let mut request = TransferBlockRequest::write_request(address, Vec::from(chunk));
1049 request.dap_index = self.jtag_state.chain_params.index as u8;
1050
1051 tracing::debug!("Transfer block: chunk={}, len={} bytes", i, chunk.len() * 4);
1052
1053 let resp: TransferBlockResponse = commands::send_command(&mut self.device, &request)
1054 .map_err(DebugProbeError::from)?;
1055
1056 if resp.transfer_response != 1 {
1057 return Err(DebugProbeError::from(CmsisDapError::ErrorResponse(
1058 RequestError::BlockTransfer {
1059 dap_index: request.dap_index,
1060 transfer_count: request.transfer_count,
1061 transfer_request: request.transfer_request,
1062 },
1063 ))
1064 .into());
1065 }
1066 }
1067
1068 Ok(())
1069 }
1070
1071 fn raw_read_block(
1072 &mut self,
1073 address: RegisterAddress,
1074 values: &mut [u32],
1075 ) -> Result<(), ArmError> {
1076 self.process_batch()?;
1077
1078 let max_packet_size_words = (self.packet_size - 6) / 4;
1089
1090 let data_chunk_len = max_packet_size_words as usize;
1091
1092 for (i, chunk) in values.chunks_mut(data_chunk_len).enumerate() {
1093 let mut request = TransferBlockRequest::read_request(address, chunk.len() as u16);
1094 request.dap_index = self.jtag_state.chain_params.index as u8;
1095
1096 tracing::debug!("Transfer block: chunk={}, len={} bytes", i, chunk.len() * 4);
1097
1098 let resp: TransferBlockResponse = commands::send_command(&mut self.device, &request)
1099 .map_err(DebugProbeError::from)?;
1100
1101 if resp.transfer_response != 1 {
1102 return Err(DebugProbeError::from(CmsisDapError::ErrorResponse(
1103 RequestError::BlockTransfer {
1104 dap_index: request.dap_index,
1105 transfer_count: request.transfer_count,
1106 transfer_request: request.transfer_request,
1107 },
1108 ))
1109 .into());
1110 }
1111
1112 chunk.clone_from_slice(&resp.transfer_data[..]);
1113 }
1114
1115 Ok(())
1116 }
1117
1118 fn raw_flush(&mut self) -> Result<(), ArmError> {
1119 self.process_batch()?;
1120 Ok(())
1121 }
1122
1123 fn into_probe(self: Box<Self>) -> Box<dyn DebugProbe> {
1124 self
1125 }
1126
1127 fn configure_jtag(&mut self, skip_scan: bool) -> Result<(), DebugProbeError> {
1128 let ir_lengths = if skip_scan {
1129 self.jtag_state
1130 .expected_scan_chain
1131 .as_ref()
1132 .map(|chain| chain.iter().filter_map(|s| s.ir_len).collect::<Vec<u8>>())
1133 .unwrap_or_default()
1134 } else {
1135 let chain = self.jtag_scan(
1136 self.jtag_state
1137 .expected_scan_chain
1138 .as_ref()
1139 .map(|chain| {
1140 chain
1141 .iter()
1142 .filter_map(|s| s.ir_len)
1143 .map(|s| s as usize)
1144 .collect::<Vec<usize>>()
1145 })
1146 .as_deref(),
1147 )?;
1148 chain.iter().map(|item| item.ir_len()).collect()
1149 };
1150 tracing::info!("Configuring JTAG with ir lengths: {:?}", ir_lengths);
1151 self.send_jtag_configure(JtagConfigureRequest::new(ir_lengths)?)?;
1152
1153 Ok(())
1154 }
1155
1156 fn jtag_sequence(&mut self, cycles: u8, tms: bool, tdi: u64) -> Result<(), DebugProbeError> {
1157 self.connect_if_needed()?;
1158
1159 let tdi_bytes = tdi.to_le_bytes();
1160 let sequence = JtagSequence::new(cycles, false, tms, tdi_bytes)?;
1161 let sequences = vec![sequence];
1162
1163 self.send_jtag_sequences(JtagSequenceRequest::new(sequences)?)?;
1164
1165 Ok(())
1166 }
1167
1168 fn swj_sequence(&mut self, bit_len: u8, bits: u64) -> Result<(), DebugProbeError> {
1169 self.connect_if_needed()?;
1170
1171 let data = bits.to_le_bytes();
1172
1173 if tracing::enabled!(tracing::Level::TRACE) {
1174 let mut seq = String::new();
1175
1176 let _ = write!(&mut seq, "swj sequence:");
1177
1178 for i in 0..bit_len {
1179 let bit = (bits >> i) & 1;
1180
1181 if bit == 1 {
1182 let _ = write!(&mut seq, "1");
1183 } else {
1184 let _ = write!(&mut seq, "0");
1185 }
1186 }
1187 tracing::trace!("{}", seq);
1188 }
1189
1190 self.send_swj_sequences(SequenceRequest::new(&data, bit_len)?)?;
1191
1192 Ok(())
1193 }
1194
1195 fn swj_pins(
1196 &mut self,
1197 pin_out: u32,
1198 pin_select: u32,
1199 pin_wait: u32,
1200 ) -> Result<u32, DebugProbeError> {
1201 self.connect_if_needed()?;
1202
1203 let request = SWJPinsRequest::from_raw_values(pin_out as u8, pin_select as u8, pin_wait);
1204
1205 let Pins(response) = commands::send_command(&mut self.device, &request)?;
1206
1207 Ok(response as u32)
1208 }
1209}
1210
1211impl DapProbe for CmsisDap {}
1212
1213impl SwoAccess for CmsisDap {
1214 fn enable_swo(&mut self, config: &SwoConfig) -> Result<(), ArmError> {
1215 let caps = self.capabilities;
1216
1217 match config.mode() {
1219 SwoMode::Uart if !caps.swo_uart_implemented => {
1220 return Err(ArmError::Probe(CmsisDapError::SwoModeNotAvailable.into()));
1221 }
1222 SwoMode::Manchester if !caps.swo_manchester_implemented => {
1223 return Err(ArmError::Probe(CmsisDapError::SwoModeNotAvailable.into()));
1224 }
1225 _ => (),
1226 }
1227
1228 self.stop_swo_capture()?;
1230
1231 if caps.swo_streaming_trace_implemented && self.device.swo_streaming_supported() {
1235 tracing::debug!("Starting SWO capture with streaming transport");
1236 self.set_swo_transport(swo::TransportRequest::WinUsbEndpoint)?;
1237 self.swo_streaming = true;
1238 } else {
1239 tracing::debug!("Starting SWO capture with polled transport");
1240 self.set_swo_transport(swo::TransportRequest::DataCommand)?;
1241 self.swo_streaming = false;
1242 }
1243
1244 match config.mode() {
1246 SwoMode::Uart => self.set_swo_mode(swo::ModeRequest::Uart)?,
1247 SwoMode::Manchester => self.set_swo_mode(swo::ModeRequest::Manchester)?,
1248 }
1249
1250 let baud = self.set_swo_baudrate(swo::BaudrateRequest {
1252 baudrate: config.baud(),
1253 })?;
1254 if baud != config.baud() {
1255 tracing::warn!(
1256 "Target SWO baud rate not met: requested {}, got {}",
1257 config.baud(),
1258 baud
1259 );
1260 }
1261
1262 self.start_swo_capture()?;
1263
1264 self.swo_active = true;
1265 Ok(())
1266 }
1267
1268 fn disable_swo(&mut self) -> Result<(), ArmError> {
1269 tracing::debug!("Stopping SWO capture");
1270 self.stop_swo_capture()?;
1271 self.swo_active = false;
1272 Ok(())
1273 }
1274
1275 fn read_swo_timeout(&mut self, timeout: Duration) -> Result<Vec<u8>, ArmError> {
1276 if self.swo_active {
1277 if self.swo_streaming {
1278 let buffer = self
1279 .device
1280 .read_swo_stream(timeout)
1281 .map_err(DebugProbeError::from)?;
1282 tracing::trace!("SWO streaming buffer: {:?}", buffer);
1283 Ok(buffer)
1284 } else {
1285 let data = self.get_swo_data()?;
1286 tracing::trace!("SWO polled data: {:?}", data);
1287 Ok(data)
1288 }
1289 } else {
1290 Ok(Vec::new())
1291 }
1292 }
1293
1294 fn swo_poll_interval_hint(&mut self, config: &SwoConfig) -> Option<Duration> {
1295 let caps = self.capabilities;
1296 if caps.swo_streaming_trace_implemented && self.device.swo_streaming_supported() {
1297 Some(Duration::from_secs(0))
1299 } else {
1300 match self.swo_buffer_size {
1301 Some(buf_size) => poll_interval_from_buf_size(config, buf_size),
1303
1304 None => None,
1306 }
1307 }
1308 }
1309
1310 fn swo_buffer_size(&mut self) -> Option<usize> {
1311 self.swo_buffer_size
1312 }
1313}
1314
1315impl Drop for CmsisDap {
1316 fn drop(&mut self) {
1317 tracing::debug!("Detaching from CMSIS-DAP probe");
1318 let _ = self.process_batch();
1320
1321 if self.swo_active {
1324 let _ = self.disable_swo();
1325 }
1326
1327 let _ = self.detach();
1328 }
1329}
1330
1331impl From<ScanChainError> for CmsisDapError {
1332 fn from(error: ScanChainError) -> Self {
1333 match error {
1334 ScanChainError::InvalidIdCode => CmsisDapError::InvalidIdCode,
1335 ScanChainError::InvalidIR => CmsisDapError::InvalidIR,
1336 }
1337 }
1338}