Skip to main content

probe_rs/probe/cmsisdap/
mod.rs

1//! CMSIS-DAP probe implementation.
2mod 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, DebugProbeSelector,
26        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/// A factory for creating [`CmsisDap`] probes.
72#[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<crate::probe::list::ProbeListItem> {
89        tools::list_cmsisdap_devices()
90    }
91}
92
93/// A CMSIS-DAP probe.
94pub 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 in kHz
109    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        // Discard anything left in buffer, as otherwise
135        // we'll get out of sync between requests and responses.
136        device.drain();
137
138        // Determine and set the packet size. We do this as soon as possible after
139        // opening the probe to ensure all future communication uses the correct size.
140        let packet_size = device.find_packet_size()? as u16;
141
142        // Read remaining probe information.
143        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    /// Set maximum JTAG/SWD clock frequency to use, in Hz.
173    ///
174    /// The actual clock frequency used by the device might be lower.
175    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    /// Reset JTAG state machine to Test-Logic-Reset.
207    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    /// Reset JTAG state machine to Run-Test/Idle, as requisite precondition for DAP_Transfer commands.
217    fn jtag_ensure_run_test_idle(&mut self) -> Result<(), CmsisDapError> {
218        // These could be coalesced into one sequence request, but for now we'll keep things simple.
219
220        // First reach Test-Logic-Reset
221        self.jtag_ensure_test_logic_reset()?;
222
223        // Then transition to Run-Test-Idle
224        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    /// Scan JTAG chain, detecting TAPs and their IDCODEs and IR lengths.
232    ///
233    /// If IR lengths for each TAP are known, provide them in `ir_lengths`.
234    ///
235    /// Returns a new JTAG chain.
236    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    /// Capture the power-up scan chain values, including all IDCODEs.
255    ///
256    /// Returns the IR and DR results as (IR, DR).
257    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        // Return to Run-Test/Idle, so the probe is ready for DAP_Transfer commands again.
262        self.jtag_ensure_run_test_idle()?;
263
264        Ok((ir, dr))
265    }
266
267    /// Detect the IR chain length and return its current contents.
268    ///
269    /// Replaces the current contents with all 1s (BYPASS) and enters
270    /// the Run-Test/Idle state.
271    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    /// Detect the DR chain length and return its contents.
278    ///
279    /// Replaces the current contents with all 1s and enters
280    /// the Run-Test/Idle state.
281    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    /// Detect current chain length and return its contents.
288    /// Must already be in either Shift-IR or Shift-DR state.
289    fn jtag_scan_inner(&mut self, name: &'static str) -> Result<BitVec, CmsisDapError> {
290        // Max scan chain length (in bits) to attempt to detect.
291        const MAX_LENGTH: usize = 128;
292        // How many bytes to write out / read in per request.
293        const BYTES_PER_REQUEST: usize = 16;
294        // How many requests are needed to read/write at least MAX_LENGTH bits.
295        const REQUESTS: usize = MAX_LENGTH.div_ceil(BYTES_PER_REQUEST * 8);
296
297        // Completely fill xR with 0s, capture result.
298        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        // Completely fill xR with 1s, capture result.
312        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        // Find first 1 in d1, which indicates length of register.
326        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        // Check at least one register is detected in the scan chain.
343        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        // Check d0[n..] are all 0.
351        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        // Extract d0[..n] as the initial scan chain contents.
362        let data = d0[..n].to_bitvec();
363
364        Ok(data)
365    }
366
367    fn jtag_ensure_shift_dr(&mut self) -> Result<(), CmsisDapError> {
368        // Transition to Test-Logic-Reset.
369        self.jtag_ensure_test_logic_reset()?;
370
371        // Transition to Shift-DR
372        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        // Transition to Test-Logic-Reset.
384        self.jtag_ensure_test_logic_reset()?;
385
386        // Transition to Shift-IR
387        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        // Ensure all pending commands are processed.
422        //self.process_batch()?;
423
424        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    /// Read the CTRL register from the currently selected debug port.
435    ///
436    /// According to the ARM specification, this *should* never fail.
437    /// In practice, it can unfortunately happen.
438    ///
439    /// To avoid an endless recursion in this cases, this function is provided
440    /// as an alternative to [`Self::process_batch()`]. This function will return any errors,
441    /// and not retry any transfers.
442    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        // We can assume that the single transfer is always executed,
449        // no need to check here.
450
451        if response.last_transfer_response.protocol_error {
452            // TODO: What does this protocol error mean exactly?
453            //       Should be verified in CMSIS-DAP spec
454            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        // We can assume that the single transfer is always executed,
487        // no need to check here.
488
489        if response.last_transfer_response.protocol_error {
490            // TODO: What does this protocol error mean exactly?
491            //       Should be verified in CMSIS-DAP spec
492            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    // Reads the CTRL/STAT register, and clears the sticky error flag if is set (or if the read
508    // faults, which shouldn't happen, but is observed to happen on some PSOC devices).
509    fn handle_sticky_err(&mut self) -> Result<(), ArmError> {
510        let ctrl = self.read_ctrl_register();
511        tracing::trace!("Ctrl/Stat register value is: {:?}", ctrl);
512
513        match ctrl {
514            Ok(ctrl) if !ctrl.sticky_err() => Ok(()),
515            Ok(_) | Err(ArmError::Dap(DapError::FaultResponse)) => {
516                // Clear sticky error flags.
517                self.write_abort({
518                    let mut abort = Abort(0);
519                    abort.set_stkerrclr(true);
520                    abort
521                })
522            }
523            Err(e) => Err(e),
524        }
525    }
526
527    /// Immediately send whatever is in our batch if it is not empty.
528    ///
529    /// If the last transfer was a read, result is Some with the read value.
530    /// Otherwise, the result is None.
531    ///
532    /// This will ensure any pending writes are processed and errors from them
533    /// raised if necessary.
534    #[tracing::instrument(skip(self))]
535    fn process_batch(&mut self) -> Result<Option<u32>, ArmError> {
536        let batch = std::mem::take(&mut self.batch);
537        if batch.is_empty() {
538            return Ok(None);
539        }
540
541        tracing::debug!("{} items in batch", batch.len());
542
543        let mut transfers = TransferRequest::empty();
544        transfers.dap_index = self.jtag_state.chain_params.index as u8;
545        for command in batch.iter().cloned() {
546            match command {
547                BatchCommand::Read(port) => {
548                    transfers.add_read(port);
549                }
550                BatchCommand::Write(port, value) => {
551                    transfers.add_write(port, value);
552                }
553            }
554        }
555
556        let response =
557            commands::send_command(&mut self.device, &transfers).map_err(DebugProbeError::from)?;
558
559        let count = response.transfers.len();
560
561        tracing::debug!("{} of batch of {} items executed", count, batch.len());
562
563        if response.last_transfer_response.protocol_error {
564            tracing::warn!(
565                "Protocol error in response to command {}",
566                batch[count.saturating_sub(1)]
567            );
568
569            return Err(DapError::Protocol(
570                self.protocol
571                    .expect("A wire protocol should have been selected by now"),
572            )
573            .into());
574        }
575
576        match response.last_transfer_response.ack {
577            Ack::Ok => {
578                // If less transfers than expected were executed, this
579                // is not the response to the latest command from the batch.
580                //
581                // According to the CMSIS-DAP specification, this shouldn't happen,
582                // the only time when not all transfers were executed is when an error occurred.
583                // Still, this seems to happen in practice.
584
585                if count < batch.len() {
586                    tracing::warn!(
587                        "CMSIS_DAP: Only {}/{} transfers were executed, but no error was reported.",
588                        count,
589                        batch.len()
590                    );
591                    return Err(DebugProbeError::Other(format!(
592                        "Possible error in CMSIS-DAP probe: Only {}/{} transfers were executed, but no error was reported.",
593                        count,
594                        batch.len()
595                    )).into());
596                }
597
598                tracing::trace!("Last transfer status: ACK");
599                Ok(response.transfers[count - 1].data)
600            }
601            Ack::NoAck => {
602                tracing::debug!(
603                    "Transfer status for batch item {}/{}: NACK",
604                    count,
605                    batch.len()
606                );
607                // TODO: Try a reset?
608                Err(DapError::NoAcknowledge.into())
609            }
610            Ack::Fault => {
611                tracing::debug!(
612                    "Transfer status for batch item {}/{}: FAULT",
613                    count,
614                    batch.len()
615                );
616
617                // To avoid a potential endless recursion,
618                // call a separate function to read the ctrl register,
619                // which doesn't use the batch API.
620                self.handle_sticky_err()?;
621
622                Err(DapError::FaultResponse.into())
623            }
624            Ack::Wait => {
625                tracing::debug!(
626                    "Transfer status for batch item {}/{}: WAIT",
627                    count,
628                    batch.len()
629                );
630
631                self.write_abort({
632                    let mut abort = Abort(0);
633                    abort.set_dapabort(true);
634                    abort
635                })?;
636
637                Err(DapError::WaitResponse.into())
638            }
639        }
640    }
641
642    /// Add a BatchCommand to our current batch.
643    ///
644    /// If the BatchCommand is a Read, this will immediately process the batch
645    /// and return the read value. If the BatchCommand is a write, the write is
646    /// executed immediately if the batch is full, otherwise it is queued for
647    /// later execution.
648    fn batch_add(&mut self, command: BatchCommand) -> Result<Option<u32>, ArmError> {
649        tracing::debug!("Adding command to batch: {}", command);
650
651        let command_is_read = matches!(command, BatchCommand::Read(_));
652        self.batch.push(command);
653
654        // We always immediately process any reads, which means there will never
655        // be more than one read in a batch. We also process whenever the batch
656        // is as long as can fit in one packet.
657        let max_writes = (self.packet_size as usize - 3) / (1 + 4);
658        if command_is_read || self.batch.len() == max_writes {
659            self.process_batch()
660        } else {
661            Ok(None)
662        }
663    }
664
665    /// Set SWO port to use requested transport.
666    ///
667    /// Check the probe capabilities to determine which transports are available.
668    fn set_swo_transport(
669        &mut self,
670        transport: swo::TransportRequest,
671    ) -> Result<(), DebugProbeError> {
672        let response = commands::send_command(&mut self.device, &transport)?;
673        match response.status {
674            Status::DapOk => Ok(()),
675            Status::DapError => {
676                Err(CmsisDapError::ErrorResponse(RequestError::SwoTransport { transport }).into())
677            }
678        }
679    }
680
681    /// Set SWO port to specified mode.
682    ///
683    /// Check the probe capabilities to determine which modes are available.
684    fn set_swo_mode(&mut self, mode: swo::ModeRequest) -> Result<(), DebugProbeError> {
685        let response = commands::send_command(&mut self.device, &mode)?;
686        match response.status {
687            Status::DapOk => Ok(()),
688            Status::DapError => {
689                Err(CmsisDapError::ErrorResponse(RequestError::SwoMode { mode }).into())
690            }
691        }
692    }
693
694    /// Set SWO port to specified baud rate.
695    ///
696    /// Returns `SwoBaudrateNotConfigured` if the probe returns 0,
697    /// indicating the requested baud rate was not configured,
698    /// and returns the configured baud rate on success (which
699    /// may differ from the requested baud rate).
700    fn set_swo_baudrate(&mut self, request: swo::BaudrateRequest) -> Result<u32, DebugProbeError> {
701        let response = commands::send_command(&mut self.device, &request)?;
702        tracing::debug!("Requested baud {}, got {}", request.baudrate, response);
703        if response == 0 {
704            Err(CmsisDapError::SwoBaudrateNotConfigured.into())
705        } else {
706            Ok(response)
707        }
708    }
709
710    /// Start SWO trace data capture.
711    fn start_swo_capture(&mut self) -> Result<(), DebugProbeError> {
712        let command = swo::ControlRequest::Start;
713        let response = commands::send_command(&mut self.device, &command)?;
714        match response.status {
715            Status::DapOk => Ok(()),
716            Status::DapError => {
717                Err(CmsisDapError::ErrorResponse(RequestError::SwoControl { command }).into())
718            }
719        }
720    }
721
722    /// Stop SWO trace data capture.
723    fn stop_swo_capture(&mut self) -> Result<(), DebugProbeError> {
724        let command = swo::ControlRequest::Stop;
725        let response = commands::send_command(&mut self.device, &command)?;
726        match response.status {
727            Status::DapOk => Ok(()),
728            Status::DapError => {
729                Err(CmsisDapError::ErrorResponse(RequestError::SwoControl { command }).into())
730            }
731        }
732    }
733
734    /// Fetch current SWO trace status.
735    #[expect(dead_code)]
736    fn get_swo_status(&mut self) -> Result<swo::StatusResponse, DebugProbeError> {
737        Ok(commands::send_command(
738            &mut self.device,
739            &swo::StatusRequest,
740        )?)
741    }
742
743    /// Fetch extended SWO trace status.
744    ///
745    /// request.request_status: request trace status
746    /// request.request_count: request remaining bytes in trace buffer
747    /// request.request_index: request sequence number and timestamp of next trace sequence
748    #[expect(dead_code)]
749    fn get_swo_extended_status(
750        &mut self,
751        request: swo::ExtendedStatusRequest,
752    ) -> Result<swo::ExtendedStatusResponse, DebugProbeError> {
753        Ok(commands::send_command(&mut self.device, &request)?)
754    }
755
756    /// Fetch latest SWO trace data by sending a DAP_SWO_Data request.
757    fn get_swo_data(&mut self) -> Result<Vec<u8>, DebugProbeError> {
758        match self.swo_buffer_size {
759            Some(swo_buffer_size) => {
760                // We'll request the smaller of the probe's SWO buffer and
761                // its maximum packet size. If the probe has less data to
762                // send it will respond with as much as it can.
763                let n = usize::min(swo_buffer_size, self.packet_size as usize) as u16;
764
765                let response: swo::DataResponse =
766                    commands::send_command(&mut self.device, &swo::DataRequest { max_count: n })?;
767                if response.status.error {
768                    Err(CmsisDapError::SwoTraceStreamError.into())
769                } else {
770                    Ok(response.data)
771                }
772            }
773            None => Ok(Vec::new()),
774        }
775    }
776
777    fn connect_if_needed(&mut self) -> Result<(), DebugProbeError> {
778        if self.connected {
779            return Ok(());
780        }
781
782        let protocol: ConnectRequest = if let Some(protocol) = self.protocol {
783            match protocol {
784                WireProtocol::Swd => ConnectRequest::Swd,
785                WireProtocol::Jtag => ConnectRequest::Jtag,
786            }
787        } else {
788            ConnectRequest::DefaultPort
789        };
790
791        let used_protocol =
792            commands::send_command(&mut self.device, &protocol).and_then(|v| match v {
793                ConnectResponse::SuccessfulInitForSWD => Ok(WireProtocol::Swd),
794                ConnectResponse::SuccessfulInitForJTAG => Ok(WireProtocol::Jtag),
795                ConnectResponse::InitFailed => {
796                    Err(CmsisDapError::ErrorResponse(RequestError::InitFailed {
797                        protocol: self.protocol,
798                    }))
799                }
800            })?;
801
802        // Store the actually used protocol, to handle cases where the default protocol is used.
803        tracing::info!("Using protocol {}", used_protocol);
804        self.protocol = Some(used_protocol);
805
806        // If operating under JTAG, try to bring the JTAG machinery out of reset. Ignore errors
807        // since not all probes support this.
808        if matches!(self.protocol, Some(WireProtocol::Jtag)) {
809            commands::send_command(
810                &mut self.device,
811                &SWJPinsRequestBuilder::new().ntrst(true).build(),
812            )
813            .ok();
814        }
815        self.connected = true;
816
817        Ok(())
818    }
819
820    fn handle_transfer_block_response(
821        &mut self,
822        address: RegisterAddress,
823        resp: &TransferBlockResponse,
824        executed_transfers: usize,
825        total_transfers: usize,
826    ) -> Result<(), ArmError> {
827        if resp.transfer_response.protocol_error {
828            tracing::warn!(
829                "Protocol error in block read from register {:?}, read {}/{}",
830                address,
831                executed_transfers,
832                total_transfers,
833            );
834
835            // TODO: Indicate which transfer failed
836            return Err(
837                DapError::Protocol(self.protocol.expect("Protocol has been selected")).into(),
838            );
839        }
840
841        match resp.transfer_response.ack {
842            // TODO: Handle this the same way as process_batch
843            Ack::Ok => Ok(()),
844            Ack::Fault => {
845                // TODO: Perform error handling -> clear fault, etc.
846                //
847                // TODO: Properly track what exactly failed
848                tracing::debug!(
849                    "FAULT response in block read from register {:?}, read {}/{}",
850                    address,
851                    executed_transfers,
852                    total_transfers,
853                );
854
855                // To avoid a potential endless recursion,
856                // call a separate function to read the ctrl register,
857                // which doesn't use the batch API.
858                self.handle_sticky_err()?;
859
860                Err(DapError::FaultResponse.into())
861            }
862            Ack::NoAck => {
863                // TODO: Perform error handling -> clear fault, etc.
864                //
865                // TODO: Properly track what exactly failed
866                tracing::debug!(
867                    "NACK response in block read from register {:?}, read {}/{}",
868                    address,
869                    executed_transfers,
870                    total_transfers
871                );
872                // TODO: Try a reset?
873                Err(DapError::NoAcknowledge.into())
874            }
875            Ack::Wait => {
876                // TODO: Perform error handling -> clear fault, etc.
877                //
878                // TODO: Properly track what exactly failed
879                tracing::debug!(
880                    "WAIT response in block read from register {:?}, read {}/{}",
881                    address,
882                    executed_transfers,
883                    total_transfers
884                );
885
886                self.write_abort({
887                    let mut abort = Abort(0);
888                    abort.set_dapabort(true);
889                    abort
890                })?;
891
892                Err(DapError::WaitResponse.into())
893            }
894        }
895    }
896}
897
898impl DebugProbe for CmsisDap {
899    fn get_name(&self) -> &str {
900        match &self.device {
901            CmsisDapDevice::V2 { handle, .. } => format!(
902                "CMSIS-DAP V2 IF: {} DESC: {:?}",
903                handle.interface_number(),
904                handle.descriptor()
905            )
906            .leak(),
907
908            #[cfg(feature = "cmsisdap_v1")]
909            _ => "CMSIS-DAP V1",
910        }
911    }
912
913    /// Get the currently set maximum speed.
914    ///
915    /// CMSIS-DAP offers no possibility to get the actual speed used.
916    fn speed_khz(&self) -> u32 {
917        self.speed_khz
918    }
919
920    /// For CMSIS-DAP, we can set the maximum speed. The actual speed
921    /// used by the probe cannot be determined, but it will not be
922    /// higher than this value.
923    fn set_speed(&mut self, speed_khz: u32) -> Result<u32, DebugProbeError> {
924        self.set_swj_clock(speed_khz * 1_000)?;
925        self.speed_khz = speed_khz;
926
927        Ok(speed_khz)
928    }
929
930    /// Enters debug mode.
931    #[tracing::instrument(skip(self))]
932    fn attach(&mut self) -> Result<(), DebugProbeError> {
933        tracing::debug!("Attaching to target system (clock = {}kHz)", self.speed_khz);
934
935        // Run connect sequence (may already be done earlier via swj operations)
936        self.connect_if_needed()?;
937
938        // Set speed after connecting as it can be reset during protocol selection
939        self.set_speed(self.speed_khz)?;
940
941        self.transfer_configure(ConfigureRequest {
942            idle_cycles: 0,
943            wait_retry: 0xffff,
944            match_retry: 0,
945        })?;
946
947        if self.active_protocol() == Some(WireProtocol::Jtag) {
948            // no-op: we configure JTAG in debug_port_setup,
949            // because that is where we execute the SWJ-DP Switch Sequence
950            // to ensure the debug port is ready for JTAG signals,
951            // at which point we can interrogate the scan chain
952            // and configure the probe with the given IR lengths.
953        } else {
954            self.configure_swd(swd::configure::ConfigureRequest {})?;
955        }
956
957        // Tell the probe we are connected so it can turn on an LED.
958        let _: Result<HostStatusResponse, _> =
959            commands::send_command(&mut self.device, &HostStatusRequest::connected(true));
960
961        Ok(())
962    }
963
964    /// Leave debug mode.
965    fn detach(&mut self) -> Result<(), crate::Error> {
966        self.process_batch()?;
967
968        if self.swo_active {
969            self.disable_swo()?;
970        }
971
972        let response = commands::send_command(&mut self.device, &DisconnectRequest {})
973            .map_err(DebugProbeError::from)?;
974
975        // Tell probe we are disconnected so it can turn off its LED.
976        let request = HostStatusRequest::connected(false);
977        let _: Result<HostStatusResponse, _> = commands::send_command(&mut self.device, &request);
978
979        self.connected = false;
980
981        match response {
982            DisconnectResponse(Status::DapOk) => Ok(()),
983            DisconnectResponse(Status::DapError) => Err(crate::Error::Probe(
984                CmsisDapError::ErrorResponse(RequestError::HostStatus { request }).into(),
985            )),
986        }
987    }
988
989    fn select_protocol(&mut self, protocol: WireProtocol) -> Result<(), DebugProbeError> {
990        match protocol {
991            WireProtocol::Jtag if self.capabilities.jtag_implemented => {
992                self.protocol = Some(WireProtocol::Jtag);
993                Ok(())
994            }
995            WireProtocol::Swd if self.capabilities.swd_implemented => {
996                self.protocol = Some(WireProtocol::Swd);
997                Ok(())
998            }
999            _ => Err(DebugProbeError::UnsupportedProtocol(protocol)),
1000        }
1001    }
1002
1003    fn active_protocol(&self) -> Option<WireProtocol> {
1004        self.protocol
1005    }
1006
1007    /// Asserts the nRESET pin.
1008    fn target_reset(&mut self) -> Result<(), DebugProbeError> {
1009        commands::send_command(&mut self.device, &ResetRequest).map(|v: ResetResponse| {
1010            tracing::info!("Target reset response: {:?}", v);
1011        })?;
1012        Ok(())
1013    }
1014
1015    fn target_reset_assert(&mut self) -> Result<(), DebugProbeError> {
1016        let request = SWJPinsRequestBuilder::new().nreset(false).build();
1017
1018        commands::send_command(&mut self.device, &request).map(|v: SWJPinsResponse| {
1019            tracing::info!("Pin response: {:?}", v);
1020        })?;
1021        Ok(())
1022    }
1023
1024    fn target_reset_deassert(&mut self) -> Result<(), DebugProbeError> {
1025        let request = SWJPinsRequestBuilder::new().nreset(true).build();
1026
1027        commands::send_command(&mut self.device, &request).map(|v: SWJPinsResponse| {
1028            tracing::info!("Pin response: {:?}", v);
1029        })?;
1030        Ok(())
1031    }
1032
1033    fn get_swo_interface(&self) -> Option<&dyn SwoAccess> {
1034        Some(self as _)
1035    }
1036
1037    fn get_swo_interface_mut(&mut self) -> Option<&mut dyn SwoAccess> {
1038        Some(self as _)
1039    }
1040
1041    fn try_get_arm_debug_interface<'probe>(
1042        self: Box<Self>,
1043        sequence: Arc<dyn ArmDebugSequence>,
1044    ) -> Result<Box<dyn ArmDebugInterface + 'probe>, (Box<dyn DebugProbe>, ArmError)> {
1045        Ok(ArmCommunicationInterface::create(self, sequence, false))
1046    }
1047
1048    fn has_arm_interface(&self) -> bool {
1049        true
1050    }
1051
1052    fn into_probe(self: Box<Self>) -> Box<dyn DebugProbe> {
1053        self
1054    }
1055
1056    fn try_as_jtag_probe(&mut self) -> Option<&mut dyn JtagAccess> {
1057        Some(self)
1058    }
1059
1060    fn try_as_dap_probe(&mut self) -> Option<&mut dyn DapProbe> {
1061        Some(self)
1062    }
1063
1064    fn has_riscv_interface(&self) -> bool {
1065        // This probe is intended for RISC-V.
1066        true
1067    }
1068
1069    fn try_get_riscv_interface_builder<'probe>(
1070        &'probe mut self,
1071    ) -> Result<Box<dyn RiscvInterfaceBuilder<'probe> + 'probe>, RiscvError> {
1072        Ok(Box::new(JtagDtmBuilder::new(self)))
1073    }
1074
1075    fn try_get_xtensa_interface<'probe>(
1076        &'probe mut self,
1077        state: &'probe mut XtensaDebugInterfaceState,
1078    ) -> Result<XtensaCommunicationInterface<'probe>, XtensaError> {
1079        Ok(XtensaCommunicationInterface::new(self, state))
1080    }
1081
1082    fn has_xtensa_interface(&self) -> bool {
1083        true
1084    }
1085}
1086
1087// TODO: we will want to replace the default implementation with one that can use vendor extensions.
1088impl AutoImplementJtagAccess for CmsisDap {}
1089
1090impl RawDapAccess for CmsisDap {
1091    fn core_status_notification(&mut self, status: CoreStatus) -> Result<(), DebugProbeError> {
1092        let running = status.is_running();
1093        commands::send_command(&mut self.device, &HostStatusRequest::running(running))?;
1094        Ok(())
1095    }
1096
1097    /// Reads the DAP register on the specified port and address.
1098    fn raw_read_register(&mut self, address: RegisterAddress) -> Result<u32, ArmError> {
1099        let res = self.batch_add(BatchCommand::Read(address))?;
1100
1101        // batch_add processes the batch immediately for a read, so a successful call
1102        // returns the read value. A None here means the probe returned a response that
1103        // didn't contain the read data - report it instead of panicking.
1104        res.ok_or_else(|| {
1105            DebugProbeError::Other("CMSIS-DAP read did not return any data".to_string()).into()
1106        })
1107    }
1108
1109    /// Writes a value to the DAP register on the specified port and address.
1110    fn raw_write_register(&mut self, address: RegisterAddress, value: u32) -> Result<(), ArmError> {
1111        self.batch_add(BatchCommand::Write(address, value))
1112            .map(|_| ())
1113    }
1114
1115    fn raw_write_block(
1116        &mut self,
1117        address: RegisterAddress,
1118        values: &[u32],
1119    ) -> Result<(), ArmError> {
1120        self.process_batch()?;
1121
1122        // the overhead for a single packet is 6 bytes
1123        //
1124        // [0]: HID overhead
1125        // [1]: Category
1126        // [2]: DAP Index
1127        // [3]: Len 1
1128        // [4]: Len 2
1129        // [5]: Request type
1130        //
1131
1132        let max_packet_size_words = (self.packet_size - 6) / 4;
1133
1134        let data_chunk_len = max_packet_size_words as usize;
1135
1136        let total_writes = values.len();
1137
1138        for (i, chunk) in values.chunks(data_chunk_len).enumerate() {
1139            let mut request = TransferBlockRequest::write_request(address, Vec::from(chunk));
1140            request.dap_index = self.jtag_state.chain_params.index as u8;
1141
1142            tracing::debug!("Transfer block: chunk={}, len={} bytes", i, chunk.len() * 4);
1143
1144            let resp: TransferBlockResponse = commands::send_command(&mut self.device, &request)
1145                .map_err(DebugProbeError::from)?;
1146
1147            let executed_writes = i * data_chunk_len + usize::from(resp.transfer_count);
1148
1149            self.handle_transfer_block_response(address, &resp, executed_writes, total_writes)?;
1150        }
1151
1152        Ok(())
1153    }
1154
1155    fn raw_read_block(
1156        &mut self,
1157        address: RegisterAddress,
1158        values: &mut [u32],
1159    ) -> Result<(), ArmError> {
1160        self.process_batch()?;
1161
1162        // the overhead for a single packet is 6 bytes
1163        //
1164        // [0]: HID overhead
1165        // [1]: Category
1166        // [2]: DAP Index
1167        // [3]: Len 1
1168        // [4]: Len 2
1169        // [5]: Request type
1170        //
1171
1172        let max_packet_size_words = (self.packet_size - 6) / 4;
1173
1174        let data_chunk_len = max_packet_size_words as usize;
1175
1176        let total_num_reads = values.len();
1177
1178        for (i, chunk) in values.chunks_mut(data_chunk_len).enumerate() {
1179            let mut request = TransferBlockRequest::read_request(address, chunk.len() as u16);
1180            request.dap_index = self.jtag_state.chain_params.index as u8;
1181
1182            tracing::debug!("Transfer block: chunk={}, len={} bytes", i, chunk.len() * 4);
1183
1184            let resp: TransferBlockResponse = commands::send_command(&mut self.device, &request)
1185                .map_err(DebugProbeError::from)?;
1186
1187            let executed_reads = i * data_chunk_len + usize::from(resp.transfer_count);
1188
1189            self.handle_transfer_block_response(address, &resp, executed_reads, total_num_reads)?;
1190
1191            chunk.clone_from_slice(&resp.transfer_data[..]);
1192        }
1193
1194        Ok(())
1195    }
1196
1197    fn raw_flush(&mut self) -> Result<(), ArmError> {
1198        self.process_batch()?;
1199        Ok(())
1200    }
1201
1202    fn into_probe(self: Box<Self>) -> Box<dyn DebugProbe> {
1203        self
1204    }
1205
1206    fn configure_jtag(&mut self, skip_scan: bool) -> Result<(), DebugProbeError> {
1207        let ir_lengths = if skip_scan {
1208            self.jtag_state
1209                .expected_scan_chain
1210                .as_ref()
1211                .map(|chain| chain.iter().filter_map(|s| s.ir_len).collect::<Vec<u8>>())
1212                .unwrap_or_default()
1213        } else {
1214            let chain = self.jtag_scan(
1215                self.jtag_state
1216                    .expected_scan_chain
1217                    .as_ref()
1218                    .map(|chain| {
1219                        chain
1220                            .iter()
1221                            .filter_map(|s| s.ir_len)
1222                            .map(|s| s as usize)
1223                            .collect::<Vec<usize>>()
1224                    })
1225                    .as_deref(),
1226            )?;
1227            chain.iter().map(|item| item.ir_len()).collect()
1228        };
1229        tracing::info!("Configuring JTAG with ir lengths: {:?}", ir_lengths);
1230        self.send_jtag_configure(JtagConfigureRequest::new(ir_lengths)?)?;
1231
1232        Ok(())
1233    }
1234
1235    fn jtag_sequence(&mut self, cycles: u8, tms: bool, tdi: u64) -> Result<(), DebugProbeError> {
1236        self.connect_if_needed()?;
1237
1238        let tdi_bytes = tdi.to_le_bytes();
1239        let sequence = JtagSequence::new(cycles, false, tms, tdi_bytes)?;
1240        let sequences = vec![sequence];
1241
1242        self.send_jtag_sequences(JtagSequenceRequest::new(sequences)?)?;
1243
1244        Ok(())
1245    }
1246
1247    fn swj_sequence(&mut self, bit_len: u8, bits: u64) -> Result<(), DebugProbeError> {
1248        self.connect_if_needed()?;
1249
1250        let data = bits.to_le_bytes();
1251
1252        if tracing::enabled!(tracing::Level::TRACE) {
1253            let mut seq = String::new();
1254
1255            let _ = write!(&mut seq, "swj sequence:");
1256
1257            for i in 0..bit_len {
1258                let bit = (bits >> i) & 1;
1259
1260                if bit == 1 {
1261                    let _ = write!(&mut seq, "1");
1262                } else {
1263                    let _ = write!(&mut seq, "0");
1264                }
1265            }
1266            tracing::trace!("{}", seq);
1267        }
1268
1269        self.send_swj_sequences(SequenceRequest::new(&data, bit_len)?)?;
1270
1271        Ok(())
1272    }
1273
1274    fn swj_pins(
1275        &mut self,
1276        pin_out: u32,
1277        pin_select: u32,
1278        pin_wait: u32,
1279    ) -> Result<u32, DebugProbeError> {
1280        self.connect_if_needed()?;
1281
1282        let request = SWJPinsRequest::from_raw_values(pin_out as u8, pin_select as u8, pin_wait);
1283
1284        let Pins(response) = commands::send_command(&mut self.device, &request)?;
1285
1286        Ok(response as u32)
1287    }
1288}
1289
1290impl DapProbe for CmsisDap {}
1291
1292impl SwoAccess for CmsisDap {
1293    fn enable_swo(&mut self, config: &SwoConfig) -> Result<(), ArmError> {
1294        let caps = self.capabilities;
1295
1296        // Check requested mode is available in probe capabilities
1297        match config.mode() {
1298            SwoMode::Uart if !caps.swo_uart_implemented => {
1299                return Err(ArmError::Probe(CmsisDapError::SwoModeNotAvailable.into()));
1300            }
1301            SwoMode::Manchester if !caps.swo_manchester_implemented => {
1302                return Err(ArmError::Probe(CmsisDapError::SwoModeNotAvailable.into()));
1303            }
1304            _ => (),
1305        }
1306
1307        // Stop any ongoing trace
1308        self.stop_swo_capture()?;
1309
1310        // Set transport. If the dedicated endpoint is available and we have opened
1311        // the probe in V2 mode and it has an SWO endpoint, request that, otherwise
1312        // request the DAP_SWO_Data polling mode.
1313        if caps.swo_streaming_trace_implemented && self.device.swo_streaming_supported() {
1314            tracing::debug!("Starting SWO capture with streaming transport");
1315            self.set_swo_transport(swo::TransportRequest::WinUsbEndpoint)?;
1316            self.swo_streaming = true;
1317        } else {
1318            tracing::debug!("Starting SWO capture with polled transport");
1319            self.set_swo_transport(swo::TransportRequest::DataCommand)?;
1320            self.swo_streaming = false;
1321        }
1322
1323        // Set mode. We've already checked that the requested mode is listed as supported.
1324        match config.mode() {
1325            SwoMode::Uart => self.set_swo_mode(swo::ModeRequest::Uart)?,
1326            SwoMode::Manchester => self.set_swo_mode(swo::ModeRequest::Manchester)?,
1327        }
1328
1329        // Set baud rate.
1330        let baud = self.set_swo_baudrate(swo::BaudrateRequest {
1331            baudrate: config.baud(),
1332        })?;
1333        if baud != config.baud() {
1334            tracing::warn!(
1335                "Target SWO baud rate not met: requested {}, got {}",
1336                config.baud(),
1337                baud
1338            );
1339        }
1340
1341        self.start_swo_capture()?;
1342
1343        self.swo_active = true;
1344        Ok(())
1345    }
1346
1347    fn disable_swo(&mut self) -> Result<(), ArmError> {
1348        tracing::debug!("Stopping SWO capture");
1349        self.stop_swo_capture()?;
1350        self.swo_active = false;
1351        Ok(())
1352    }
1353
1354    fn read_swo_timeout(&mut self, timeout: Duration) -> Result<Vec<u8>, ArmError> {
1355        if self.swo_active {
1356            if self.swo_streaming {
1357                let buffer = self
1358                    .device
1359                    .read_swo_stream(timeout)
1360                    .map_err(DebugProbeError::from)?;
1361                tracing::trace!("SWO streaming buffer: {:?}", buffer);
1362                Ok(buffer)
1363            } else {
1364                let data = self.get_swo_data()?;
1365                tracing::trace!("SWO polled data: {:?}", data);
1366                Ok(data)
1367            }
1368        } else {
1369            Ok(Vec::new())
1370        }
1371    }
1372
1373    fn swo_poll_interval_hint(&mut self, config: &SwoConfig) -> Option<Duration> {
1374        let caps = self.capabilities;
1375        if caps.swo_streaming_trace_implemented && self.device.swo_streaming_supported() {
1376            // Streaming reads block waiting for new data so any polling interval is fine
1377            Some(Duration::from_secs(0))
1378        } else {
1379            match self.swo_buffer_size {
1380                // Given the buffer size and SWO baud rate we can estimate a poll rate.
1381                Some(buf_size) => poll_interval_from_buf_size(config, buf_size),
1382
1383                // If we don't know the buffer size, we can't give a meaningful hint.
1384                None => None,
1385            }
1386        }
1387    }
1388
1389    fn swo_buffer_size(&mut self) -> Option<usize> {
1390        self.swo_buffer_size
1391    }
1392}
1393
1394impl Drop for CmsisDap {
1395    fn drop(&mut self) {
1396        tracing::debug!("Detaching from CMSIS-DAP probe");
1397        // We ignore the error cases as we can't do much about it anyways.
1398        let _ = self.process_batch();
1399
1400        // If SWO is active, disable it before calling detach,
1401        // which ensures detach won't error on disabling SWO.
1402        if self.swo_active {
1403            let _ = self.disable_swo();
1404        }
1405
1406        let _ = self.detach();
1407    }
1408}
1409
1410impl From<ScanChainError> for CmsisDapError {
1411    fn from(error: ScanChainError) -> Self {
1412        match error {
1413            ScanChainError::InvalidIdCode => CmsisDapError::InvalidIdCode,
1414            ScanChainError::InvalidIR => CmsisDapError::InvalidIR,
1415        }
1416    }
1417}