use std::collections::HashMap;
use crate::error::DataError;
struct Embedded {
family: &'static str,
core: &'static str,
json: &'static str,
}
const CHIPS: &[Embedded] = &[
Embedded {
family: "stm32mp25",
core: "cm33",
json: include_str!("../database/chip/stm32mp25_cm33.json"),
},
Embedded {
family: "stm32mp25",
core: "cm0p",
json: include_str!("../database/chip/stm32mp25_cm0p.json"),
},
Embedded {
family: "stm32mp23",
core: "cm33",
json: include_str!("../database/chip/stm32mp23_cm33.json"),
},
Embedded {
family: "stm32mp21",
core: "cm33",
json: include_str!("../database/chip/stm32mp21_cm33.json"),
},
Embedded {
family: "mimx95",
core: "cm7",
json: include_str!("../database/chip/mimx95_cm7.json"),
},
Embedded {
family: "mimx93",
core: "cm33",
json: include_str!("../database/chip/mimx93_cm33.json"),
},
];
#[derive(serde::Deserialize)]
struct RawChip {
irqs: Vec<RawIrq>,
peripherals: Vec<RawPeripheral>,
}
#[derive(serde::Deserialize)]
struct RawIrq {
name: String,
value: u16,
}
#[derive(serde::Deserialize)]
struct RawPeripheral {
name: String,
base_address: String,
block: String,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PeripheralEntry {
pub base: u32,
pub block: String,
}
impl PeripheralEntry {
pub fn kind(&self) -> &str {
self.block.split('/').next().unwrap_or(&self.block)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct IrqEntry {
pub number: u16,
pub name: String,
}
#[derive(Debug, Clone)]
pub struct ChipMap {
peripherals: HashMap<String, PeripheralEntry>,
irqs: HashMap<String, IrqEntry>,
}
impl ChipMap {
pub fn peripheral(&self, name: &str) -> Option<&PeripheralEntry> {
self.peripherals.get(&name.to_ascii_lowercase())
}
pub fn contains_peripheral(&self, name: &str) -> bool {
self.peripherals.contains_key(&name.to_ascii_lowercase())
}
pub fn irq(&self, name: &str) -> Option<&IrqEntry> {
self.irqs.get(&name.to_ascii_lowercase())
}
}
pub fn load(chip: &str, core: &str) -> Result<ChipMap, DataError> {
let needle = normalize(chip);
let core_key = core.to_ascii_lowercase();
let entry = CHIPS
.iter()
.find(|entry| needle.starts_with(entry.family) && entry.core == core_key)
.ok_or_else(|| DataError::ChipMapUnavailable {
chip: chip.to_string(),
core: core.to_string(),
})?;
let raw: RawChip = serde_json::from_str(entry.json).map_err(|err| DataError::ChipMapParse {
chip: chip.to_string(),
core: core.to_string(),
detail: err.to_string(),
})?;
let mut peripherals = HashMap::with_capacity(raw.peripherals.len());
for p in raw.peripherals {
let base = parse_hex(&p.base_address).ok_or_else(|| DataError::ChipMapParse {
chip: chip.to_string(),
core: core.to_string(),
detail: format!(
"peripheral '{}' has invalid base '{}'",
p.name, p.base_address
),
})?;
peripherals.insert(
p.name.to_ascii_lowercase(),
PeripheralEntry {
base,
block: p.block,
},
);
}
let irqs = raw
.irqs
.into_iter()
.map(|irq| {
(
irq.name.to_ascii_lowercase(),
IrqEntry {
number: irq.value,
name: irq.name,
},
)
})
.collect();
Ok(ChipMap { peripherals, irqs })
}
fn parse_hex(value: &str) -> Option<u32> {
let trimmed = value.trim();
let digits = trimmed
.strip_prefix("0x")
.or_else(|| trimmed.strip_prefix("0X"))
.unwrap_or(trimmed);
u32::from_str_radix(digits, 16).ok()
}
fn normalize(chip: &str) -> String {
let lowered = chip.to_ascii_lowercase();
match lowered.strip_prefix("imx") {
Some(rest) => format!("mimx{rest}"),
None => lowered,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn resolves_imx95_cm7_lpi2c_and_irq() {
let map = load("imx95", "cm7").expect("imx95 cm7 map should resolve");
let lpi2c1 = map.peripheral("LPI2C1").expect("LPI2C1 should exist");
assert_ne!(lpi2c1.base, 0);
assert_eq!(lpi2c1.kind(), "lpi2c");
assert!(map.irq("LPI2C1").is_some());
}
#[test]
fn resolves_stm32mp25_cm33_gpio() {
let map = load("stm32mp257fak3", "cm33").expect("stm32mp25 cm33 map should resolve");
let gpioa = map.peripheral("GPIOA").expect("GPIOA should exist");
assert_eq!(gpioa.kind(), "gpio");
assert!(map.contains_peripheral("i2c1"));
}
#[test]
fn rejects_unknown_core() {
assert!(matches!(
load("stm32mp257fak3", "cm4"),
Err(DataError::ChipMapUnavailable { .. })
));
}
}