use core::{ptr};
use crate::{SoftwareError};
pub const SLOTINFO_MAGIC: u32 = 0xEFEEDBBA;
pub const USERLAND_HEADER_MAGIC: u32 = 0xDEC0EDFE;
pub const KERNEL_HEADER_MAGIC: u32 = 0xDEC00DF0;
pub const FILESYSTEM_MAGIC: u32 = 0xBADD0BEEu32.swap_bytes();
pub const EXTERNAL_APPS_MAGIC: u32 = 0xDEC0EDFE;
pub const RAM_BASE_N0110_OR_N0115: u32 = 0x20000000;
pub const RAM_BASE_N0120: u32 = 0x24000000;
pub const SLOTS_N0110_OR_N0115: [*const u32; 2] = [0x90010000 as *const u32, 0x90410000 as *const u32];
pub const SLOTS_N0120: [*const u32; 2] = [0x90020000 as *const u32, 0x90420000 as *const u32];
pub const STORAGE_FILE_MAX_NAME_LEN: usize = u16::MAX as usize;
#[repr(C)]
#[derive(Debug)]
pub struct SlotInfo {
pub header: u32, pub kernel_header_address: &'static KernelHeader, pub userland_header_address: &'static UserlandHeader, pub footer: u32, }
impl SlotInfo {
pub fn is_valid(&self) -> Result<(), SoftwareError> {
if self.header != SLOTINFO_MAGIC {
return Err(SoftwareError::InvalidMagicNumber { expected: SLOTINFO_MAGIC, found: self.header });
}
if self.footer != SLOTINFO_MAGIC {
return Err(SoftwareError::InvalidMagicNumber { expected: SLOTINFO_MAGIC, found: self.footer });
}
Ok(())
}
}
#[repr(C)]
#[derive(Debug)]
pub struct UserlandHeader {
pub header: u32, pub expected_epsilon_version: [u8; 8], pub storage_address_ram: *const u8, pub storage_size_ram: u32, pub external_apps_flash_start: *const u8, pub external_apps_flash_end: *const u8, pub external_apps_ram_start: *const u8, pub external_apps_ram_end: *const u8, pub device_name_flash_start: *const u8, pub device_name_flash_end: *const u8, pub footer: u32, }
impl UserlandHeader {
pub fn is_valid(&self) -> Result<(), SoftwareError> {
if self.header != USERLAND_HEADER_MAGIC {
return Err(SoftwareError::InvalidMagicNumber { expected: USERLAND_HEADER_MAGIC, found: self.header });
}
if self.footer != USERLAND_HEADER_MAGIC {
return Err(SoftwareError::InvalidMagicNumber { expected: USERLAND_HEADER_MAGIC, found: self.footer });
}
Ok(())
}
}
#[repr(C)]
#[derive(Debug)]
pub struct KernelHeader {
pub header: u32, pub epsilon_version: [u8; 8], pub patch_level: [u8; 8], pub footer: u32, }
impl KernelHeader {
pub fn is_valid(&self) -> Result<(), SoftwareError> {
if self.header != KERNEL_HEADER_MAGIC {
return Err(SoftwareError::InvalidMagicNumber { expected: KERNEL_HEADER_MAGIC, found: self.header });
}
if self.footer != KERNEL_HEADER_MAGIC {
return Err(SoftwareError::InvalidMagicNumber { expected: KERNEL_HEADER_MAGIC, found: self.footer });
}
Ok(())
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CalculatorModel {
N0110_N0115,
N0120,
}
impl CalculatorModel {
pub fn ram_base(&self) -> *const u8 {
match self {
Self::N0110_N0115 => RAM_BASE_N0110_OR_N0115 as *const u8,
Self::N0120 => RAM_BASE_N0120 as *const u8,
}
}
pub fn slotinfo_address(&self) -> &'static SlotInfo {
let ram = self.ram_base() as *const u32;
let slot_info = ram as *const SlotInfo;
let slot_info_ref = unsafe { &*slot_info };
return slot_info_ref;
}
pub fn detect() -> Self {
unsafe {
let count_n0110_n0115 = SLOTS_N0110_OR_N0115.iter().filter(|&&slot| ptr::read_unaligned(slot) == EXTERNAL_APPS_MAGIC).count();
let count_n0120 = SLOTS_N0120.iter().filter(|&&slot| ptr::read_unaligned(slot) == EXTERNAL_APPS_MAGIC).count();
if count_n0110_n0115 > count_n0120 {
Self::N0110_N0115
} else {
Self::N0120
}
}
}
}
#[derive(Debug)]
pub struct Filesystem {
pub storage_size: u32,
pub storage_start_addr: *const u8,
pub storage_end_addr: *const u8,
pub header_addr: *const u32,
pub footer_addr: *const u32,
pub usable_size: u32,
pub usable_start_addr: *const u8,
pub usable_end_addr: *const u8,
}
impl Filesystem {
pub fn new() -> Self {
let user_land = CalculatorModel::detect().slotinfo_address().userland_header_address;
Self {
storage_size: user_land.storage_size_ram,
storage_start_addr: user_land.storage_address_ram,
storage_end_addr: unsafe { user_land.storage_address_ram.add(4 + user_land.storage_size_ram as usize + 4) }, header_addr: user_land.storage_address_ram as *const u32, footer_addr: unsafe { user_land.storage_address_ram.add(4 + user_land.storage_size_ram as usize) as *const u32 },
usable_size: user_land.storage_size_ram - 2, usable_start_addr: unsafe { user_land.storage_address_ram.add(4)}, usable_end_addr: unsafe { user_land.storage_address_ram.add(4 + user_land.storage_size_ram as usize - 2) }, }
}
pub fn is_valid(&self) -> Result<(), SoftwareError> {
unsafe {
let header = ptr::read_unaligned(self.header_addr);
if header != FILESYSTEM_MAGIC {
return Err(SoftwareError::InvalidMagicNumber { expected: FILESYSTEM_MAGIC, found: header });
}
let footer = ptr::read_unaligned(self.footer_addr);
if footer != FILESYSTEM_MAGIC {
return Err(SoftwareError::InvalidMagicNumber { expected: FILESYSTEM_MAGIC, found: footer });
}
}
Ok(())
}
}
#[cfg(target_os = "none")]
pub fn model() -> CalculatorModel {
CalculatorModel::detect()
}
#[cfg(target_os = "none")]
pub fn address() -> *const u8 {
CalculatorModel::detect().ram_base()
}
#[cfg(target_os = "none")]
pub fn kernel_header() -> &'static KernelHeader {
CalculatorModel::detect().slotinfo_address().kernel_header_address
}
#[cfg(target_os = "none")]
pub fn userland_header() -> &'static UserlandHeader {
CalculatorModel::detect().slotinfo_address().userland_header_address
}
#[cfg(target_os = "none")]
pub fn storage() -> Filesystem {
Filesystem::new()
}