use std::collections::HashMap;
use probe_rs_target::{MemoryRange, MemoryRegion, NvmRegion};
use crate::Session;
use crate::flashing::progress::ProgressOperation;
use crate::flashing::{FlashError, FlashLoader, flasher::Flasher};
use crate::flashing::{FlashLayout, FlashSector};
use super::FlashProgress;
struct FlasherWithRegions {
flasher: Flasher,
regions: Vec<NvmRegion>,
}
pub fn erase_all(
session: &mut Session,
progress: &mut FlashProgress<'_>,
read_flasher_rtt: bool,
) -> Result<(), FlashError> {
tracing::debug!("Erasing all...");
let mut algos = Vec::<FlasherWithRegions>::new();
tracing::debug!("Regions:");
for region in session
.target()
.memory_map
.iter()
.filter_map(MemoryRegion::as_nvm_region)
{
if region.is_alias {
tracing::debug!("Skipping alias memory region {:#010x?}", region.range);
continue;
}
tracing::debug!(
" region: {:#010x?} ({} bytes)",
region.range,
region.range.end - region.range.start
);
let region = region.clone();
let Some(core_name) = region.cores.first() else {
return Err(FlashError::NoNvmCoreAccess(region));
};
let target = session.target();
let core = target.core_index_by_name(core_name).unwrap();
let algo = FlashLoader::get_flash_algorithm_for_region(®ion, target, core_name, &[])?;
tracing::debug!(" -- using algorithm: {}", algo.name);
if let Some(entry) = algos.iter_mut().find(|entry| {
entry.flasher.flash_algorithm.name == algo.name && entry.flasher.core_index == core
}) {
entry.regions.push(region);
} else {
algos.push(FlasherWithRegions {
flasher: {
let mut flasher = Flasher::new(session.target(), core, algo)?;
flasher.read_rtt_output(read_flasher_rtt);
flasher
},
regions: vec![region],
});
}
}
let algos = algos;
let mut do_chip_erase = true;
let mut phases = vec![];
for el in algos.iter() {
let flash_algorithm = &el.flasher.flash_algorithm;
if do_chip_erase && !el.flasher.is_chip_erase_supported(session) {
do_chip_erase = false;
}
let mut layout = FlashLayout::default();
for region in el.regions.iter() {
for info in flash_algorithm.iter_sectors() {
let range = info.address_range();
if region.range.contains_range(&range) {
layout.sectors.push(FlashSector {
address: info.base_address,
size: info.size,
});
}
}
}
phases.push(layout);
}
if do_chip_erase {
progress.add_progress_bar(ProgressOperation::Erase, None);
} else {
for phase in phases.iter() {
let sector_size = phase.sectors().iter().map(|s| s.size()).sum::<u64>();
progress.add_progress_bar(ProgressOperation::Erase, Some(sector_size));
}
}
progress.initialized(phases);
for el in algos {
let mut flasher = el.flasher;
tracing::debug!("Erasing with algorithm: {}", flasher.flash_algorithm.name);
if flasher.is_chip_erase_supported(session) {
tracing::debug!(" -- chip erase supported, doing it.");
flasher.run_erase_all(session, progress)?;
} else {
tracing::debug!(" -- chip erase not supported, erasing by sector.");
let sectors = flasher
.flash_algorithm()
.iter_sectors()
.filter(|info| {
let range = info.base_address..info.base_address + info.size;
el.regions.iter().any(|r| r.range.contains_range(&range))
})
.collect::<Vec<_>>();
flasher.run_erase(session, progress, |active, _| {
for info in sectors {
tracing::debug!(
" sector: {:#010x}-{:#010x} ({} bytes)",
info.base_address,
info.base_address + info.size,
info.size
);
let sector = FlashSector {
address: info.base_address,
size: info.size,
};
active.erase_sector(§or)?;
}
Ok(())
})?;
}
}
Ok(())
}
pub fn erase(
session: &mut Session,
progress: &mut FlashProgress<'_>,
address_start: u64,
address_end: u64,
read_flasher_rtt: bool,
) -> Result<(), FlashError> {
tracing::debug!("Erasing {address_start:08x}..{address_end:08x}");
let address_range = address_start..address_end;
let mut algos: HashMap<(String, String), Vec<NvmRegion>> = HashMap::new();
tracing::debug!("Regions:");
for region in session
.target()
.memory_map
.iter()
.filter_map(MemoryRegion::as_nvm_region)
{
tracing::debug!(
" region: {:#010x?} ({} bytes)",
region.range,
region.range.end - region.range.start
);
if !region.range.intersects_range(&address_range) {
tracing::debug!(" -- doesn't overlap, ignoring!");
continue;
}
let core_name = region
.cores
.first()
.ok_or_else(|| FlashError::NoNvmCoreAccess(region.clone()))?;
let algo =
FlashLoader::get_flash_algorithm_for_region(region, session.target(), core_name, &[])?;
let entry = algos
.entry((algo.name.clone(), core_name.clone()))
.or_default();
entry.push(region.clone());
tracing::debug!(" -- using algorithm: {}", algo.name);
}
for ((algo_name, core_name), regions) in algos {
tracing::debug!("Erasing with algorithm: {}", algo_name);
let algo = session.target().flash_algorithm_by_name(&algo_name);
let algo = algo.unwrap();
let core_index = session.target().core_index_by_name(&core_name).unwrap();
let mut flasher = Flasher::new(session.target(), core_index, algo)?;
flasher.read_rtt_output(read_flasher_rtt);
let sectors = flasher
.flash_algorithm()
.iter_sectors()
.filter(|info| address_range.contains_range(&info.address_range()))
.filter(|info| {
let range = info.base_address..info.base_address + info.size;
regions.iter().any(|r| r.range.contains_range(&range))
})
.collect::<Vec<_>>();
flasher.run_erase(session, progress, |active, _| {
for info in sectors {
tracing::debug!(
" sector: {:#010x}-{:#010x} ({} bytes)",
info.base_address,
info.base_address + info.size,
info.size
);
let sector = FlashSector {
address: info.base_address,
size: info.size,
};
active.erase_sector(§or)?;
}
Ok(())
})?;
}
Ok(())
}
pub fn run_blank_check(
session: &mut Session,
progress: &mut FlashProgress<'_>,
address_start: u64,
address_end: u64,
read_flasher_rtt: bool,
) -> Result<(), FlashError> {
tracing::debug!("Blank-checking {address_start:08x}..{address_end:08x}");
let address_range = address_start..address_end;
let mut algos: HashMap<(String, String), Vec<NvmRegion>> = HashMap::new();
tracing::debug!("Regions:");
for region in session
.target()
.memory_map
.iter()
.filter_map(MemoryRegion::as_nvm_region)
{
tracing::debug!(
" region: {:#010x?} ({} bytes)",
region.range,
region.range.end - region.range.start
);
if !region.range.intersects_range(&address_range) {
tracing::debug!(" -- doesn't overlap, ignoring!");
continue;
}
let core_name = region
.cores
.first()
.ok_or_else(|| FlashError::NoNvmCoreAccess(region.clone()))?;
let algo =
FlashLoader::get_flash_algorithm_for_region(region, session.target(), core_name, &[])?;
let entry = algos
.entry((algo.name.clone(), core_name.clone()))
.or_default();
entry.push(region.clone());
tracing::debug!(" -- using algorithm: {}", algo.name);
}
for ((algo_name, core_name), regions) in algos {
tracing::debug!("Blank-checking with algorithm: {}", algo_name);
let algo = session.target().flash_algorithm_by_name(&algo_name);
let algo = algo.unwrap();
let core_index = session.target().core_index_by_name(&core_name).unwrap();
let mut flasher = Flasher::new(session.target(), core_index, algo)?;
flasher.read_rtt_output(read_flasher_rtt);
let sectors = flasher
.flash_algorithm()
.iter_sectors()
.filter(|info| address_range.contains_range(&info.address_range()))
.filter(|info| {
let range = info.base_address..info.base_address + info.size;
regions.iter().any(|r| r.range.contains_range(&range))
})
.collect::<Vec<_>>();
flasher.run_blank_check(session, progress, |active, _| {
for info in sectors {
tracing::debug!(
" sector: {:#010x}-{:#010x} ({} bytes)",
info.base_address,
info.base_address + info.size,
info.size
);
let sector = FlashSector {
address: info.base_address,
size: info.size,
};
active.blank_check(§or)?;
}
Ok(())
})?;
}
Ok(())
}