Skip to main content

probe_rs/
probe.rs

1//! Probe drivers
2pub(crate) mod common;
3pub mod usb_util;
4
5pub mod blackmagic;
6pub mod ch347usbjtag;
7pub mod cmsisdap;
8pub mod fake_probe;
9pub mod ftdi;
10pub mod glasgow;
11pub mod jlink;
12pub mod list;
13pub(crate) mod queue;
14mod selector;
15pub mod sifliuart;
16pub mod stlink;
17pub mod wlink;
18
19use crate::architecture::arm::sequences::{ArmDebugSequence, DefaultArmSequence};
20use crate::architecture::arm::{ArmDebugInterface, ArmError};
21use crate::architecture::arm::{RegisterAddress, SwoAccess, communication_interface::DapProbe};
22use crate::architecture::riscv::communication_interface::{RiscvError, RiscvInterfaceBuilder};
23use crate::architecture::xtensa::communication_interface::{
24    XtensaCommunicationInterface, XtensaDebugInterfaceState, XtensaError,
25};
26use crate::config::TargetSelector;
27use crate::config::registry::Registry;
28use crate::probe::common::JtagState;
29use crate::probe::queue::{BatchExecutionError, DeferredResultSet, ErasedQueue};
30use crate::{Error, Permissions, Session};
31use bitvec::slice::BitSlice;
32use bitvec::vec::BitVec;
33use common::ScanChainError;
34use parking_lot::RwLock;
35use probe_rs_target::ScanChainElement;
36use serde::{Deserialize, Serialize};
37use std::any::Any;
38use std::fmt;
39use std::sync::{Arc, LazyLock};
40
41pub use selector::DebugProbeSelector;
42
43/// Used to log warnings when the measured target voltage is
44/// lower than 1.4V, if at all measurable.
45const LOW_TARGET_VOLTAGE_WARNING_THRESHOLD: f32 = 1.4;
46
47static DRIVERS: LazyLock<RwLock<Vec<&'static dyn ProbeFactory>>> = LazyLock::new(|| {
48    let probes: Vec<&'static dyn ProbeFactory> = vec![
49        &blackmagic::BlackMagicProbeFactory,
50        &cmsisdap::CmsisDapFactory,
51        &ftdi::FtdiProbeFactory,
52        &stlink::StLinkFactory,
53        &jlink::JLinkFactory,
54        &wlink::WchLinkFactory,
55        &sifliuart::SifliUartFactory,
56        &glasgow::GlasgowFactory,
57        &ch347usbjtag::Ch347UsbJtagFactory,
58    ];
59
60    RwLock::new(probes)
61});
62
63pub(crate) fn register_probe_factory(factory: &'static dyn ProbeFactory) {
64    DRIVERS.write().push(factory);
65}
66
67/// The protocol that is to be used by the probe when communicating with the target.
68///
69/// For ARM select `Swd` or `Jtag`, for RISC-V select `Jtag`.
70#[derive(Copy, Clone, PartialEq, Eq, Debug, serde::Serialize, serde::Deserialize)]
71pub enum WireProtocol {
72    /// Serial Wire Debug is ARMs proprietary standard for communicating with ARM cores.
73    /// You can find specifics in the [`ARM Debug Interface v5.2`](https://developer.arm.com/documentation/ihi0031/f/?lang=en) specification.
74    Swd,
75    /// JTAG is a standard which is supported by many chips independent of architecture.
76    /// See [`Wikipedia`](https://en.wikipedia.org/wiki/JTAG) for more info.
77    Jtag,
78}
79
80impl fmt::Display for WireProtocol {
81    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
82        match self {
83            WireProtocol::Swd => f.write_str("SWD"),
84            WireProtocol::Jtag => f.write_str("JTAG"),
85        }
86    }
87}
88
89impl std::str::FromStr for WireProtocol {
90    type Err = String;
91
92    fn from_str(s: &str) -> Result<Self, Self::Err> {
93        match &s.to_ascii_lowercase()[..] {
94            "swd" => Ok(WireProtocol::Swd),
95            "jtag" => Ok(WireProtocol::Jtag),
96            _ => Err(format!(
97                "'{s}' is not a valid protocol. Choose either 'swd' or 'jtag'."
98            )),
99        }
100    }
101}
102
103/// A command queued in a batch for later execution
104///
105/// Mostly used internally but returned in DebugProbeError to indicate
106/// which batched command actually encountered the error.
107#[derive(Clone, Debug)]
108pub enum BatchCommand {
109    /// Read from a port
110    Read(RegisterAddress),
111
112    /// Write to a port
113    Write(RegisterAddress, u32),
114}
115
116impl fmt::Display for BatchCommand {
117    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
118        match self {
119            BatchCommand::Read(port) => {
120                write!(f, "Read(port={port:?})")
121            }
122            BatchCommand::Write(port, data) => {
123                write!(f, "Write(port={port:?}, data={data:#010x})")
124            }
125        }
126    }
127}
128
129/// Marker trait for all probe errors.
130pub trait ProbeError: std::error::Error + Send + Sync + std::any::Any {}
131
132impl std::error::Error for Box<dyn ProbeError> {
133    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
134        self.as_ref().source()
135    }
136}
137
138/// A probe-specific error.
139#[derive(Debug, thiserror::Error)]
140#[error(transparent)]
141pub struct BoxedProbeError(#[from] Box<dyn ProbeError>);
142
143impl BoxedProbeError {
144    fn as_any(&self) -> &dyn std::any::Any {
145        self.0.as_ref()
146    }
147
148    /// Returns true if the underlying error is of type `T`.
149    pub fn is<T: ProbeError>(&self) -> bool {
150        self.as_any().is::<T>()
151    }
152
153    /// Attempts to downcast the error to a specific error type.
154    pub fn downcast_ref<T: ProbeError>(&self) -> Option<&T> {
155        self.as_any().downcast_ref()
156    }
157
158    /// Attempts to downcast the error to a specific error type.
159    pub fn downcast_mut<T: ProbeError>(&mut self) -> Option<&mut T> {
160        let any: &mut dyn std::any::Any = self.0.as_mut();
161        any.downcast_mut()
162    }
163}
164
165impl<T> From<T> for BoxedProbeError
166where
167    T: ProbeError,
168{
169    fn from(e: T) -> Self {
170        BoxedProbeError(Box::new(e))
171    }
172}
173
174/// This error occurs whenever the debug probe logic encounters an error while operating the relevant debug probe.
175#[derive(thiserror::Error, Debug, docsplay::Display)]
176pub enum DebugProbeError {
177    /// USB Communication Error
178    Usb(#[source] std::io::Error),
179
180    /// An error which is specific to the debug probe in use occurred.
181    ProbeSpecific(#[source] BoxedProbeError),
182
183    /// The debug probe could not be created.
184    ProbeCouldNotBeCreated(#[from] ProbeCreationError),
185
186    /// The probe does not support the {0} protocol.
187    UnsupportedProtocol(WireProtocol),
188
189    /// The selected probe does not support the '{interface_name}' interface.
190    ///
191    /// This happens if a probe does not support certain functionality, such as:
192    /// - ARM debugging
193    /// - RISC-V debugging
194    /// - SWO
195    #[ignore_extra_doc_attributes]
196    InterfaceNotAvailable {
197        /// The name of the unsupported interface.
198        interface_name: &'static str,
199    },
200
201    /// The probe does not support the requested speed setting ({0} kHz).
202    UnsupportedSpeed(u32),
203
204    /// You need to be attached to the target to perform this action.
205    ///
206    /// The debug probe did not yet perform the init sequence.
207    /// Try calling [`DebugProbe::attach`] before trying again.
208    #[ignore_extra_doc_attributes]
209    NotAttached,
210
211    /// You need to be detached from the target to perform this action.
212    ///
213    /// The debug probe already performed the init sequence.
214    /// Try running the failing command before [`DebugProbe::attach`].
215    #[ignore_extra_doc_attributes]
216    Attached,
217
218    /// Failed to find or attach to the target. Please check the wiring before retrying.
219    TargetNotFound,
220
221    /// Error in previous batched command.
222    BatchError(BatchCommand),
223
224    /// The '{function_name}' functionality is not implemented yet.
225    ///
226    /// The variant of the function you called is not yet implemented.
227    /// This can happen if some debug probe has some unimplemented functionality for a specific protocol or architecture.
228    #[ignore_extra_doc_attributes]
229    NotImplemented {
230        /// The name of the unsupported functionality.
231        function_name: &'static str,
232    },
233
234    /// The '{command_name}' functionality is not supported by the selected probe.
235    /// This can happen when a probe does not allow for setting speed manually for example.
236    CommandNotSupportedByProbe {
237        /// The name of the unsupported command.
238        command_name: &'static str,
239    },
240
241    /// An error occurred handling the JTAG scan chain.
242    JtagScanChain(#[from] ScanChainError),
243
244    /// Some other error occurred
245    #[display("{0}")]
246    Other(String),
247
248    /// A timeout occurred during probe operation.
249    Timeout,
250}
251
252impl<T: ProbeError> From<T> for DebugProbeError {
253    fn from(e: T) -> Self {
254        Self::ProbeSpecific(BoxedProbeError::from(e))
255    }
256}
257
258/// An error during probe creation occurred.
259/// This is almost always a sign of a bad USB setup.
260/// Check UDEV rules if you are on Linux and try installing Zadig
261/// (This will disable vendor specific drivers for your probe!) if you are on Windows.
262#[derive(thiserror::Error, Debug, docsplay::Display)]
263pub enum ProbeCreationError {
264    /// The selected debug probe was not found.
265    /// This can be due to permissions.
266    NotFound,
267
268    /// The selected USB device could not be opened.
269    CouldNotOpen,
270
271    /// An HID API occurred.
272    #[cfg(feature = "cmsisdap_v1")]
273    HidApi(#[from] hidapi::HidError),
274
275    /// A USB error occurred.
276    Usb(#[source] std::io::Error),
277
278    /// An error specific with the selected probe occurred.
279    ProbeSpecific(#[source] BoxedProbeError),
280
281    /// Something else happened.
282    #[display("{0}")]
283    Other(&'static str),
284}
285
286impl<T: ProbeError> From<T> for ProbeCreationError {
287    fn from(e: T) -> Self {
288        Self::ProbeSpecific(BoxedProbeError::from(e))
289    }
290}
291
292/// The Probe struct is a generic wrapper over the different
293/// probes supported.
294///
295/// # Examples
296///
297/// ## Open the first probe found
298///
299/// The `list_all` and `from_probe_info` functions can be used
300/// to create a new `Probe`:
301///
302/// ```no_run
303/// use probe_rs::probe::{Probe, list::Lister};
304///
305/// let lister = Lister::new();
306///
307/// let probe_list = lister.list_all();
308/// let probe = probe_list[0].open();
309/// ```
310#[derive(Debug)]
311pub struct Probe {
312    inner: Box<dyn DebugProbe>,
313    attached: bool,
314}
315
316impl Probe {
317    /// Create a new probe from a more specific probe driver.
318    pub fn new(probe: impl DebugProbe + 'static) -> Self {
319        Self {
320            inner: Box::new(probe),
321            attached: false,
322        }
323    }
324
325    pub(crate) fn from_attached_probe(probe: Box<dyn DebugProbe>) -> Self {
326        Self {
327            inner: probe,
328            attached: true,
329        }
330    }
331
332    /// Same as [`Probe::new`] but without automatic boxing in case you already have a box.
333    pub fn from_specific_probe(probe: Box<dyn DebugProbe>) -> Self {
334        Probe {
335            inner: probe,
336            attached: false,
337        }
338    }
339
340    /// Get the human readable name for the probe.
341    pub fn get_name(&self) -> String {
342        self.inner.get_name().to_string()
343    }
344
345    /// Attach to the chip.
346    ///
347    /// This runs all the necessary protocol init routines.
348    ///
349    /// The target is loaded from the builtin list of targets.
350    /// If this doesn't work, you might want to try [`Probe::attach_under_reset`].
351    pub fn attach(
352        self,
353        target: impl Into<TargetSelector>,
354        permissions: Permissions,
355    ) -> Result<Session, Error> {
356        let registry = Registry::from_builtin_families();
357        self.attach_with_registry(target, permissions, &registry)
358    }
359
360    /// Attach to the chip.
361    ///
362    /// This runs all the necessary protocol init routines.
363    ///
364    /// The target is loaded from a custom registry.
365    /// If this doesn't work, you might want to try [`Probe::attach_under_reset`].
366    pub fn attach_with_registry(
367        self,
368        target: impl Into<TargetSelector>,
369        permissions: Permissions,
370        registry: &Registry,
371    ) -> Result<Session, Error> {
372        Session::new(
373            self,
374            target.into(),
375            AttachMethod::Normal,
376            permissions,
377            registry,
378        )
379    }
380
381    /// Attach to a target without knowing what target you have at hand.
382    /// This can be used for automatic device discovery or performing operations on an unspecified target.
383    pub fn attach_to_unspecified(&mut self) -> Result<(), Error> {
384        self.inner.attach()?;
385        self.attached = true;
386        Ok(())
387    }
388
389    /// A combination of [`Probe::attach_to_unspecified`] and [`Probe::attach_under_reset`].
390    pub fn attach_to_unspecified_under_reset(&mut self) -> Result<(), Error> {
391        if let Some(dap_probe) = self.try_as_dap_probe() {
392            DefaultArmSequence(()).reset_hardware_assert(dap_probe)?;
393        } else {
394            tracing::info!(
395                "Custom reset sequences are not supported on {}.",
396                self.get_name()
397            );
398            tracing::info!("Falling back to standard probe reset.");
399            self.target_reset_assert()?;
400        }
401        self.attach_to_unspecified()?;
402        Ok(())
403    }
404
405    /// Attach to the chip under hard-reset.
406    ///
407    /// This asserts the reset pin via the probe, plays the protocol init routines and deasserts the pin.
408    /// This is necessary if the chip is not responding to the SWD reset sequence.
409    /// For example this can happen if the chip has the SWDIO pin remapped.
410    ///
411    /// The target is loaded from the builtin list of targets.
412    pub fn attach_under_reset(
413        self,
414        target: impl Into<TargetSelector>,
415        permissions: Permissions,
416    ) -> Result<Session, Error> {
417        let registry = Registry::from_builtin_families();
418        self.attach_under_reset_with_registry(target, permissions, &registry)
419    }
420
421    /// Attach to the chip under hard-reset.
422    ///
423    /// This asserts the reset pin via the probe, plays the protocol init routines and deasserts the pin.
424    /// This is necessary if the chip is not responding to the SWD reset sequence.
425    /// For example this can happen if the chip has the SWDIO pin remapped.
426    ///
427    /// The target is loaded from a custom registry.
428    pub fn attach_under_reset_with_registry(
429        self,
430        target: impl Into<TargetSelector>,
431        permissions: Permissions,
432        registry: &Registry,
433    ) -> Result<Session, Error> {
434        // The session will de-assert reset after connecting to the debug interface.
435        Session::new(
436            self,
437            target.into(),
438            AttachMethod::UnderReset,
439            permissions,
440            registry,
441        )
442        .map_err(|e| match e {
443            Error::Arm(ArmError::Timeout)
444            | Error::Riscv(RiscvError::Timeout)
445            | Error::Xtensa(XtensaError::Timeout) => Error::Other(
446                "Timeout while attaching to target under reset. \
447                    This can happen if the target is not responding to the reset sequence. \
448                    Ensure the chip's reset pin is connected, or try attaching without reset \
449                    (`connectUnderReset = false` for DAP Clients, or remove `connect-under-reset` \
450                        option from CLI options.)."
451                    .to_string(),
452            ),
453            e => e,
454        })
455    }
456
457    /// Selects the transport protocol to be used by the debug probe.
458    pub fn select_protocol(&mut self, protocol: WireProtocol) -> Result<(), DebugProbeError> {
459        if !self.attached {
460            self.inner.select_protocol(protocol)
461        } else {
462            Err(DebugProbeError::Attached)
463        }
464    }
465
466    /// Get the currently selected protocol
467    ///
468    /// Depending on the probe, this might not be available.
469    pub fn protocol(&self) -> Option<WireProtocol> {
470        self.inner.active_protocol()
471    }
472
473    /// Leave debug mode
474    pub fn detach(&mut self) -> Result<(), crate::Error> {
475        self.attached = false;
476        self.inner.detach()?;
477        Ok(())
478    }
479
480    /// Resets the target device.
481    pub fn target_reset(&mut self) -> Result<(), DebugProbeError> {
482        self.inner.target_reset()
483    }
484
485    /// Asserts the reset of the target.
486    /// This is always the hard reset which means the reset wire has to be connected to work.
487    ///
488    /// This is not supported on all probes.
489    pub fn target_reset_assert(&mut self) -> Result<(), DebugProbeError> {
490        tracing::debug!("Asserting target reset");
491        self.inner.target_reset_assert()
492    }
493
494    /// Deasserts the reset of the target.
495    /// This is always the hard reset which means the reset wire has to be connected to work.
496    ///
497    /// This is not supported on all probes.
498    pub fn target_reset_deassert(&mut self) -> Result<(), DebugProbeError> {
499        tracing::debug!("Deasserting target reset");
500        self.inner.target_reset_deassert()
501    }
502
503    /// Configure protocol speed to use in kHz
504    pub fn set_speed(&mut self, speed_khz: u32) -> Result<u32, DebugProbeError> {
505        if !self.attached {
506            self.inner.set_speed(speed_khz)
507        } else {
508            Err(DebugProbeError::Attached)
509        }
510    }
511
512    /// Get the currently used maximum speed for the debug protocol in kHz.
513    ///
514    /// Not all probes report which speed is used, meaning this value is not
515    /// always the actual speed used. However, the speed should not be any
516    /// higher than this value.
517    pub fn speed_khz(&self) -> u32 {
518        self.inner.speed_khz()
519    }
520
521    /// Check if the probe has an interface to
522    /// debug Xtensa chips.
523    pub fn has_xtensa_interface(&self) -> bool {
524        self.inner.has_xtensa_interface()
525    }
526
527    /// Try to get a [`XtensaCommunicationInterface`], which can
528    /// can be used to communicate with chips using the Xtensa
529    /// architecture.
530    ///
531    /// The user is responsible for creating and managing the [`XtensaDebugInterfaceState`] state
532    /// object.
533    ///
534    /// If an error occurs while trying to connect, the probe is returned.
535    pub fn try_get_xtensa_interface<'probe>(
536        &'probe mut self,
537        state: &'probe mut XtensaDebugInterfaceState,
538    ) -> Result<XtensaCommunicationInterface<'probe>, XtensaError> {
539        if !self.attached {
540            Err(DebugProbeError::NotAttached.into())
541        } else {
542            Ok(self.inner.try_get_xtensa_interface(state)?)
543        }
544    }
545
546    /// Checks if the probe supports connecting to chips
547    /// using the Arm Debug Interface.
548    pub fn has_arm_debug_interface(&self) -> bool {
549        self.inner.has_arm_interface()
550    }
551
552    /// Try to get a trait object implementing [`ArmDebugInterface`], which can
553    /// can be used to communicate with chips using the ARM debug interface.
554    ///
555    /// If an error occurs while trying to connect, the probe is returned.
556    pub fn try_into_arm_debug_interface<'probe>(
557        self,
558        sequence: Arc<dyn ArmDebugSequence>,
559    ) -> Result<Box<dyn ArmDebugInterface + 'probe>, (Self, ArmError)> {
560        if !self.attached {
561            Err((self, DebugProbeError::NotAttached.into()))
562        } else {
563            self.inner
564                .try_get_arm_debug_interface(sequence)
565                .map_err(|(probe, err)| (Probe::from_attached_probe(probe), err))
566        }
567    }
568
569    /// Check if the probe has an interface to debug RISC-V chips.
570    pub fn has_riscv_interface(&self) -> bool {
571        self.inner.has_riscv_interface()
572    }
573
574    /// Try to get a [`RiscvInterfaceBuilder`] object, which can be used to set up a communication
575    /// interface with chips using the RISC-V architecture.
576    ///
577    /// The returned object can be used to create the interface state, which is required to
578    /// attach to the RISC-V target. The user is responsible for managing this state object.
579    ///
580    /// If an error occurs while trying to connect, the probe is returned.
581    pub fn try_get_riscv_interface_builder<'probe>(
582        &'probe mut self,
583    ) -> Result<Box<dyn RiscvInterfaceBuilder<'probe> + 'probe>, RiscvError> {
584        if !self.attached {
585            Err(DebugProbeError::NotAttached.into())
586        } else {
587            self.inner.try_get_riscv_interface_builder()
588        }
589    }
590
591    /// Returns a [`JtagAccess`] from the debug probe, if implemented.
592    pub fn try_as_jtag_probe(&mut self) -> Option<&mut dyn JtagAccess> {
593        self.inner.try_as_jtag_probe()
594    }
595
596    /// Gets a SWO interface from the debug probe.
597    ///
598    /// This does not work on all probes.
599    pub fn get_swo_interface(&self) -> Option<&dyn SwoAccess> {
600        self.inner.get_swo_interface()
601    }
602
603    /// Gets a mutable SWO interface from the debug probe.
604    ///
605    /// This does not work on all probes.
606    pub fn get_swo_interface_mut(&mut self) -> Option<&mut dyn SwoAccess> {
607        self.inner.get_swo_interface_mut()
608    }
609
610    /// Gets a DAP interface from the debug probe.
611    ///
612    /// This does not work on all probes.
613    pub fn try_as_dap_probe(&mut self) -> Option<&mut dyn DapProbe> {
614        self.inner.try_as_dap_probe()
615    }
616
617    /// Try reading the target voltage of via the connected voltage pin.
618    ///
619    /// This does not work on all probes.
620    pub fn get_target_voltage(&mut self) -> Result<Option<f32>, DebugProbeError> {
621        self.inner.get_target_voltage()
622    }
623
624    /// Try to convert the probe into a concrete probe type.
625    pub fn try_into<P: DebugProbe>(&mut self) -> Option<&mut P> {
626        (self.inner.as_mut() as &mut dyn Any).downcast_mut::<P>()
627    }
628}
629
630/// An abstraction over a probe driver type.
631///
632/// This trait has to be implemented by ever debug probe driver.
633///
634/// The `std::fmt::Display` implementation will be used to display the probe in the list of available probes,
635/// and should return a human-readable name for the probe type.
636pub trait ProbeFactory: std::any::Any + std::fmt::Display + std::fmt::Debug + Sync {
637    /// Creates a new boxed [`DebugProbe`] from a given [`DebugProbeSelector`].
638    /// This will be called for all available debug drivers when discovering probes.
639    /// When opening, it will open the first probe which succeeds during this call.
640    fn open(&self, selector: &DebugProbeSelector) -> Result<Box<dyn DebugProbe>, DebugProbeError>;
641
642    /// Returns a list of all available debug probes of the current type, each annotated with
643    /// whether the current process can access it.
644    fn list_probes(&self) -> Vec<list::ProbeListItem>;
645
646    /// Returns a list of probes that match the optional selector.
647    ///
648    /// If the selector is `None`, all available probes are returned.
649    fn list_probes_filtered(
650        &self,
651        selector: Option<&DebugProbeSelector>,
652    ) -> Vec<list::ProbeListItem> {
653        // The default implementation falls back to listing all probes so that drivers don't need
654        // to deal with the common filtering logic.
655        self.list_probes()
656            .into_iter()
657            .filter(|probe| {
658                selector
659                    .as_ref()
660                    .is_none_or(|s| s.matches_probe(&probe.info))
661            })
662            .collect()
663    }
664}
665
666/// An abstraction over a general debug probe.
667///
668/// This trait has to be implemented by ever debug probe driver.
669pub trait DebugProbe: Any + Send + fmt::Debug {
670    /// Get human readable name for the probe.
671    fn get_name(&self) -> &str;
672
673    /// Get the currently used maximum speed for the debug protocol in kHz.
674    ///
675    /// Not all probes report which speed is used, meaning this value is not
676    /// always the actual speed used. However, the speed should not be any
677    /// higher than this value.
678    fn speed_khz(&self) -> u32;
679
680    /// Set the speed in kHz used for communication with the target device.
681    ///
682    /// The desired speed might not be supported by the probe. If the desired
683    /// speed is not directly supported, a lower speed will be selected if possible.
684    ///
685    /// If possible, the actual speed used is returned by the function. Some probes
686    /// cannot report this, so the value may be inaccurate.
687    ///
688    /// If the requested speed is not supported,
689    /// `DebugProbeError::UnsupportedSpeed` will be returned.
690    ///
691    fn set_speed(&mut self, speed_khz: u32) -> Result<u32, DebugProbeError>;
692
693    /// Attach to the chip.
694    ///
695    /// This should run all the necessary protocol init routines.
696    fn attach(&mut self) -> Result<(), DebugProbeError>;
697
698    /// Detach from the chip.
699    ///
700    /// This should run all the necessary protocol deinit routines.
701    ///
702    /// If the probe uses batched commands, this will also cause all
703    /// remaining commands to be executed. If an error occurs during
704    /// this execution, the probe might remain in the attached state.
705    fn detach(&mut self) -> Result<(), crate::Error>;
706
707    /// This should hard reset the target device.
708    fn target_reset(&mut self) -> Result<(), DebugProbeError>;
709
710    /// This should assert the reset pin of the target via debug probe.
711    fn target_reset_assert(&mut self) -> Result<(), DebugProbeError>;
712
713    /// This should deassert the reset pin of the target via debug probe.
714    fn target_reset_deassert(&mut self) -> Result<(), DebugProbeError>;
715
716    /// Selects the transport protocol to be used by the debug probe.
717    fn select_protocol(&mut self, protocol: WireProtocol) -> Result<(), DebugProbeError>;
718
719    /// Get the transport protocol currently in active use by the debug probe.
720    fn active_protocol(&self) -> Option<WireProtocol>;
721
722    /// Check if the probe offers an interface to debug ARM chips.
723    fn has_arm_interface(&self) -> bool {
724        false
725    }
726
727    /// Returns a [`JtagAccess`] from the debug probe, if implemented.
728    fn try_as_jtag_probe(&mut self) -> Option<&mut dyn JtagAccess> {
729        None
730    }
731
732    /// Get the dedicated interface to debug ARM chips. To check that the
733    /// probe actually supports this, call [DebugProbe::has_arm_interface] first.
734    fn try_get_arm_debug_interface<'probe>(
735        self: Box<Self>,
736        _sequence: Arc<dyn ArmDebugSequence>,
737    ) -> Result<Box<dyn ArmDebugInterface + 'probe>, (Box<dyn DebugProbe>, ArmError)> {
738        Err((
739            self.into_probe(),
740            DebugProbeError::InterfaceNotAvailable {
741                interface_name: "ARM",
742            }
743            .into(),
744        ))
745    }
746
747    /// Try to get a [`RiscvInterfaceBuilder`] object, which can be used to set up a communication
748    /// interface with chips using the RISC-V architecture.
749    ///
750    /// Ensure that the probe actually supports this by calling
751    /// [DebugProbe::has_riscv_interface] first.
752    fn try_get_riscv_interface_builder<'probe>(
753        &'probe mut self,
754    ) -> Result<Box<dyn RiscvInterfaceBuilder<'probe> + 'probe>, RiscvError> {
755        Err(DebugProbeError::InterfaceNotAvailable {
756            interface_name: "RISC-V",
757        }
758        .into())
759    }
760
761    /// Check if the probe offers an interface to debug RISC-V chips.
762    fn has_riscv_interface(&self) -> bool {
763        false
764    }
765
766    /// Get the dedicated interface to debug Xtensa chips. Ensure that the
767    /// probe actually supports this by calling [DebugProbe::has_xtensa_interface] first.
768    fn try_get_xtensa_interface<'probe>(
769        &'probe mut self,
770        _state: &'probe mut XtensaDebugInterfaceState,
771    ) -> Result<XtensaCommunicationInterface<'probe>, XtensaError> {
772        Err(DebugProbeError::InterfaceNotAvailable {
773            interface_name: "Xtensa",
774        }
775        .into())
776    }
777
778    /// Check if the probe offers an interface to debug Xtensa chips.
779    fn has_xtensa_interface(&self) -> bool {
780        false
781    }
782
783    /// Get a SWO interface from the debug probe.
784    ///
785    /// This is not available on all debug probes.
786    fn get_swo_interface(&self) -> Option<&dyn SwoAccess> {
787        None
788    }
789
790    /// Get a mutable SWO interface from the debug probe.
791    ///
792    /// This is not available on all debug probes.
793    fn get_swo_interface_mut(&mut self) -> Option<&mut dyn SwoAccess> {
794        None
795    }
796
797    /// Boxes itself.
798    fn into_probe(self: Box<Self>) -> Box<dyn DebugProbe>;
799
800    /// Try creating a DAP interface for the given probe.
801    ///
802    /// This is not available on all probes.
803    fn try_as_dap_probe(&mut self) -> Option<&mut dyn DapProbe> {
804        None
805    }
806
807    /// Reads the target voltage in Volts, if possible. Returns `Ok(None)`
808    /// if the probe doesn’t support reading the target voltage.
809    fn get_target_voltage(&mut self) -> Result<Option<f32>, DebugProbeError> {
810        Ok(None)
811    }
812}
813
814impl PartialEq for dyn ProbeFactory {
815    fn eq(&self, other: &Self) -> bool {
816        // Consider ProbeFactory objects equal when their types and data pointers are equal.
817        // Pointer equality is insufficient, because ZST objects may have the same dangling pointer
818        // as their address.
819        self.type_id() == other.type_id()
820            && std::ptr::eq(
821                self as *const _ as *const (),
822                other as *const _ as *const (),
823            )
824    }
825}
826
827/// Gathers some information about a debug probe which was found during a scan.
828#[derive(Debug, Clone, PartialEq)]
829pub struct DebugProbeInfo {
830    /// The name of the debug probe.
831    pub identifier: String,
832    /// The USB vendor ID of the debug probe.
833    pub vendor_id: u16,
834    /// The USB product ID of the debug probe.
835    pub product_id: u16,
836    /// The serial number of the debug probe.
837    pub serial_number: Option<String>,
838    /// The interface index of the debug probe
839    pub interface: Option<u8>,
840
841    /// This is a composite HID device.
842    pub is_hid_interface: bool,
843
844    /// A reference to the [`ProbeFactory`] that created this info object.
845    probe_factory: &'static dyn ProbeFactory,
846}
847
848impl std::fmt::Display for DebugProbeInfo {
849    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
850        write!(
851            f,
852            "{} -- {:04x}:{:04x}",
853            self.identifier, self.vendor_id, self.product_id,
854        )?;
855
856        if let Some(interface) = self.interface {
857            write!(f, "-{}", interface)?;
858        }
859
860        write!(
861            f,
862            ":{} ({})",
863            self.serial_number.as_deref().unwrap_or(""),
864            self.probe_factory
865        )
866    }
867}
868
869impl DebugProbeInfo {
870    /// Creates a new info struct that uniquely identifies a probe.
871    pub fn new<S: Into<String>>(
872        identifier: S,
873        vendor_id: u16,
874        product_id: u16,
875        serial_number: Option<String>,
876        probe_factory: &'static dyn ProbeFactory,
877        interface: Option<u8>,
878        is_hid_interface: bool,
879    ) -> Self {
880        Self {
881            identifier: identifier.into(),
882            vendor_id,
883            product_id,
884            serial_number,
885            probe_factory,
886            interface,
887            is_hid_interface,
888        }
889    }
890
891    /// Open the probe described by this `DebugProbeInfo`.
892    pub fn open(&self) -> Result<Probe, DebugProbeError> {
893        let selector = DebugProbeSelector::from(self);
894        self.probe_factory
895            .open(&selector)
896            .map(Probe::from_specific_probe)
897    }
898
899    /// Returns whether this info was returned by a particular probe factory.
900    pub fn is_probe_type<F: ProbeFactory>(&self) -> bool {
901        self.probe_factory.type_id() == std::any::TypeId::of::<F>()
902    }
903
904    /// Returns a human-readable string describing the probe type.
905    ///
906    /// The exact contents of the string are unstable, this is intended for human consumption only.
907    pub fn probe_type(&self) -> String {
908        self.probe_factory.to_string()
909    }
910}
911
912/// Bit-banging interface, ARM edition.
913///
914/// This trait (and [RawJtagIo], [JtagAccess]) should not be used by architecture implementations
915/// directly. Architectures should implement their own protocol interfaces, and use the raw probe
916/// interfaces (like [RawSwdIo]) to perform the low-level operations AS A FALLBACK. Probes like
917/// [CmsisDap] should prefer directly implementing the architecture protocols, if they have the
918/// capability.
919///
920/// Currently ARM implements this idea via [crate::architecture::arm::RawDapAccess], which
921/// is then implemented by [CmsisDap] or a fallback is provided for any probe that
922/// implements both `RawSwdIo` and [JtagAccess].
923///
924/// RISC-V is close with its [crate::architecture::riscv::dtm::DtmAccess] trait.
925///
926/// [CmsisDap]: crate::probe::cmsisdap::CmsisDap
927pub trait RawSwdIo: DebugProbe {
928    /// Drive a sequence of SWD I/O items and return the sampled bits.
929    fn swd_io<S>(&mut self, swdio: S) -> Result<Vec<bool>, DebugProbeError>
930    where
931        S: IntoIterator<Item = IoSequenceItem>;
932
933    /// Drive the CMSIS-DAP SWJ pins.
934    fn swj_pins(
935        &mut self,
936        pin_out: u32,
937        pin_select: u32,
938        pin_wait: u32,
939    ) -> Result<u32, DebugProbeError>;
940
941    /// Returns the SWD wire-protocol timing settings used by this probe.
942    fn swd_settings(&self) -> &SwdSettings;
943}
944
945/// A trait for implementing low-level JTAG interface operations.
946pub trait RawJtagIo: DebugProbe {
947    /// Returns a mutable reference to the current state.
948    fn state_mut(&mut self) -> &mut JtagDriverState;
949
950    /// Returns the current state.
951    fn state(&self) -> &JtagDriverState;
952
953    /// Shifts a number of bits through the TAP.
954    fn shift_bits(
955        &mut self,
956        tms: impl IntoIterator<Item = bool>,
957        tdi: impl IntoIterator<Item = bool>,
958        cap: impl IntoIterator<Item = bool>,
959    ) -> Result<(), DebugProbeError> {
960        for ((tms, tdi), cap) in tms.into_iter().zip(tdi).zip(cap) {
961            self.shift_bit(tms, tdi, cap)?;
962        }
963
964        Ok(())
965    }
966
967    /// Shifts a single bit through the TAP.
968    ///
969    /// Drivers may choose, and are encouraged, to buffer bits and flush them
970    /// in batches for performance reasons.
971    fn shift_bit(&mut self, tms: bool, tdi: bool, capture: bool) -> Result<(), DebugProbeError>;
972
973    /// Returns the bits captured from TDO and clears the capture buffer.
974    fn read_captured_bits(&mut self) -> Result<BitVec, DebugProbeError>;
975
976    /// Resets the JTAG state machine by shifting out a number of high TMS bits.
977    fn reset_jtag_state_machine(&mut self) -> Result<(), DebugProbeError> {
978        tracing::debug!("Resetting JTAG chain by setting tms high for 5 bits");
979
980        // Reset JTAG chain (5 times TMS high), and enter idle state afterwards
981        let tms = [true, true, true, true, true, false];
982        let tdi = std::iter::repeat(true);
983
984        self.shift_bits(tms, tdi, std::iter::repeat(false))?;
985        let response = self.read_captured_bits()?;
986
987        tracing::debug!("Response to reset: {response}");
988
989        Ok(())
990    }
991}
992
993/// One step of a [`RawSwdIo::swd_io`] sequence.
994#[derive(Debug, Clone, Copy, PartialEq)]
995pub enum IoSequenceItem {
996    /// Drive SWDIO to the given level for one clock.
997    Output(bool),
998    /// Sample SWDIO for one clock.
999    Input,
1000}
1001
1002/// SWD wire-protocol timing settings used by [`RawSwdIo`] probes.
1003#[derive(Debug)]
1004pub struct SwdSettings {
1005    /// Initial number of idle cycles between consecutive writes.
1006    ///
1007    /// When a WAIT response is received, the number of idle cycles
1008    /// will be increased automatically, so this number can be quite
1009    /// low.
1010    pub num_idle_cycles_between_writes: usize,
1011
1012    /// How often a SWD transfer is retried when a WAIT response
1013    /// is received.
1014    pub num_retries_after_wait: usize,
1015
1016    /// When a SWD transfer is retried due to a WAIT response, the idle
1017    /// cycle amount is doubled every time as a backoff. This sets a maximum
1018    /// cap to the cycle amount.
1019    pub max_retry_idle_cycles_after_wait: usize,
1020
1021    /// Number of idle cycles inserted before the result
1022    /// of a write is checked.
1023    ///
1024    /// When performing a write operation, the write can
1025    /// be buffered, meaning that completing the transfer
1026    /// does not mean that the write was performed successfully.
1027    ///
1028    /// To check that all writes have been executed, the
1029    /// `RDBUFF` register can be read from the DP.
1030    ///
1031    /// If any writes are still pending, this read will result in a WAIT response.
1032    /// By adding idle cycles before performing this read, the chance of a
1033    /// WAIT response is smaller.
1034    pub idle_cycles_before_write_verify: usize,
1035
1036    /// Number of idle cycles to insert after a transfer
1037    ///
1038    /// It is recommended that at least 8 idle cycles are
1039    /// inserted.
1040    pub idle_cycles_after_transfer: usize,
1041}
1042
1043impl Default for SwdSettings {
1044    fn default() -> Self {
1045        Self {
1046            num_idle_cycles_between_writes: 2,
1047            num_retries_after_wait: 1000,
1048            max_retry_idle_cycles_after_wait: 128,
1049            idle_cycles_before_write_verify: 8,
1050            idle_cycles_after_transfer: 8,
1051        }
1052    }
1053}
1054
1055/// The state of a bitbanging JTAG driver.
1056///
1057/// This struct tracks the state of the JTAG state machine,  which TAP is currently selected, and
1058/// contains information about the system (like scan chain).
1059#[derive(Debug)]
1060pub struct JtagDriverState {
1061    /// The state of the JTAG state machine.
1062    pub state: JtagState,
1063
1064    /// The expected scan chain.
1065    pub expected_scan_chain: Option<Vec<ScanChainElement>>,
1066
1067    /// The actual scan chain.
1068    pub scan_chain: Vec<ScanChainElement>,
1069
1070    /// The parameters of the scan chain.
1071    pub chain_params: ChainParams,
1072
1073    /// Idle cycles necessary between consecutive accesses to the DMI register.
1074    pub jtag_idle_cycles: usize,
1075}
1076impl JtagDriverState {
1077    fn max_ir_address(&self) -> u32 {
1078        (1 << self.chain_params.irlen) - 1
1079    }
1080}
1081
1082impl Default for JtagDriverState {
1083    fn default() -> Self {
1084        Self {
1085            state: JtagState::Reset,
1086            expected_scan_chain: None,
1087            scan_chain: Vec::new(),
1088            chain_params: ChainParams::default(),
1089            jtag_idle_cycles: 0,
1090        }
1091    }
1092}
1093
1094/// Marker trait for bitbanging JTAG probes.
1095///
1096/// This trait exists to control which probes implement [`JtagAccess`]. In some cases,
1097/// a probe may implement [`RawJtagIo`] but does not want an auto-implemented [JtagAccess].
1098pub trait AutoImplementJtagAccess: RawJtagIo + 'static {}
1099
1100/// Low-Level access to the JTAG protocol
1101///
1102/// This trait should be implemented by all probes which offer low-level access to
1103/// the JTAG protocol, i.e. direct control over the bytes sent and received.
1104pub trait JtagAccess: DebugProbe {
1105    /// Set the JTAG scan chain information for the target under debug.
1106    ///
1107    /// This allows the probe to know which TAPs are in the scan chain and their
1108    /// position and IR lengths.
1109    ///
1110    /// If the scan chain is provided, and the selected protocol is JTAG, the
1111    /// probe will use this information to validate that the scan chain is
1112    /// what is expected.
1113    ///
1114    /// This is called by the `Session` when attaching to a target.
1115    /// So this does not need to be called manually, unless you want to
1116    /// modify the scan chain. You must be attached to a target to set the
1117    /// scan_chain since the scan chain only applies to the attached target.
1118    fn set_expected_scan_chain(
1119        &mut self,
1120        scan_chain: &[ScanChainElement],
1121    ) -> Result<(), DebugProbeError>;
1122
1123    /// Set the JTAG scan chain information for the target under debug.
1124    ///
1125    /// If the scan chain is provided, and the selected protocol is JTAG, the
1126    /// probe will automatically configure the JTAG interface to match the
1127    /// scan chain configuration without trying to determine the chain at
1128    /// runtime.
1129    fn set_scan_chain(&mut self, scan_chain: &[ScanChainElement]) -> Result<(), DebugProbeError>;
1130
1131    /// Scans `IDCODE` and `IR` length information about the devices on the JTAG chain.
1132    ///
1133    /// If configured, this will use the data from [`Self::set_scan_chain`]. Otherwise, it
1134    /// will try to measure and extract `IR` lengths by driving the JTAG interface.
1135    ///
1136    /// The measured scan chain will be stored in the probe's internal state.
1137    fn scan_chain(&mut self) -> Result<&[ScanChainElement], DebugProbeError>;
1138
1139    /// Shifts a number of bits through the TAP.
1140    fn shift_raw_sequence(&mut self, sequence: JtagSequence) -> Result<BitVec, DebugProbeError>;
1141
1142    /// Executes a TAP reset.
1143    fn tap_reset(&mut self) -> Result<(), DebugProbeError>;
1144
1145    /// For RISC-V, and possibly other interfaces, the JTAG interface has to remain in
1146    /// the idle state for several cycles between consecutive accesses to the DR register.
1147    ///
1148    /// This function configures the number of idle cycles which are inserted after each access.
1149    fn set_idle_cycles(&mut self, idle_cycles: u8) -> Result<(), DebugProbeError>;
1150
1151    /// Return the currently configured idle cycles.
1152    fn idle_cycles(&self) -> u8;
1153
1154    /// Selects the JTAG TAP to be used for communication.
1155    ///
1156    /// The index is the position of the TAP in the scan chain, which can
1157    /// be configured using [`set_scan_chain()`](JtagAccess::set_scan_chain()).
1158    fn select_target(&mut self, index: usize) -> Result<(), DebugProbeError> {
1159        if index != 0 {
1160            return Err(DebugProbeError::NotImplemented {
1161                function_name: "select_jtag_tap",
1162            });
1163        }
1164
1165        Ok(())
1166    }
1167
1168    /// Read a JTAG register.
1169    ///
1170    /// This function emulates a read by performing a write with all zeros to the DR.
1171    fn read_register(&mut self, address: u32, len: u32) -> Result<BitVec, DebugProbeError> {
1172        let data = vec![0u8; len.div_ceil(8) as usize];
1173
1174        self.write_register(address, &data, len)
1175    }
1176
1177    /// Write to a JTAG register
1178    ///
1179    /// This function will perform a write to the IR register, if necessary,
1180    /// to select the correct register, and then to the DR register, to transmit the
1181    /// data. The data shifted out of the DR register will be returned.
1182    fn write_register(
1183        &mut self,
1184        address: u32,
1185        data: &[u8],
1186        len: u32,
1187    ) -> Result<BitVec, DebugProbeError>;
1188
1189    /// Shift a value into the DR JTAG register
1190    ///
1191    /// The data shifted out of the DR register will be returned.
1192    fn write_dr(&mut self, data: &[u8], len: u32) -> Result<BitVec, DebugProbeError>;
1193
1194    /// Executes a sequence of JTAG commands.
1195    fn write_register_batch(
1196        &mut self,
1197        writes: &ErasedQueue,
1198    ) -> Result<DeferredResultSet<CommandResult>, BatchExecutionError> {
1199        tracing::debug!(
1200            "Using default `JtagAccess::write_register_batch` hurts performance. Please implement proper batching for this probe."
1201        );
1202        let mut results = DeferredResultSet::new();
1203
1204        for (idx, write) in writes.iter() {
1205            match write {
1206                JtagCommand::WriteRegister(write) => {
1207                    let response = match self.write_register(
1208                        write.inner.address,
1209                        &write.inner.data,
1210                        write.inner.len,
1211                    ) {
1212                        Ok(response) => response,
1213                        Err(e) => {
1214                            return Err(BatchExecutionError::new_from_debug_probe(e, results));
1215                        }
1216                    };
1217
1218                    match (write.transform)(&write.inner, &response) {
1219                        Ok(res) => results.push(idx, res),
1220                        Err(e) => {
1221                            return Err(BatchExecutionError::new_specific(e, results));
1222                        }
1223                    }
1224                }
1225
1226                JtagCommand::ShiftDr(write) => {
1227                    let response = match self.write_dr(&write.inner.data, write.inner.len) {
1228                        Ok(response) => response,
1229                        Err(e) => {
1230                            return Err(BatchExecutionError::new_from_debug_probe(e, results));
1231                        }
1232                    };
1233                    match (write.transform)(&write.inner, &response) {
1234                        Ok(res) => results.push(idx, res),
1235                        Err(e) => return Err(BatchExecutionError::new_specific(e, results)),
1236                    }
1237                }
1238            }
1239        }
1240
1241        Ok(results)
1242    }
1243}
1244
1245/// A raw JTAG bit sequence.
1246pub struct JtagSequence {
1247    /// TDO capture
1248    pub tdo_capture: bool,
1249
1250    /// TMS value
1251    pub tms: bool,
1252
1253    /// Data to generate on TDI
1254    pub data: BitVec,
1255}
1256
1257/// Data for a JTAG register write
1258#[derive(Debug, Clone)]
1259pub struct JtagWriteData {
1260    /// The IR register to write to.
1261    pub address: u32,
1262
1263    /// The data to be written to DR.
1264    pub data: Vec<u8>,
1265
1266    /// The number of bits in `data`
1267    pub len: u32,
1268}
1269
1270/// Data for a DR shift - no transform, just the payload.
1271#[derive(Debug, Clone)]
1272pub struct ShiftDrData {
1273    /// The data to be written to DR.
1274    pub data: Vec<u8>,
1275
1276    /// The number of bits in `data`
1277    pub len: u32,
1278}
1279
1280/// A typed JTAG register write command with compile-time error type.
1281#[derive(Debug, Clone)]
1282pub struct JtagWriteCommand<E> {
1283    /// The inner data for the write command.
1284    pub data: JtagWriteData,
1285
1286    /// A function to transform the raw response into a [`CommandResult`]
1287    pub transform: fn(&JtagWriteData, &BitSlice) -> Result<CommandResult, E>,
1288}
1289
1290impl<E: std::error::Error + Send + Sync + 'static> From<JtagWriteCommand<E>> for JtagCommand {
1291    fn from(value: JtagWriteCommand<E>) -> Self {
1292        let typed_transform = value.transform;
1293
1294        let erased_command = ErasedCommand {
1295            inner: value.data,
1296            transform: Box::new(move |data, bits| {
1297                (typed_transform)(data, bits)
1298                    .map_err(|e| Box::new(e) as Box<dyn std::error::Error + Send + Sync>)
1299            }),
1300        };
1301
1302        JtagCommand::WriteRegister(erased_command)
1303    }
1304}
1305
1306/// A DR shift command
1307#[derive(Debug, Clone)]
1308pub struct ShiftDrCommand<E> {
1309    /// The inner data for the shift command.
1310    pub inner: ShiftDrData,
1311
1312    /// A function to transform the raw response into a [`CommandResult`]
1313    pub transform: fn(&ShiftDrData, &BitSlice) -> Result<CommandResult, E>,
1314}
1315
1316impl<E: std::error::Error + Send + Sync + 'static> From<ShiftDrCommand<E>> for JtagCommand {
1317    fn from(value: ShiftDrCommand<E>) -> Self {
1318        let typed_transform = value.transform;
1319
1320        let erased_command = ErasedCommand {
1321            inner: value.inner,
1322            transform: Box::new(move |data, bits| {
1323                (typed_transform)(data, bits)
1324                    .map_err(|e| Box::new(e) as Box<dyn std::error::Error + Send + Sync>)
1325            }),
1326        };
1327
1328        JtagCommand::ShiftDr(erased_command)
1329    }
1330}
1331
1332/// Type alias for the erased transform function used in batched JTAG commands.
1333pub(crate) type ErasedTransformFn<T> = Box<
1334    dyn Fn(&T, &BitSlice) -> Result<CommandResult, Box<dyn std::error::Error + Send + Sync>>
1335        + Send
1336        + Sync,
1337>;
1338
1339/// An erased JTAG register write command (internal use).
1340pub(crate) struct ErasedCommand<T> {
1341    /// The inner data for the write command.
1342    pub inner: T,
1343
1344    /// A function to transform the raw response into a [`CommandResult`]
1345    pub transform: ErasedTransformFn<T>,
1346}
1347
1348impl<T: std::fmt::Debug> std::fmt::Debug for ErasedCommand<T> {
1349    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1350        f.debug_struct("ErasedCommand")
1351            .field("inner", &self.inner)
1352            .field("transform", &"<fn>")
1353            .finish()
1354    }
1355}
1356
1357/// A low-level JTAG command (uses type-erased commands internally).
1358#[derive(Debug)]
1359pub(crate) enum JtagCommand {
1360    /// Write a register.
1361    WriteRegister(ErasedCommand<JtagWriteData>),
1362    /// Shift a value into the DR register.
1363    ShiftDr(ErasedCommand<ShiftDrData>),
1364}
1365
1366impl From<ErasedCommand<JtagWriteData>> for JtagCommand {
1367    fn from(cmd: ErasedCommand<JtagWriteData>) -> Self {
1368        JtagCommand::WriteRegister(cmd)
1369    }
1370}
1371
1372impl From<ErasedCommand<ShiftDrData>> for JtagCommand {
1373    fn from(cmd: ErasedCommand<ShiftDrData>) -> Self {
1374        JtagCommand::ShiftDr(cmd)
1375    }
1376}
1377
1378/// Chain parameters to select a target tap within the chain.
1379#[derive(Clone, Copy, Debug, Default)]
1380pub struct ChainParams {
1381    /// The TAP's position in the chain.
1382    pub index: usize,
1383
1384    /// IR bits to shift before the TAP.
1385    pub irpre: usize,
1386
1387    /// IR bits to shift after the TAP.
1388    pub irpost: usize,
1389
1390    /// DR bits to shift before the TAP.
1391    pub drpre: usize,
1392
1393    /// DR bits to shift after the TAP.
1394    pub drpost: usize,
1395
1396    /// Length of the instruction register.
1397    pub irlen: usize,
1398}
1399
1400impl ChainParams {
1401    fn from_jtag_chain(chain: &[ScanChainElement], selected: usize) -> Option<Self> {
1402        let mut params = Self {
1403            index: selected,
1404            ..Default::default()
1405        };
1406        let mut found = false;
1407        for (index, tap) in chain.iter().enumerate() {
1408            let ir_len = tap.ir_len() as usize;
1409            if index == selected {
1410                params.irlen = ir_len;
1411                found = true;
1412            } else if found {
1413                params.irpost += ir_len;
1414                params.drpost += 1;
1415            } else {
1416                params.irpre += ir_len;
1417                params.drpre += 1;
1418            }
1419        }
1420
1421        found.then_some(params)
1422    }
1423}
1424
1425/// Results generated by `JtagCommand`s
1426#[derive(Debug, Clone)]
1427pub enum CommandResult {
1428    /// No result
1429    None,
1430
1431    /// A single byte
1432    U8(u8),
1433
1434    /// A single 16-bit word
1435    U16(u16),
1436
1437    /// A single 32-bit word
1438    U32(u32),
1439
1440    /// Multiple bytes
1441    VecU8(Vec<u8>),
1442}
1443
1444impl CommandResult {
1445    /// Returns the result as a `u32` if possible.
1446    ///
1447    /// # Panics
1448    ///
1449    /// Panics if the result is not a `u32`.
1450    pub fn into_u32(self) -> u32 {
1451        match self {
1452            CommandResult::U32(val) => val,
1453            _ => panic!("CommandResult is not a u32"),
1454        }
1455    }
1456
1457    /// Returns the result as a `u8` if possible.
1458    ///
1459    /// # Panics
1460    ///
1461    /// Panics if the result is not a `u8`.
1462    pub fn into_u8(self) -> u8 {
1463        match self {
1464            CommandResult::U8(val) => val,
1465            _ => panic!("CommandResult is not a u8"),
1466        }
1467    }
1468}
1469
1470/// The method that should be used for attaching.
1471#[derive(PartialEq, Eq, Debug, Copy, Clone, Default, Serialize, Deserialize)]
1472pub enum AttachMethod {
1473    /// Attach normally with no special behavior.
1474    #[default]
1475    Normal,
1476    /// Attach to the target while it is in reset.
1477    ///
1478    /// This is required on targets that can remap SWD pins or disable the SWD interface in sleep.
1479    UnderReset,
1480}
1481
1482#[cfg(test)]
1483mod test {
1484    use super::*;
1485
1486    #[test]
1487    fn test_is_probe_factory() {
1488        let probe_info = DebugProbeInfo::new(
1489            "Mock probe",
1490            0x12,
1491            0x23,
1492            Some("mock_serial".to_owned()),
1493            &ftdi::FtdiProbeFactory,
1494            None,
1495            false,
1496        );
1497
1498        assert!(probe_info.is_probe_type::<ftdi::FtdiProbeFactory>());
1499        assert!(!probe_info.is_probe_type::<jlink::JLinkFactory>());
1500    }
1501}