use color_eyre::eyre::{Result, eyre};
use owo_colors::OwoColorize;
use probe_rs::config::{MemoryRegion, Registry};
use probe_rs::probe::list::Lister;
use probe_rs::{Permissions, Session};
use std::fs;
use crate::cli::Cli;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct RamRange {
pub name: String,
pub start: u32,
pub end: u32,
}
impl RamRange {
pub fn len(&self) -> u32 {
self.end - self.start
}
pub fn is_empty(&self) -> bool {
self.end == self.start
}
}
pub fn open_session(cli: &Cli) -> Result<Session> {
let lister = Lister::new();
let probes = lister.list_all();
if probes.is_empty() {
return Err(eyre!("No probes found"));
}
let probe_info = match &cli.probe {
Some(sel) => probes
.iter()
.find(|p| p.identifier.contains(sel) || p.serial_number.as_deref() == Some(sel))
.ok_or_else(|| eyre!("Probe '{sel}' not found"))?,
None => &probes[0],
};
println!("Using probe: {}", probe_info.identifier.bold());
let probe = probe_info.open()?;
let target = cli.chip.clone();
let session = if let Some(chip_description_path) = cli.chip_description_path.as_ref() {
let yaml_content = fs::read_to_string(chip_description_path)?;
let mut registry = Registry::from_builtin_families();
registry.add_target_family_from_yaml(yaml_content.as_str())?;
probe.attach_with_registry(target, Permissions::default(), ®istry)?
} else {
probe.attach(cli.chip.clone(), Permissions::default())?
};
Ok(session)
}
pub fn discover_ram_regions(session: &Session) -> Vec<RamRange> {
session
.target()
.memory_map
.iter()
.filter_map(|region| match region {
MemoryRegion::Ram(r) => Some(RamRange {
name: r.name.clone().unwrap_or_else(|| "RAM".to_string()),
start: r.range.start as u32,
end: r.range.end as u32,
}),
_ => None,
})
.collect()
}
pub fn clip_to_block(region: &RamRange, block: u32) -> Option<RamRange> {
assert!(block > 0, "block must be > 0");
let len = region.len();
let kept = (len / block) * block;
if kept == 0 {
return None;
}
Some(RamRange {
name: region.name.clone(),
start: region.start,
end: region.start + kept,
})
}
#[cfg(test)]
mod tests {
use super::*;
fn rr(start: u32, end: u32) -> RamRange {
RamRange {
name: "T".into(),
start,
end,
}
}
#[test]
fn clip_exact_multiple_unchanged() {
let r = rr(0x2000_0000, 0x2000_4000); let c = clip_to_block(&r, 0x1000).unwrap();
assert_eq!(c, rr(0x2000_0000, 0x2000_4000));
}
#[test]
fn clip_drops_trailing_partial_block() {
let r = rr(0x2000_0000, 0x2000_4500); let c = clip_to_block(&r, 0x1000).unwrap();
assert_eq!(c.end, 0x2000_4000);
}
#[test]
fn clip_too_small_returns_none() {
let r = rr(0x2000_0000, 0x2000_0800); assert!(clip_to_block(&r, 0x1000).is_none());
}
}