use crate::application::use_cases::detect_chip::DetectChipUseCase;
use crate::domain::{bad_block::BlockStatus, FlashOperation, FlashType};
use crate::error::{Error, Result};
use crate::infrastructure::chip_database::ChipRegistry;
use crate::infrastructure::flash_protocol::nand::SpiNand;
use colored::*;
use std::path::PathBuf;
pub struct BbtHandler {
detect_use_case: DetectChipUseCase,
}
impl Default for BbtHandler {
fn default() -> Self {
Self::new()
}
}
impl BbtHandler {
pub fn new() -> Self {
Self {
detect_use_case: DetectChipUseCase::new(ChipRegistry::new()),
}
}
pub fn handle_scan(
&self,
speed: Option<u8>,
output: Option<PathBuf>,
driver: Option<&str>,
) -> Result<()> {
println!("Detecting flash chip...");
let (programmer, spec) = self.detect_use_case.execute(speed, driver)?;
if spec.flash_type != FlashType::Nand {
return Err(Error::NotSupported(
"BBT scan is only available for NAND flash".to_string(),
));
}
println!(
"Detected: {} ({})",
spec.name.green().bold(),
spec.manufacturer.green()
);
println!("Scanning for bad blocks... (This may take a while)");
let mut protocol = SpiNand::new(programmer, spec.clone());
let total_blocks = (spec.capacity.as_bytes() / spec.layout.block_size) as u64;
let pb = super::create_progress_bar(total_blocks, "Scanning Blocks");
let bbt = protocol.scan_bbt(&|progress| {
pb.set_position(progress.current);
})?;
pb.finish_with_message("Scan Complete");
println!("\n{}", "Scan Results:".cyan().bold());
let bad_count = bbt.bad_block_count();
if bad_count == 0 {
println!("No bad blocks found! {}", "Excellent!".green());
} else {
println!("Found {} bad blocks:", bad_count.to_string().red().bold());
println!("--------------------------------");
println!("{:<10} {:<15}", "Block", "Status");
println!("--------------------------------");
let total_blocks_usize = total_blocks as usize;
for block in 0..total_blocks_usize {
let status = bbt.get_status(block);
if status == BlockStatus::BadFactory {
println!("{:<10} {}", block, "Factory Bad".red());
} else if status == BlockStatus::BadRuntime {
println!("{:<10} {}", block, "Runtime Bad".red());
}
}
}
if let Some(path) = output {
println!("\nSaving BBT to: {:?}", path);
let file = std::fs::File::create(&path).map_err(Error::Io)?;
serde_json::to_writer_pretty(file, &bbt)
.map_err(|e| Error::Other(format!("Failed to save BBT file: {}", e)))?;
println!("{}", "BBT saved successfully!".green().bold());
}
Ok(())
}
pub fn handle_load(&self, input: PathBuf) -> Result<()> {
println!("Loading BBT from: {:?}", input);
let bbt = super::load_bbt(&input)?;
let bad_count = bbt.bad_block_count();
println!("Loaded table with {} bad blocks.", bad_count);
if bad_count > 0 {
println!("--------------------------------");
println!("{:<10} {:<15}", "Block", "Status");
println!("--------------------------------");
for block in 0..bbt.len() {
let status = bbt.get_status(block);
if status == BlockStatus::BadFactory {
println!("{:<10} {}", block, "Factory Bad".red());
} else if status == BlockStatus::BadRuntime {
println!("{:<10} {}", block, "Runtime Bad".red());
}
}
}
Ok(())
}
}