use alloc::{vec, vec::Vec};
use embedded_sdmmc::Block;
pub fn create_mbr_with_fat(size: usize) -> anyhow::Result<Vec<u8>> {
let mut buffer = vec![0u8; Block::LEN * 2];
let bytes_per_sector = 512;
let min_clusters = 4_085;
let max_clusters = 65_525;
let cluster_ratio = max_clusters * bytes_per_sector;
let sectors = size / bytes_per_sector;
let bytes = sectors * bytes_per_sector;
let sectors_per_cluster = bytes.div_ceil(cluster_ratio).max(1);
let clusters = sectors / sectors_per_cluster;
anyhow::ensure!(min_clusters < clusters, "partition too small: {clusters}");
anyhow::ensure!(clusters < max_clusters, "partition too large: {clusters}");
let buf = &mut buffer;
let sectors = u32::try_from(sectors)?;
buf[0x01b8..0x01b8 + 4].copy_from_slice(&[0xfa, 0xfb, 0xfc, 0xfd]);
buf[0x01be + 0x04..0x01be + 0x04 + 1].copy_from_slice(&[0x0e]);
buf[0x01be + 0x08..0x01be + 0x08 + 4].copy_from_slice(&[0x01, 0x00, 0x00, 0x00]);
buf[0x01be + 0x0c..0x01be + 0x0c + 4].copy_from_slice(§ors.to_le_bytes());
buf[0x01fe..0x01fe + 2].copy_from_slice(&[0x55, 0xaa]);
let buf = &mut buffer[Block::LEN..];
let is_large = sectors > u16::MAX as u32;
let sectors_small = is_large.then_some(0).unwrap_or(sectors as u16);
let sectors_large = is_large.then_some(sectors).unwrap_or(0);
let sectors_per_cluster = u8::try_from(sectors_per_cluster)?;
let bytes_per_sector = u16::try_from(bytes_per_sector)?;
buf[0x00..0x00 + 3].copy_from_slice(&[0xeb, 0x3c, 0x90]);
buf[0x03..0x03 + 8].copy_from_slice(b"buf-fs16");
buf[0x0b..0x0b + 2].copy_from_slice(&bytes_per_sector.to_le_bytes());
buf[0x0d..0x0d + 1].copy_from_slice(&[sectors_per_cluster]);
buf[0x0e..0x0e + 2].copy_from_slice(&[0x01, 0x00]);
buf[0x10..0x10 + 1].copy_from_slice(&[0x02]);
buf[0x11..0x11 + 2].copy_from_slice(&[0x00, 0x02]);
buf[0x13..0x13 + 2].copy_from_slice(§ors_small.to_le_bytes());
buf[0x15..0x15 + 1].copy_from_slice(&[0xf8]);
buf[0x16..0x16 + 2].copy_from_slice(&[0x20, 0x00]);
buf[0x18..0x18 + 2].copy_from_slice(&[0x20, 0x00]);
buf[0x1a..0x1a + 2].copy_from_slice(&[0x20, 0x00]);
buf[0x1c..0x1c + 4].copy_from_slice(&[0x01, 0x00, 0x00, 0x00]);
buf[0x20..0x20 + 4].copy_from_slice(§ors_large.to_le_bytes());
buf[0x24..0x24 + 001].copy_from_slice(&[0x80]);
buf[0x25..0x25 + 001].copy_from_slice(&[0x00]);
buf[0x26..0x26 + 001].copy_from_slice(&[0x29]);
buf[0x27..0x27 + 004].copy_from_slice(&[0x8b, 0x4f, 0x18, 0x56]);
buf[0x2b..0x2b + 011].copy_from_slice(b"BUF-FS F16 ");
buf[0x36..0x36 + 008].copy_from_slice(b"FAT16 ");
buf[0x3e..0x3e + 129].copy_from_slice(&[
0x0e, 0x1f, 0xbe, 0x5b, 0x7c, 0xac, 0x22, 0xc0, 0x74, 0x0b, 0x56, 0xb4, 0x0e, 0xbb, 0x07,
0x00, 0xcd, 0x10, 0x5e, 0xeb, 0xf0, 0x32, 0xe4, 0xcd, 0x16, 0xcd, 0x19, 0xeb, 0xfe, 0x54,
0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x61, 0x20, 0x62, 0x6f,
0x6f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x64, 0x69, 0x73, 0x6b, 0x2e, 0x20, 0x20, 0x50,
0x6c, 0x65, 0x61, 0x73, 0x65, 0x20, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x20, 0x61, 0x20,
0x62, 0x6f, 0x6f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x66, 0x6c, 0x6f, 0x70, 0x70, 0x79,
0x20, 0x61, 0x6e, 0x64, 0x0d, 0x0a, 0x70, 0x72, 0x65, 0x73, 0x73, 0x20, 0x61, 0x6e, 0x79,
0x20, 0x6b, 0x65, 0x79, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x72, 0x79, 0x20, 0x61, 0x67, 0x61,
0x69, 0x6e, 0x20, 0x2e, 0x2e, 0x2e, 0x20, 0x0d, 0x0a,
]);
buf[0x1fe..0x1fe + 002].copy_from_slice(&[0x55, 0xaa]);
Ok(buffer)
}
#[cfg(test)]
mod tests {
use embedded_sdmmc::{VolumeIdx, VolumeManager};
use proptest::prelude::*;
use crate::{Clock, Device};
use super::*;
proptest! {
#[test]
fn mbr_load_works(size in Device::MIN_SIZE..=Device::MAX_SIZE) {
let buffer = create_mbr_with_fat(size).unwrap();
let device = Device::from_raw_bytes_unchecked(buffer);
let clock = Clock::default();
let mut mgr = VolumeManager::new(device, clock);
let mut vol = mgr.open_volume(VolumeIdx(0)).unwrap();
let _root = vol.open_root_dir().unwrap();
}
}
}