|
|
@ -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");
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|