Browse Source

WIP: very early ICDI hack

Basically a copypasta from stlink with names and USB VID/PID changed.
Currently the probe is detected but can't be created.
master
Marc Poulhiès 2 years ago
parent
commit
a578d1b0dc
  1. 410
      probe-rs/src/probe/icdi/mod.rs
  2. 10
      probe-rs/src/probe/icdi/tools.rs
  3. 66
      probe-rs/src/probe/icdi/usb_interface.rs
  4. 7
      probe-rs/src/probe/mod.rs

410
probe-rs/src/probe/icdi/mod.rs

@ -2,7 +2,7 @@ pub mod constants;
pub mod tools;
mod usb_interface;
use self::usb_interface::{STLinkUSBDevice, StLinkUsb};
use self::usb_interface::{ICDIUSBDevice, IcdiUsb};
use super::{DAPAccess, DebugProbe, DebugProbeError, PortType, ProbeCreationError, WireProtocol};
use crate::{
architecture::arm::{
@ -24,7 +24,7 @@ use thiserror::Error;
use usb_interface::TIMEOUT;
#[derive(Debug)]
pub struct STLink<D: StLinkUsb> {
pub struct ICDI<D: IcdiUsb> {
device: D,
hw_version: u8,
jtag_version: u8,
@ -37,12 +37,12 @@ pub struct STLink<D: StLinkUsb> {
openend_aps: Vec<u8>,
}
impl DebugProbe for STLink<STLinkUSBDevice> {
impl DebugProbe for ICDI<ICDIUSBDevice> {
fn new_from_selector(
selector: impl Into<DebugProbeSelector>,
) -> Result<Box<Self>, DebugProbeError> {
let mut stlink = Self {
device: STLinkUSBDevice::new_from_selector(selector)?,
let mut icdi = Self {
device: ICDIUSBDevice::new_from_selector(selector)?,
hw_version: 0,
jtag_version: 0,
protocol: WireProtocol::Swd,
@ -53,13 +53,13 @@ impl DebugProbe for STLink<STLinkUSBDevice> {
openend_aps: vec![],
};
stlink.init()?;
// icdi.init()?;
Ok(Box::new(stlink))
Ok(Box::new(icdi))
}
fn get_name(&self) -> &str {
"ST-Link"
"ICDI"
}
fn speed(&self) -> u32 {
@ -164,7 +164,7 @@ impl DebugProbe for STLink<STLinkUSBDevice> {
}
fn detach(&mut self) -> Result<(), DebugProbeError> {
log::debug!("Detaching from STLink.");
log::debug!("Detaching from ICDI.");
if self.swo_enabled {
self.disable_swo()
.map_err(|e| DebugProbeError::ProbeSpecific(e.into()))?;
@ -233,7 +233,7 @@ impl DebugProbe for STLink<STLinkUSBDevice> {
fn get_arm_interface<'probe>(
self: Box<Self>,
) -> Result<Option<Box<dyn ArmProbeInterface + 'probe>>, DebugProbeError> {
let interface = StlinkArmDebug::new(self)?;
let interface = IcdiArmDebug::new(self)?;
Ok(Some(Box::new(interface)))
}
@ -243,7 +243,7 @@ impl DebugProbe for STLink<STLinkUSBDevice> {
}
}
impl DAPAccess for STLink<STLinkUSBDevice> {
impl DAPAccess for ICDI<ICDIUSBDevice> {
/// Reads the DAP register on the specified port and address.
fn read_register(&mut self, port: PortType, addr: u16) -> Result<u32, DebugProbeError> {
if (addr & 0xf0) == 0 || port != PortType::DebugPort {
@ -266,7 +266,7 @@ impl DAPAccess for STLink<STLinkUSBDevice> {
// Unwrap is ok!
Ok((&buf[4..8]).pread_with(0, LE).unwrap())
} else {
Err(StlinkError::BlanksNotAllowedOnDPRegister.into())
Err(IcdiError::BlanksNotAllowedOnDPRegister.into())
}
}
@ -304,7 +304,7 @@ impl DAPAccess for STLink<STLinkUSBDevice> {
Ok(())
} else {
Err(StlinkError::BlanksNotAllowedOnDPRegister.into())
Err(IcdiError::BlanksNotAllowedOnDPRegister.into())
}
}
@ -319,19 +319,19 @@ impl DAPAccess for STLink<STLinkUSBDevice> {
}
}
impl<'a> AsRef<dyn DebugProbe + 'a> for STLink<STLinkUSBDevice> {
impl<'a> AsRef<dyn DebugProbe + 'a> for ICDI<ICDIUSBDevice> {
fn as_ref(&self) -> &(dyn DebugProbe + 'a) {
self
}
}
impl<'a> AsMut<dyn DebugProbe + 'a> for STLink<STLinkUSBDevice> {
impl<'a> AsMut<dyn DebugProbe + 'a> for ICDI<ICDIUSBDevice> {
fn as_mut(&mut self) -> &mut (dyn DebugProbe + 'a) {
self
}
}
impl<D: StLinkUsb> Drop for STLink<D> {
impl<D: IcdiUsb> Drop for ICDI<D> {
fn drop(&mut self) {
// We ignore the error cases as we can't do much about it anyways.
if self.swo_enabled {
@ -341,7 +341,7 @@ impl<D: StLinkUsb> Drop for STLink<D> {
}
}
impl<D: StLinkUsb> STLink<D> {
impl<D: IcdiUsb> ICDI<D> {
/// Maximum number of bytes to send or receive for 32- and 16- bit transfers.
///
/// 8-bit transfers have a maximum size of the maximum USB packet size (64 bytes for full speed).
@ -374,7 +374,7 @@ impl<D: StLinkUsb> STLink<D> {
Ok((2.0 * a1 * 1.2 / a0) as f32)
} else {
// Should never happen
Err(StlinkError::VoltageDivisionByZero.into())
Err(IcdiError::VoltageDivisionByZero.into())
}
}
Err(e) => Err(e),
@ -395,7 +395,7 @@ impl<D: StLinkUsb> STLink<D> {
1 => MassStorage,
2 => Jtag,
3 => Swim,
_ => return Err(StlinkError::UnknownMode.into()),
_ => return Err(IcdiError::UnknownMode.into()),
};
log::debug!("Current device mode: {:?}", mode);
@ -479,7 +479,7 @@ impl<D: StLinkUsb> STLink<D> {
// Make sure everything is okay with the firmware we use.
if self.jtag_version == 0 {
return Err(StlinkError::JTAGNotSupportedOnProbe.into());
return Err(IcdiError::JTAGNotSupportedOnProbe.into());
}
if self.hw_version < 3 && self.jtag_version < Self::MIN_JTAG_VERSION {
return Err(DebugProbeError::ProbeFirmwareOutdated);
@ -494,7 +494,7 @@ impl<D: StLinkUsb> STLink<D> {
/// Opens the ST-Link USB device and tries to identify the ST-Links version and its target voltage.
/// Internal helper.
fn init(&mut self) -> Result<(), DebugProbeError> {
log::debug!("Initializing STLink...");
log::debug!("Initializing ICDI...");
if let Err(e) = self.enter_idle() {
match e {
@ -510,7 +510,7 @@ impl<D: StLinkUsb> STLink<D> {
}
let version = self.get_version()?;
log::debug!("STLink version: {:?}", version);
log::debug!("ICDI version: {:?}", version);
if self.hw_version == 3 {
let (_, current) = self.get_communication_frequencies(WireProtocol::Swd)?;
@ -703,7 +703,7 @@ impl<D: StLinkUsb> STLink<D> {
}
status => {
log::warn!("send_jtag_command {} failed: {:?}", cmd[0], status);
return Err(From::from(StlinkError::CommandFailed(status)));
return Err(From::from(IcdiError::CommandFailed(status)));
}
}
@ -715,7 +715,7 @@ impl<D: StLinkUsb> STLink<D> {
// Return the last error (will be SwdDpWait or SwdApWait)
let status = Status::from(read_data[0]);
return Err(From::from(StlinkError::CommandFailed(status)));
return Err(From::from(IcdiError::CommandFailed(status)));
}
pub fn start_trace_reception(&mut self, config: &SwoConfig) -> Result<(), DebugProbeError> {
@ -1036,7 +1036,7 @@ impl<D: StLinkUsb> STLink<D> {
}
}
impl<D: StLinkUsb> SwoAccess for STLink<D> {
impl<D: IcdiUsb> SwoAccess for ICDI<D> {
fn enable_swo(&mut self, config: &SwoConfig) -> Result<(), ProbeRsError> {
match config.mode() {
SwoMode::UART => {
@ -1044,7 +1044,7 @@ impl<D: StLinkUsb> SwoAccess for STLink<D> {
Ok(())
}
SwoMode::Manchester => Err(DebugProbeError::ProbeSpecific(
StlinkError::ManchesterSwoNotSupported.into(),
IcdiError::ManchesterSwoNotSupported.into(),
)
.into()),
}
@ -1062,7 +1062,7 @@ impl<D: StLinkUsb> SwoAccess for STLink<D> {
}
#[derive(Error, Debug)]
pub(crate) enum StlinkError {
pub(crate) enum IcdiError {
#[error("Invalid voltage values returned by probe.")]
VoltageDivisionByZero,
#[error("Probe is an unknown mode.")]
@ -1081,26 +1081,26 @@ pub(crate) enum StlinkError {
ManchesterSwoNotSupported,
}
impl From<StlinkError> for DebugProbeError {
fn from(e: StlinkError) -> Self {
impl From<IcdiError> for DebugProbeError {
fn from(e: IcdiError) -> Self {
DebugProbeError::ProbeSpecific(Box::new(e))
}
}
impl From<StlinkError> for ProbeCreationError {
fn from(e: StlinkError) -> Self {
impl From<IcdiError> for ProbeCreationError {
fn from(e: IcdiError) -> Self {
ProbeCreationError::ProbeSpecific(Box::new(e))
}
}
#[derive(Debug)]
struct StlinkArmDebug {
probe: Box<STLink<STLinkUSBDevice>>,
struct IcdiArmDebug {
probe: Box<ICDI<ICDIUSBDevice>>,
state: ArmCommunicationInterfaceState,
}
impl StlinkArmDebug {
fn new(probe: Box<STLink<STLinkUSBDevice>>) -> Result<Self, DebugProbeError> {
impl IcdiArmDebug {
fn new(probe: Box<ICDI<ICDIUSBDevice>>) -> Result<Self, DebugProbeError> {
let state = ArmCommunicationInterfaceState::new();
// Determine the number and type of available APs.
@ -1350,7 +1350,7 @@ impl StlinkArmDebug {
}
}
impl DPAccess for StlinkArmDebug {
impl DPAccess for IcdiArmDebug {
fn read_dp_register<R: DPRegister>(&mut self) -> Result<R, DebugPortError> {
if R::VERSION > self.state.debug_port_version {
return Err(DebugPortError::UnsupportedRegister {
@ -1391,9 +1391,9 @@ impl DPAccess for StlinkArmDebug {
}
}
impl<'probe> ArmProbeInterface for StlinkArmDebug {
impl<'probe> ArmProbeInterface for IcdiArmDebug {
fn memory_interface(&mut self, access_port: MemoryAP) -> Result<Memory<'_>, ProbeRsError> {
let interface = StLinkMemoryInterface {
let interface = IcdiMemoryInterface {
probe: self,
access_port,
};
@ -1454,7 +1454,7 @@ impl<'probe> ArmProbeInterface for StlinkArmDebug {
}
}
impl<AP, R> APAccess<AP, R> for StlinkArmDebug
impl<AP, R> APAccess<AP, R> for IcdiArmDebug
where
R: APRegister<AP> + Clone,
AP: AccessPort,
@ -1488,19 +1488,19 @@ where
}
}
impl<'a> AsRef<dyn DebugProbe + 'a> for StlinkArmDebug {
impl<'a> AsRef<dyn DebugProbe + 'a> for IcdiArmDebug {
fn as_ref(&self) -> &(dyn DebugProbe + 'a) {
self.probe.as_ref()
}
}
impl<'a> AsMut<dyn DebugProbe + 'a> for StlinkArmDebug {
impl<'a> AsMut<dyn DebugProbe + 'a> for IcdiArmDebug {
fn as_mut(&mut self) -> &mut (dyn DebugProbe + 'a) {
self.probe.as_mut()
}
}
impl SwoAccess for StlinkArmDebug {
impl SwoAccess for IcdiArmDebug {
fn enable_swo(&mut self, config: &SwoConfig) -> Result<(), ProbeRsError> {
self.probe.enable_swo(config)
}
@ -1515,12 +1515,12 @@ impl SwoAccess for StlinkArmDebug {
}
#[derive(Debug)]
struct StLinkMemoryInterface<'probe> {
probe: &'probe mut StlinkArmDebug,
struct IcdiMemoryInterface<'probe> {
probe: &'probe mut IcdiArmDebug,
access_port: MemoryAP,
}
impl MemoryInterface for StLinkMemoryInterface<'_> {
impl MemoryInterface for IcdiMemoryInterface<'_> {
fn read_word_32(&mut self, address: u32) -> Result<u32, ProbeRsError> {
self.probe.select_ap(self.access_port)?;
@ -1679,163 +1679,163 @@ impl MemoryInterface for StLinkMemoryInterface<'_> {
}
}
#[cfg(test)]
mod test {
use super::{constants::commands, usb_interface::StLinkUsb, STLink};
use crate::{DebugProbeError, WireProtocol};
use scroll::Pwrite;
#[derive(Debug)]
struct MockUsb {
hw_version: u8,
jtag_version: u8,
swim_version: u8,
target_voltage_a0: f32,
target_voltage_a1: f32,
}
impl MockUsb {
fn build(self) -> STLink<MockUsb> {
STLink {
device: self,
hw_version: 0,
protocol: WireProtocol::Swd,
jtag_version: 0,
swd_speed_khz: 0,
jtag_speed_khz: 0,
swo_enabled: false,
openend_aps: vec![],
}
}
}
impl StLinkUsb for MockUsb {
fn write(
&mut self,
cmd: &[u8],
_write_data: &[u8],
read_data: &mut [u8],
_timeout: std::time::Duration,
) -> Result<(), crate::DebugProbeError> {
match cmd[0] {
commands::GET_VERSION => {
// GET_VERSION response structure:
// Byte 0-1:
// [15:12] Major/HW version
// [11:6] JTAG/SWD version
// [5:0] SWIM or MSC version
// Byte 2-3: ST_VID
// Byte 4-5: STLINK_PID
let version: u16 = ((self.hw_version as u16) << 12)
| ((self.jtag_version as u16) << 6)
| ((self.swim_version as u16) << 0);
read_data[0] = (version >> 8) as u8;
read_data[1] = version as u8;
Ok(())
}
commands::GET_TARGET_VOLTAGE => {
read_data.pwrite(self.target_voltage_a0, 0).unwrap();
read_data.pwrite(self.target_voltage_a0, 4).unwrap();
Ok(())
}
commands::JTAG_COMMAND => {
// Return a status of OK for JTAG commands
read_data[0] = 0x80;
Ok(())
}
_ => Ok(()),
}
}
fn reset(&mut self) -> Result<(), crate::DebugProbeError> {
Ok(())
}
fn read_swo(
&mut self,
_read_data: &mut [u8],
_timeout: std::time::Duration,
) -> Result<usize, DebugProbeError> {
unimplemented!("Not implemented for MockUSB")
}
}
#[test]
fn detect_old_firmware() {
// Test that the init function detects old, unsupported firmware.
let usb_mock = MockUsb {
hw_version: 2,
jtag_version: 20,
swim_version: 0,
target_voltage_a0: 1.0,
target_voltage_a1: 2.0,
};
let mut probe = usb_mock.build();
let init_result = probe.init();
match init_result.unwrap_err() {
DebugProbeError::ProbeFirmwareOutdated => (),
other => panic!("Expected firmware outdated error, got {}", other),
}
}
#[test]
fn firmware_without_multiple_ap_support() {
// Test that firmware with only support for a single AP works,
// as long as only AP 0 is selected
let usb_mock = MockUsb {
hw_version: 2,
jtag_version: 26,
swim_version: 0,
target_voltage_a0: 1.0,
target_voltage_a1: 2.0,
};
let mut probe = usb_mock.build();
probe.init().expect("Init function failed");
// Selecting AP 0 should still work
probe.select_ap(0).expect("Select AP 0 failed.");
probe
.select_ap(1)
.expect_err("Selecting AP other than AP 0 should fail");
}
#[test]
fn firmware_with_multiple_ap_support() {
// Test that firmware with only support for a single AP works,
// as long as only AP 0 is selected
let usb_mock = MockUsb {
hw_version: 2,
jtag_version: 30,
swim_version: 0,
target_voltage_a0: 1.0,
target_voltage_a1: 2.0,
};
let mut probe = usb_mock.build();
probe.init().expect("Init function failed");
// Selecting AP 0 should still work
probe.select_ap(0).expect("Select AP 0 failed.");
probe
.select_ap(1)
.expect("Selecting AP other than AP 0 should work");
}
}
// #[cfg(test)]
// mod test {
// use super::{constants::commands, usb_interface::StLinkUsb, STLink};
// use crate::{DebugProbeError, WireProtocol};
// use scroll::Pwrite;
// #[derive(Debug)]
// struct MockUsb {
// hw_version: u8,
// jtag_version: u8,
// swim_version: u8,
// target_voltage_a0: f32,
// target_voltage_a1: f32,
// }
// impl MockUsb {
// fn build(self) -> STLink<MockUsb> {
// STLink {
// device: self,
// hw_version: 0,
// protocol: WireProtocol::Swd,
// jtag_version: 0,
// swd_speed_khz: 0,
// jtag_speed_khz: 0,
// swo_enabled: false,
// openend_aps: vec![],
// }
// }
// }
// impl StLinkUsb for MockUsb {
// fn write(
// &mut self,
// cmd: &[u8],
// _write_data: &[u8],
// read_data: &mut [u8],
// _timeout: std::time::Duration,
// ) -> Result<(), crate::DebugProbeError> {
// match cmd[0] {
// commands::GET_VERSION => {
// // GET_VERSION response structure:
// // Byte 0-1:
// // [15:12] Major/HW version
// // [11:6] JTAG/SWD version
// // [5:0] SWIM or MSC version
// // Byte 2-3: ST_VID
// // Byte 4-5: STLINK_PID
// let version: u16 = ((self.hw_version as u16) << 12)
// | ((self.jtag_version as u16) << 6)
// | ((self.swim_version as u16) << 0);
// read_data[0] = (version >> 8) as u8;
// read_data[1] = version as u8;
// Ok(())
// }
// commands::GET_TARGET_VOLTAGE => {
// read_data.pwrite(self.target_voltage_a0, 0).unwrap();
// read_data.pwrite(self.target_voltage_a0, 4).unwrap();
// Ok(())
// }
// commands::JTAG_COMMAND => {
// // Return a status of OK for JTAG commands
// read_data[0] = 0x80;
// Ok(())
// }
// _ => Ok(()),
// }
// }
// fn reset(&mut self) -> Result<(), crate::DebugProbeError> {
// Ok(())
// }
// fn read_swo(
// &mut self,
// _read_data: &mut [u8],
// _timeout: std::time::Duration,
// ) -> Result<usize, DebugProbeError> {
// unimplemented!("Not implemented for MockUSB")
// }
// }
// #[test]
// fn detect_old_firmware() {
// // Test that the init function detects old, unsupported firmware.
// let usb_mock = MockUsb {
// hw_version: 2,
// jtag_version: 20,
// swim_version: 0,
// target_voltage_a0: 1.0,
// target_voltage_a1: 2.0,
// };
// let mut probe = usb_mock.build();
// let init_result = probe.init();
// match init_result.unwrap_err() {
// DebugProbeError::ProbeFirmwareOutdated => (),
// other => panic!("Expected firmware outdated error, got {}", other),
// }
// }
// #[test]
// fn firmware_without_multiple_ap_support() {
// // Test that firmware with only support for a single AP works,
// // as long as only AP 0 is selected
// let usb_mock = MockUsb {
// hw_version: 2,
// jtag_version: 26,
// swim_version: 0,
// target_voltage_a0: 1.0,
// target_voltage_a1: 2.0,
// };
// let mut probe = usb_mock.build();
// probe.init().expect("Init function failed");
// // Selecting AP 0 should still work
// probe.select_ap(0).expect("Select AP 0 failed.");
// probe
// .select_ap(1)
// .expect_err("Selecting AP other than AP 0 should fail");
// }
// #[test]
// fn firmware_with_multiple_ap_support() {
// // Test that firmware with only support for a single AP works,
// // as long as only AP 0 is selected
// let usb_mock = MockUsb {
// hw_version: 2,
// jtag_version: 30,
// swim_version: 0,
// target_voltage_a0: 1.0,
// target_voltage_a1: 2.0,
// };
// let mut probe = usb_mock.build();
// probe.init().expect("Init function failed");
// // Selecting AP 0 should still work
// probe.select_ap(0).expect("Select AP 0 failed.");
// probe
// .select_ap(1)
// .expect("Selecting AP other than AP 0 should work");
// }
// }

10
probe-rs/src/probe/icdi/tools.rs

@ -7,7 +7,7 @@ use super::usb_interface::USB_PID_EP_MAP;
use super::usb_interface::USB_VID;
use std::time::Duration;
pub(super) fn is_stlink_device<T: UsbContext>(device: &Device<T>) -> bool {
pub(super) fn is_icdi_device<T: UsbContext>(device: &Device<T>) -> bool {
// Check the VID/PID.
if let Ok(descriptor) = device.device_descriptor() {
(descriptor.vendor_id() == USB_VID)
@ -17,12 +17,12 @@ pub(super) fn is_stlink_device<T: UsbContext>(device: &Device<T>) -> bool {
}
}
pub fn list_stlink_devices() -> Vec<DebugProbeInfo> {
pub fn list_icdi_devices() -> Vec<DebugProbeInfo> {
if let Ok(context) = rusb::Context::new() {
if let Ok(devices) = context.devices() {
devices
.iter()
.filter(is_stlink_device)
.filter(is_icdi_device)
.filter_map(|device| {
let descriptor = device.device_descriptor().ok()?;
@ -45,13 +45,13 @@ pub fn list_stlink_devices() -> Vec<DebugProbeInfo> {
Some(DebugProbeInfo::new(
format!(
"STLink {}",
"ICDI {}",
&USB_PID_EP_MAP[&descriptor.product_id()].version_name
),
descriptor.vendor_id(),
descriptor.product_id(),
sn_str,
DebugProbeType::STLink,
DebugProbeType::ICDI,
))
})
.collect::<Vec<_>>()

66
probe-rs/src/probe/icdi/usb_interface.rs

@ -2,11 +2,11 @@ use lazy_static::lazy_static;
use rusb::{Context, DeviceHandle, Error, UsbContext};
use std::time::Duration;
use crate::probe::stlink::StlinkError;
use crate::probe::icdi::IcdiError;
use std::collections::HashMap;
use super::tools::{is_stlink_device, read_serial_number};
use super::tools::{is_icdi_device, read_serial_number};
use crate::{
probe::{DebugProbeError, ProbeCreationError},
DebugProbeSelector,
@ -16,29 +16,29 @@ use crate::{
const CMD_LEN: usize = 16;
/// The USB VendorID.
pub const USB_VID: u16 = 0x0483;
pub const USB_VID: u16 = 0x1cbe; // Luminary Micro Inc.
pub const TIMEOUT: Duration = Duration::from_millis(1000);
lazy_static! {
/// Map of USB PID to firmware version name and device endpoints.
pub static ref USB_PID_EP_MAP: HashMap<u16, STLinkInfo> = {
pub static ref USB_PID_EP_MAP: HashMap<u16, ICDIInfo> = {
let mut m = HashMap::new();
m.insert(0x3748, STLinkInfo::new("V2", 0x3748, 0x02, 0x81, 0x83));
m.insert(0x374b, STLinkInfo::new("V2-1", 0x374b, 0x01, 0x81, 0x82));
m.insert(0x374a, STLinkInfo::new("V2-1", 0x374a, 0x01, 0x81, 0x82)); // Audio
m.insert(0x3742, STLinkInfo::new("V2-1", 0x3742, 0x01, 0x81, 0x82)); // No MSD
m.insert(0x3752, STLinkInfo::new("V2-1", 0x3752, 0x01, 0x81, 0x82)); // Unproven
m.insert(0x374e, STLinkInfo::new("V3", 0x374e, 0x01, 0x81, 0x82));
m.insert(0x374f, STLinkInfo::new("V3", 0x374f, 0x01, 0x81, 0x82)); // Bridge
m.insert(0x3753, STLinkInfo::new("V3", 0x3753, 0x01, 0x81, 0x82)); // 2VCP
m.insert(0x00fd, ICDIInfo::new("V2", 0x00fd, 0x02, 0x81, 0x83));
// m.insert(0x374b, STLinkInfo::new("V2-1", 0x374b, 0x01, 0x81, 0x82));
// m.insert(0x374a, STLinkInfo::new("V2-1", 0x374a, 0x01, 0x81, 0x82)); // Audio
// m.insert(0x3742, STLinkInfo::new("V2-1", 0x3742, 0x01, 0x81, 0x82)); // No MSD
// m.insert(0x3752, STLinkInfo::new("V2-1", 0x3752, 0x01, 0x81, 0x82)); // Unproven
// m.insert(0x374e, STLinkInfo::new("V3", 0x374e, 0x01, 0x81, 0x82));
// m.insert(0x374f, STLinkInfo::new("V3", 0x374f, 0x01, 0x81, 0x82)); // Bridge
// m.insert(0x3753, STLinkInfo::new("V3", 0x3753, 0x01, 0x81, 0x82)); // 2VCP
m
};
}
/// A helper struct to match STLink deviceinfo.
#[derive(Clone, Debug, Default)]
pub struct STLinkInfo {
pub struct ICDIInfo {
pub version_name: String,
pub usb_pid: u16,
ep_out: u8,
@ -46,7 +46,7 @@ pub struct STLinkInfo {
ep_swo: u8,
}
impl STLinkInfo {
impl ICDIInfo {
pub fn new<V: Into<String>>(
version_name: V,
usb_pid: u16,
@ -64,21 +64,21 @@ impl STLinkInfo {
}
}
pub(crate) struct STLinkUSBDevice {
pub(crate) struct ICDIUSBDevice {
device_handle: DeviceHandle<rusb::Context>,
info: STLinkInfo,
info: ICDIInfo,
}
impl std::fmt::Debug for STLinkUSBDevice {
impl std::fmt::Debug for ICDIUSBDevice {
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
fmt.debug_struct("STLinkUSBDevice")
fmt.debug_struct("ICDIUSBDevice")
.field("device_handle", &"DeviceHandle<rusb::Context>")
.field("info", &self.info)
.finish()
}
}
pub trait StLinkUsb: std::fmt::Debug {
pub trait IcdiUsb: std::fmt::Debug {
fn write(
&mut self,
cmd: &[u8],
@ -98,7 +98,7 @@ pub trait StLinkUsb: std::fmt::Debug {
) -> Result<usize, DebugProbeError>;
}
impl STLinkUSBDevice {
impl ICDIUSBDevice {
/// Creates and initializes a new USB device.
pub fn new_from_selector(
selector: impl Into<DebugProbeSelector>,
@ -112,7 +112,7 @@ impl STLinkUSBDevice {
let device = context
.devices()?
.iter()
.filter(is_stlink_device)
.filter(is_icdi_device)
.find_map(|device| {
let descriptor = device.device_descriptor().ok()?;
// First match the VID & PID.
@ -174,15 +174,15 @@ impl STLinkUSBDevice {
}
if !endpoint_out {
return Err(StlinkError::EndpointNotFound.into());
return Err(IcdiError::EndpointNotFound.into());
}
if !endpoint_in {
return Err(StlinkError::EndpointNotFound.into());
return Err(IcdiError::EndpointNotFound.into());
}
if !endpoint_swo {
return Err(StlinkError::EndpointNotFound.into());
return Err(IcdiError::EndpointNotFound.into());
}
let usb_stlink = Self {
@ -190,7 +190,7 @@ impl STLinkUSBDevice {
info,
};
log::debug!("Succesfully attached to STLink.");
log::debug!("Succesfully attached to ICDI.");
Ok(usb_stlink)
}
@ -202,7 +202,7 @@ impl STLinkUSBDevice {
}
}
impl StLinkUsb for STLinkUSBDevice {
impl IcdiUsb for ICDIUSBDevice {
/// Writes to the out EP and reads back data if needed.
/// First the `cmd` is sent.
/// In a second step `write_data` is transmitted.
@ -215,7 +215,7 @@ impl StLinkUsb for STLinkUSBDevice {
timeout: Duration,
) -> Result<(), DebugProbeError> {
log::trace!(
"Sending command {:x?} to STLink, timeout: {:?}",
"Sending command {:x?} to ICDI, timeout: {:?}",
cmd,
timeout
);
@ -234,7 +234,7 @@ impl StLinkUsb for STLinkUSBDevice {
.map_err(|e| DebugProbeError::USB(Some(Box::new(e))))?;
if written_bytes != CMD_LEN {
return Err(StlinkError::NotEnoughBytesRead {
return Err(IcdiError::NotEnoughBytesRead {
is: written_bytes,
should: CMD_LEN,
}
@ -247,7 +247,7 @@ impl StLinkUsb for STLinkUSBDevice {
.write_bulk(ep_out, write_data, timeout)
.map_err(|e| DebugProbeError::USB(Some(Box::new(e))))?;
if written_bytes != write_data.len() {
return Err(StlinkError::NotEnoughBytesRead {
return Err(IcdiError::NotEnoughBytesRead {
is: written_bytes,
should: write_data.len(),
}
@ -261,7 +261,7 @@ impl StLinkUsb for STLinkUSBDevice {
.read_bulk(ep_in, read_data, timeout)
.map_err(|e| DebugProbeError::USB(Some(Box::new(e))))?;
if read_bytes != read_data.len() {
return Err(StlinkError::NotEnoughBytesRead {
return Err(IcdiError::NotEnoughBytesRead {
is: read_bytes,
should: read_data.len(),
}
@ -277,7 +277,7 @@ impl StLinkUsb for STLinkUSBDevice {
timeout: Duration,
) -> Result<usize, DebugProbeError> {
log::trace!(
"Reading {:?} SWO bytes to STLink, timeout: {:?}",
"Reading {:?} SWO bytes to ICDI, timeout: {:?}",
read_data.len(),
timeout
);
@ -298,14 +298,14 @@ impl StLinkUsb for STLinkUSBDevice {
/// Reset the USB device. This can be used to recover when the
/// STLink does not respond to USB requests.
fn reset(&mut self) -> Result<(), DebugProbeError> {
log::debug!("Resetting USB device of STLink");
log::debug!("Resetting USB device of ICDI");
self.device_handle
.reset()
.map_err(|e| DebugProbeError::USB(Some(Box::new(e))))
}
}
impl Drop for STLinkUSBDevice {
impl Drop for ICDIUSBDevice {
fn drop(&mut self) {
// We ignore the error case as we can't do much about it anyways.
let _ = self.close();

7
probe-rs/src/probe/mod.rs

@ -182,6 +182,7 @@ impl Probe {
list.extend(ftdi::list_ftdi_devices());
}
list.extend(stlink::tools::list_stlink_devices());
list.extend(icdi::tools::list_icdi_devices());
list.extend(list_jlink_devices().expect("Failed to list J-Link devices."));
@ -203,6 +204,11 @@ impl Probe {
Err(DebugProbeError::ProbeCouldNotBeCreated(ProbeCreationError::NotFound)) => {}
Err(e) => return Err(e),
};
match icdi::ICDI::new_from_selector(selector.clone()) {
Ok(link) => return Ok(Probe::from_specific_probe(link)),
Err(DebugProbeError::ProbeCouldNotBeCreated(ProbeCreationError::NotFound)) => {}
Err(e) => return Err(e),
};
match stlink::STLink::new_from_selector(selector.clone()) {
Ok(link) => return Ok(Probe::from_specific_probe(link)),
Err(DebugProbeError::ProbeCouldNotBeCreated(ProbeCreationError::NotFound)) => {}
@ -488,6 +494,7 @@ pub trait DebugProbe: Send + Sync + fmt::Debug {
pub enum DebugProbeType {
DAPLink,
FTDI,
ICDI,
STLink,
JLink,
}

Loading…
Cancel
Save