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, ®istry)
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, ®istry)
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}