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, 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/// 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<DebugProbeInfo> {
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    /// Immediately send whatever is in our batch if it is not empty.
508    ///
509    /// If the last transfer was a read, result is Some with the read value.
510    /// Otherwise, the result is None.
511    ///
512    /// This will ensure any pending writes are processed and errors from them
513    /// raised if necessary.
514    #[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 less transfers than expected were executed, this
559                // is not the response to the latest command from the batch.
560                //
561                // According to the CMSIS-DAP specification, this shouldn't happen,
562                // the only time when not all transfers were executed is when an error occured.
563                // Still, this seems to happen in practice.
564
565                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                // TODO: Try a reset?
588                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                // To avoid a potential endless recursion,
598                // call a separate function to read the ctrl register,
599                // which doesn't use the batch API.
600                let ctrl = self.read_ctrl_register()?;
601
602                tracing::trace!("Ctrl/Stat register value is: {:?}", ctrl);
603
604                if ctrl.sticky_err() {
605                    // Clear sticky error flags.
606                    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    /// Add a BatchCommand to our current batch.
634    ///
635    /// If the BatchCommand is a Read, this will immediately process the batch
636    /// and return the read value. If the BatchCommand is a write, the write is
637    /// executed immediately if the batch is full, otherwise it is queued for
638    /// later execution.
639    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        // We always immediately process any reads, which means there will never
646        // be more than one read in a batch. We also process whenever the batch
647        // is as long as can fit in one packet.
648        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    /// Set SWO port to use requested transport.
657    ///
658    /// Check the probe capabilities to determine which transports are available.
659    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    /// Set SWO port to specified mode.
673    ///
674    /// Check the probe capabilities to determine which modes are available.
675    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    /// Set SWO port to specified baud rate.
686    ///
687    /// Returns `SwoBaudrateNotConfigured` if the probe returns 0,
688    /// indicating the requested baud rate was not configured,
689    /// and returns the configured baud rate on success (which
690    /// may differ from the requested baud rate).
691    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    /// Start SWO trace data capture.
702    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    /// Stop SWO trace data capture.
714    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    /// Fetch current SWO trace status.
726    #[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    /// Fetch extended SWO trace status.
735    ///
736    /// request.request_status: request trace status
737    /// request.request_count: request remaining bytes in trace buffer
738    /// request.request_index: request sequence number and timestamp of next trace sequence
739    #[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    /// Fetch latest SWO trace data by sending a DAP_SWO_Data request.
748    fn get_swo_data(&mut self) -> Result<Vec<u8>, DebugProbeError> {
749        match self.swo_buffer_size {
750            Some(swo_buffer_size) => {
751                // We'll request the smaller of the probe's SWO buffer and
752                // its maximum packet size. If the probe has less data to
753                // send it will respond with as much as it can.
754                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        // Store the actually used protocol, to handle cases where the default protocol is used.
794        tracing::info!("Using protocol {}", used_protocol);
795        self.protocol = Some(used_protocol);
796
797        // If operating under JTAG, try to bring the JTAG machinery out of reset. Ignore errors
798        // since not all probes support this.
799        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    /// Get the currently set maximum speed.
828    ///
829    /// CMSIS-DAP offers no possibility to get the actual speed used.
830    fn speed_khz(&self) -> u32 {
831        self.speed_khz
832    }
833
834    /// For CMSIS-DAP, we can set the maximum speed. The actual speed
835    /// used by the probe cannot be determined, but it will not be
836    /// higher than this value.
837    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    /// Enters debug mode.
845    #[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        // Run connect sequence (may already be done earlier via swj operations)
850        self.connect_if_needed()?;
851
852        // Set speed after connecting as it can be reset during protocol selection
853        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            // no-op: we configure JTAG in debug_port_setup,
863            // because that is where we execute the SWJ-DP Switch Sequence
864            // to ensure the debug port is ready for JTAG signals,
865            // at which point we can interrogate the scan chain
866            // and configure the probe with the given IR lengths.
867        } else {
868            self.configure_swd(swd::configure::ConfigureRequest {})?;
869        }
870
871        // Tell the probe we are connected so it can turn on an LED.
872        let _: Result<HostStatusResponse, _> =
873            commands::send_command(&mut self.device, &HostStatusRequest::connected(true));
874
875        Ok(())
876    }
877
878    /// Leave debug mode.
879    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        // Tell probe we are disconnected so it can turn off its LED.
890        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    /// Asserts the nRESET pin.
922    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        // This probe is intended for RISC-V.
980        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
1001// TODO: we will want to replace the default implementation with one that can use vendor extensions.
1002impl 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    /// Reads the DAP register on the specified port and address.
1012    fn raw_read_register(&mut self, address: RegisterAddress) -> Result<u32, ArmError> {
1013        let res = self.batch_add(BatchCommand::Read(address))?;
1014
1015        // NOTE(unwrap): batch_add will always return Some if the last command is a read
1016        // and running the batch was successful.
1017        Ok(res.unwrap())
1018    }
1019
1020    /// Writes a value to the DAP register on the specified port and address.
1021    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        // the overhead for a single packet is 6 bytes
1034        //
1035        // [0]: HID overhead
1036        // [1]: Category
1037        // [2]: DAP Index
1038        // [3]: Len 1
1039        // [4]: Len 2
1040        // [5]: Request type
1041        //
1042
1043        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        // the overhead for a single packet is 6 bytes
1079        //
1080        // [0]: HID overhead
1081        // [1]: Category
1082        // [2]: DAP Index
1083        // [3]: Len 1
1084        // [4]: Len 2
1085        // [5]: Request type
1086        //
1087
1088        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        // Check requested mode is available in probe capabilities
1218        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        // Stop any ongoing trace
1229        self.stop_swo_capture()?;
1230
1231        // Set transport. If the dedicated endpoint is available and we have opened
1232        // the probe in V2 mode and it has an SWO endpoint, request that, otherwise
1233        // request the DAP_SWO_Data polling mode.
1234        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        // Set mode. We've already checked that the requested mode is listed as supported.
1245        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        // Set baud rate.
1251        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            // Streaming reads block waiting for new data so any polling interval is fine
1298            Some(Duration::from_secs(0))
1299        } else {
1300            match self.swo_buffer_size {
1301                // Given the buffer size and SWO baud rate we can estimate a poll rate.
1302                Some(buf_size) => poll_interval_from_buf_size(config, buf_size),
1303
1304                // If we don't know the buffer size, we can't give a meaningful hint.
1305                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        // We ignore the error cases as we can't do much about it anyways.
1319        let _ = self.process_batch();
1320
1321        // If SWO is active, disable it before calling detach,
1322        // which ensures detach won't error on disabling SWO.
1323        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}