use std::fs::OpenOptions;
use std::io::Write;
use std::path::Path;
use svg::{
Document, Node,
node::element::{Group, Rectangle, Text},
};
use crate::rpc::functions::flash::FlashLayout;
pub struct FlashVisualizer<'layout> {
flash_layout: &'layout FlashLayout,
}
impl<'layout> FlashVisualizer<'layout> {
pub(super) fn new(flash_layout: &'layout FlashLayout) -> Self {
Self { flash_layout }
}
fn memory_to_local(&self, address: u64) -> f32 {
let top_sector_address = self
.flash_layout
.sectors
.last()
.map_or(0, |s| s.address + s.size);
address as f32 / top_sector_address as f32 * 100.0
}
fn memory_block(&self, address: u64, size: u64, dimensions: (u32, u32)) -> Group {
let height = self.memory_to_local(size);
let start = 100.0 - self.memory_to_local(address) - height;
let mut group = Group::new();
group.append(
Rectangle::new()
.set("x", dimensions.0)
.set("y", start)
.set("width", dimensions.1)
.set("height", height),
);
group.append(
Text::new(format!("{address:#08X?}"))
.set("x", dimensions.0 + 1)
.set("y", start + height - 2.0)
.set("font-size", 5)
.set("font-family", "Arial")
.set("fill", "Black"),
);
group.append(
Text::new(format!("{:#08X?}", address + size))
.set("x", dimensions.0 + 1)
.set("y", start + 5.0)
.set("font-size", 5)
.set("font-family", "Arial")
.set("fill", "Black"),
);
group
}
pub fn generate_svg(&self) -> String {
let mut document = Document::new();
let mut group = Group::new().set("transform", "scale(1, 1)");
for sector in self.flash_layout.sectors.iter() {
let rectangle = self
.memory_block(sector.address, sector.size, (50, 50))
.set("fill", "CornflowerBlue");
group.append(rectangle);
}
for page in self.flash_layout.pages.iter() {
let rectangle = self
.memory_block(page.address, page.data_len, (100, 50))
.set("fill", "Crimson");
group.append(rectangle);
}
for block in self.flash_layout.data_blocks.iter() {
let rectangle = self
.memory_block(block.address, block.size, (150, 50))
.set("fill", "MediumSeaGreen");
group.append(rectangle);
}
for fill in self.flash_layout.fills.iter() {
let rectangle = self
.memory_block(fill.address, fill.size, (150, 50))
.set("fill", "SandyBrown");
group.append(rectangle);
}
document.append(group);
document.assign("viewBox", (0, -20, 300, 140));
format!("{document}")
}
pub fn write_svg(&self, path: impl AsRef<Path>) -> std::io::Result<()> {
let svg = self.generate_svg();
let mut file = OpenOptions::new()
.read(true)
.write(true)
.create(true)
.truncate(true)
.open(path.as_ref())?;
file.write_all(svg.as_bytes())
}
}
impl FlashLayout {
pub fn visualize(&self) -> FlashVisualizer {
FlashVisualizer::new(self)
}
}