use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct Capacity(pub u32);
impl Capacity {
pub const fn bytes(bytes: u32) -> Self {
Self(bytes)
}
pub const fn megabytes(mb: u32) -> Self {
Self(mb * 1024 * 1024)
}
pub const fn gigabits(gb: u32) -> Self {
Self(gb * 128 * 1024 * 1024) }
pub fn as_bytes(&self) -> u32 {
self.0
}
pub fn as_megabytes(&self) -> u32 {
self.0 / (1024 * 1024)
}
}
impl fmt::Display for Capacity {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mb = self.as_megabytes();
if mb >= 1024 {
write!(f, "{} GB", mb / 1024)
} else if mb > 0 {
write!(f, "{} MB", mb)
} else {
write!(f, "{} KB", self.0 / 1024)
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Address(pub u32);
impl Address {
pub fn new(addr: u32) -> Self {
Self(addr)
}
pub fn as_u32(&self) -> u32 {
self.0
}
pub fn page(&self, page_size: u32) -> u32 {
self.0 / page_size
}
pub fn block(&self, block_size: u32) -> u32 {
self.0 / block_size
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FlashType {
Nand,
Nor,
SpiEeprom,
I2cEeprom,
MicrowireEeprom,
SpiFram,
}
#[derive(Debug, Clone)]
pub struct FlashOptions {
pub address: u32,
pub length: Option<u32>,
pub use_ecc: bool,
pub ignore_ecc_errors: bool,
pub bad_block_strategy: super::bad_block::BadBlockStrategy,
pub oob_mode: super::OobMode,
pub speed: Option<u8>,
pub verify: bool,
pub retry_count: u32,
pub bbt_file: Option<std::path::PathBuf>,
pub driver: Option<String>,
}
impl Default for FlashOptions {
fn default() -> Self {
Self {
address: 0,
length: None,
use_ecc: true,
ignore_ecc_errors: false,
bad_block_strategy: super::bad_block::BadBlockStrategy::Fail,
oob_mode: super::OobMode::None,
speed: None,
verify: false,
retry_count: 0,
bbt_file: None,
driver: None,
}
}
}
impl fmt::Display for FlashType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
FlashType::Nand => write!(f, "SPI NAND"),
FlashType::Nor => write!(f, "SPI NOR"),
FlashType::SpiEeprom => write!(f, "SPI EEPROM"),
FlashType::I2cEeprom => write!(f, "I2C EEPROM"),
FlashType::MicrowireEeprom => write!(f, "Microwire EEPROM"),
FlashType::SpiFram => write!(f, "SPI FRAM"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct JedecId {
pub manufacturer: u8,
pub device: u8,
pub density: u8,
}
impl JedecId {
pub fn new(data: [u8; 3]) -> Self {
Self {
manufacturer: data[0],
device: data[1],
density: data[2],
}
}
pub fn as_bytes(&self) -> [u8; 3] {
[self.manufacturer, self.device, self.density]
}
}
impl fmt::Display for JedecId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{:02X} {:02X} {:02X}",
self.manufacturer, self.device, self.density
)
}
}
#[derive(Debug, Clone)]
pub struct Progress {
pub current: u64,
pub total: u64,
pub message: Option<String>,
}
impl Progress {
pub fn new(current: u64, total: u64) -> Self {
Self {
current,
total,
message: None,
}
}
pub fn percentage(&self) -> f64 {
if self.total == 0 {
0.0
} else {
(self.current as f64 / self.total as f64) * 100.0
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_capacity_creation_and_conversion() {
let cap_bytes = Capacity::bytes(1024);
assert_eq!(cap_bytes.as_bytes(), 1024);
let cap_mb = Capacity::megabytes(1);
assert_eq!(cap_mb.as_bytes(), 1024 * 1024);
assert_eq!(cap_mb.as_megabytes(), 1);
let cap_gb_bits = Capacity::gigabits(1);
assert_eq!(cap_gb_bits.as_megabytes(), 128);
assert_eq!(cap_gb_bits.as_bytes(), 128 * 1024 * 1024);
}
#[test]
fn test_capacity_display() {
assert_eq!(format!("{}", Capacity::bytes(512)), "0 KB"); assert_eq!(format!("{}", Capacity::bytes(1024)), "1 KB");
assert_eq!(format!("{}", Capacity::megabytes(10)), "10 MB");
assert_eq!(format!("{}", Capacity::megabytes(2048)), "2 GB");
}
#[test]
fn test_address_calculations() {
let addr = Address::new(0x20800);
let page_size = 2048;
let block_size = 128 * 1024;
assert_eq!(addr.page(page_size), 65);
assert_eq!(addr.block(block_size), 1);
}
#[test]
fn test_jedec_id() {
let id_bytes = [0xEF, 0x40, 0x18];
let jedec = JedecId::new(id_bytes);
assert_eq!(jedec.manufacturer, 0xEF);
assert_eq!(jedec.device, 0x40);
assert_eq!(jedec.density, 0x18);
assert_eq!(jedec.as_bytes(), id_bytes);
assert_eq!(format!("{}", jedec), "EF 40 18");
}
#[test]
fn test_progress_percentage() {
let p_start = Progress::new(0, 100);
assert_eq!(p_start.percentage(), 0.0);
let p_mid = Progress::new(50, 100);
assert_eq!(p_mid.percentage(), 50.0);
let p_done = Progress::new(100, 100);
assert_eq!(p_done.percentage(), 100.0);
let p_zero = Progress::new(0, 0);
assert_eq!(p_zero.percentage(), 0.0);
}
#[test]
fn test_flash_options_default() {
let opts = FlashOptions::default();
assert_eq!(opts.address, 0);
assert!(opts.use_ecc);
assert!(!opts.verify);
}
}