pub(crate) mod daplink;
pub(crate) mod jlink;
pub(crate) mod stlink;
use crate::architecture::arm::{DAPAccess, PortType};
use crate::config::{RegistryError, TargetSelector};
use crate::error::Error;
use crate::{Memory, Session};
use jlink::list_jlink_devices;
use std::fmt;
use thiserror::Error;
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum WireProtocol {
Swd,
Jtag,
}
impl fmt::Display for WireProtocol {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
WireProtocol::Swd => write!(f, "SWD"),
WireProtocol::Jtag => write!(f, "JTAG"),
}
}
}
impl std::str::FromStr for WireProtocol {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match &s.to_ascii_lowercase()[..] {
"swd" => Ok(WireProtocol::Swd),
"jtag" => Ok(WireProtocol::Jtag),
_ => Err(format!(
"'{}' is not a valid protocol. Choose from [swd, jtag].",
s
)),
}
}
}
#[derive(Error, Debug)]
pub enum DebugProbeError {
#[error("USB Communication Error")]
USB(#[source] Option<Box<dyn std::error::Error + Send + Sync>>),
#[error("JTAG not supported on probe")]
JTAGNotSupportedOnProbe,
#[error("The firmware on the probe is outdated")]
ProbeFirmwareOutdated,
#[error("An error specific to a probe type occured: {0}")]
ProbeSpecific(#[source] Box<dyn std::error::Error + Send + Sync>),
#[error("An unknown error occured.")]
Unknown,
#[error("Probe could not be created.")]
ProbeCouldNotBeCreated,
#[error("Probe does not support protocol {0}.")]
UnsupportedProtocol(WireProtocol),
#[error("Operation timed out.")]
Timeout,
#[error("An error specific to the selected architecture occured: {0}")]
ArchitectureSpecific(#[source] Box<dyn std::error::Error + Send + Sync>),
#[error("The connected probe does not support the interface '{0}'")]
InterfaceNotAvailable(&'static str),
#[error("An error occured while working with the registry occured: {0}")]
Registry(#[from] RegistryError),
#[error("Tried to close interface while it was still in use.")]
InterfaceInUse,
#[error("The requested speed setting ({0} kHz) is not supported by the probe.")]
UnsupportedSpeed(u32),
}
#[derive(Debug)]
pub struct Probe {
inner: Box<dyn DebugProbe>,
}
impl Probe {
pub fn new(probe: impl DebugProbe + 'static) -> Self {
Self {
inner: Box::new(probe),
}
}
pub fn list_all() -> Vec<DebugProbeInfo> {
let mut list = daplink::tools::list_daplink_devices();
list.extend(stlink::tools::list_stlink_devices());
list.extend(list_jlink_devices().expect("Failed to list J-Link devices."));
list
}
pub fn from_probe_info(info: &DebugProbeInfo) -> Result<Self, DebugProbeError> {
let probe = match info.probe_type {
DebugProbeType::DAPLink => {
let mut dap_link = daplink::DAPLink::new_from_probe_info(info)?;
dap_link.attach()?;
Probe::from_specific_probe(dap_link)
}
DebugProbeType::STLink => {
let mut link = stlink::STLink::new_from_probe_info(info)?;
link.attach()?;
Probe::from_specific_probe(link)
}
DebugProbeType::JLink => {
let mut link = jlink::JLink::new_from_probe_info(info)?;
link.attach()?;
Probe::from_specific_probe(link)
}
};
Ok(probe)
}
pub fn from_specific_probe(probe: Box<dyn DebugProbe>) -> Self {
Probe { inner: probe }
}
pub fn get_name(&self) -> String {
self.inner.get_name().to_string()
}
pub fn attach(mut self, target: impl Into<TargetSelector>) -> Result<Session, Error> {
self.inner.attach()?;
Session::new(self, target)
}
pub fn select_protocol(&mut self, protocol: WireProtocol) -> Result<(), DebugProbeError> {
self.inner.select_protocol(protocol)
}
pub fn detach(&mut self) -> Result<(), DebugProbeError> {
self.inner.detach()
}
pub fn target_reset(&mut self) -> Result<(), DebugProbeError> {
self.inner.target_reset()
}
pub fn set_speed(&mut self, speed_khz: u32) -> Result<u32, DebugProbeError> {
self.inner.set_speed(speed_khz)
}
pub fn speed_khz(&self) -> u32 {
self.inner.speed()
}
pub fn dedicated_memory_interface(&self) -> Option<Memory> {
self.inner.dedicated_memory_interface()
}
pub fn has_dap_interface(&self) -> bool {
self.inner.get_interface_dap().is_some()
}
pub fn get_interface_dap(&self) -> Option<&dyn DAPAccess> {
self.inner.get_interface_dap()
}
pub fn get_interface_dap_mut(&mut self) -> Option<&mut dyn DAPAccess> {
self.inner.get_interface_dap_mut()
}
pub fn has_jtag_interface(&self) -> bool {
self.inner.get_interface_jtag().is_some()
}
pub fn get_interface_jtag(&self) -> Option<&dyn JTAGAccess> {
self.inner.get_interface_jtag()
}
pub fn get_interface_jtag_mut(&mut self) -> Option<&mut dyn JTAGAccess> {
self.inner.get_interface_jtag_mut()
}
}
pub trait DebugProbe: Send + Sync + fmt::Debug {
fn new_from_probe_info(info: &DebugProbeInfo) -> Result<Box<Self>, DebugProbeError>
where
Self: Sized;
fn get_name(&self) -> &str;
fn speed(&self) -> u32;
fn set_speed(&mut self, speed_khz: u32) -> Result<u32, DebugProbeError>;
fn attach(&mut self) -> Result<(), DebugProbeError>;
fn detach(&mut self) -> Result<(), DebugProbeError>;
fn target_reset(&mut self) -> Result<(), DebugProbeError>;
fn select_protocol(&mut self, protocol: WireProtocol) -> Result<(), DebugProbeError>;
fn dedicated_memory_interface(&self) -> Option<Memory>;
fn get_interface_dap(&self) -> Option<&dyn DAPAccess>;
fn get_interface_dap_mut(&mut self) -> Option<&mut dyn DAPAccess>;
fn get_interface_jtag(&self) -> Option<&dyn JTAGAccess>;
fn get_interface_jtag_mut(&mut self) -> Option<&mut dyn JTAGAccess>;
}
#[derive(Debug, Clone)]
pub enum DebugProbeType {
DAPLink,
STLink,
JLink,
}
#[derive(Clone)]
pub struct DebugProbeInfo {
pub identifier: String,
pub vendor_id: u16,
pub product_id: u16,
pub serial_number: Option<String>,
pub probe_type: DebugProbeType,
}
impl std::fmt::Debug for DebugProbeInfo {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"{} (VID: {}, PID: {}, {}{:?})",
self.identifier,
self.vendor_id,
self.product_id,
self.serial_number
.clone()
.map_or("".to_owned(), |v| format!("Serial: {},", v)),
self.probe_type
)
}
}
impl DebugProbeInfo {
pub fn new<S: Into<String>>(
identifier: S,
vendor_id: u16,
product_id: u16,
serial_number: Option<String>,
probe_type: DebugProbeType,
) -> Self {
Self {
identifier: identifier.into(),
vendor_id,
product_id,
serial_number,
probe_type,
}
}
pub fn open(&self) -> Result<Probe, DebugProbeError> {
Probe::from_probe_info(&self)
}
}
#[derive(Default, Debug)]
pub struct FakeProbe;
impl DebugProbe for FakeProbe {
fn new_from_probe_info(_info: &DebugProbeInfo) -> Result<Box<Self>, DebugProbeError>
where
Self: Sized,
{
Err(DebugProbeError::ProbeCouldNotBeCreated)
}
fn get_name(&self) -> &str {
"Mock probe for testing"
}
fn speed(&self) -> u32 {
unimplemented!()
}
fn set_speed(&mut self, _speed_khz: u32) -> Result<u32, DebugProbeError> {
unimplemented!()
}
fn attach(&mut self) -> Result<(), DebugProbeError> {
unimplemented!()
}
fn select_protocol(&mut self, _protocol: WireProtocol) -> Result<(), DebugProbeError> {
unimplemented!()
}
fn detach(&mut self) -> Result<(), DebugProbeError> {
Ok(())
}
fn target_reset(&mut self) -> Result<(), DebugProbeError> {
Err(DebugProbeError::Unknown)
}
fn dedicated_memory_interface(&self) -> Option<Memory> {
None
}
fn get_interface_dap(&self) -> Option<&dyn DAPAccess> {
None
}
fn get_interface_dap_mut(&mut self) -> Option<&mut dyn DAPAccess> {
None
}
fn get_interface_jtag(&self) -> Option<&dyn JTAGAccess> {
None
}
fn get_interface_jtag_mut(&mut self) -> Option<&mut dyn JTAGAccess> {
None
}
}
impl DAPAccess for FakeProbe {
fn read_register(&mut self, _port: PortType, _addr: u16) -> Result<u32, DebugProbeError> {
Err(DebugProbeError::Unknown)
}
fn write_register(
&mut self,
_port: PortType,
_addr: u16,
_value: u32,
) -> Result<(), DebugProbeError> {
Err(DebugProbeError::Unknown)
}
}
pub trait JTAGAccess {
fn read_register(&mut self, address: u32, len: u32) -> Result<Vec<u8>, DebugProbeError>;
fn set_idle_cycles(&mut self, idle_cycles: u8);
fn write_register(
&mut self,
address: u32,
data: &[u8],
len: u32,
) -> Result<Vec<u8>, DebugProbeError>;
}