use super::ir::{TiBoard, TiChip, TiClocksConfig, TiIr};
use anyhow::{Context, Result, anyhow};
use indexmap::IndexMap;
use std::path::Path;
pub fn yaml_to_chip(text: &str) -> Result<TiChip> {
serde_yaml::from_str(text).context("parse ti chip yaml")
}
pub fn yaml_to_board(text: &str) -> Result<TiBoard> {
serde_yaml::from_str(text).context("parse ti board yaml")
}
pub fn load_chip_db(name: &str) -> Result<TiChip> {
let text = rlvgl_chips_ti::chip_yaml(name)
.ok_or_else(|| anyhow!("ti chipdb has no chip named '{name}'"))?;
yaml_to_chip(text).with_context(|| format!("parsing chipdb chip '{name}'"))
}
pub fn load_board_db(name: &str) -> Result<TiBoard> {
let text = rlvgl_chips_ti::board_yaml(name)
.ok_or_else(|| anyhow!("ti chipdb has no board named '{name}'"))?;
yaml_to_board(text).with_context(|| format!("parsing chipdb board '{name}'"))
}
pub fn load_chip_file(path: &Path) -> Result<TiChip> {
let text = std::fs::read_to_string(path)
.with_context(|| format!("read chip yaml {}", path.display()))?;
yaml_to_chip(&text).with_context(|| format!("parse chip yaml {}", path.display()))
}
pub fn load_board_file(path: &Path) -> Result<TiBoard> {
let text = std::fs::read_to_string(path)
.with_context(|| format!("read board yaml {}", path.display()))?;
yaml_to_board(&text).with_context(|| format!("parse board yaml {}", path.display()))
}
pub fn merge(chip: TiChip, board: TiBoard) -> Result<TiIr> {
if board.chip != chip.name {
return Err(anyhow!(
"board '{}' targets chip '{}' but loaded chip spec is '{}'",
board.name,
board.chip,
chip.name
));
}
validate_pins_against_chip(&chip, &board)?;
let clocks = default_clocks(&chip);
let pins = board.pins.clone();
Ok(TiIr {
version: "0.1".to_string(),
chip,
board,
clocks,
pins,
metadata: IndexMap::new(),
})
}
fn default_clocks(chip: &TiChip) -> TiClocksConfig {
TiClocksConfig {
cpu_hz: chip.clock_tree.cpu_hz,
apb_hz: chip.clock_tree.apb_hz,
xtal_hz: chip.clock_tree.xtal_hi_hz,
xtal_hi_hz: chip.clock_tree.xtal_hi_hz,
xtal_lo_hz: chip.clock_tree.xtal_lo_hz,
kernels: IndexMap::new(),
}
}
fn validate_pins_against_chip(chip: &TiChip, board: &TiBoard) -> Result<()> {
for pin in &board.pins {
let dio_present = chip.io_mux.iter().any(|p| p.dio == pin.dio);
if !dio_present {
return Err(anyhow!(
"board '{}' assigns DIO{} but chip '{}' io_mux table does not list that DIO",
board.name,
pin.dio,
chip.name
));
}
}
let mut seen: IndexMap<&str, u8> = IndexMap::new();
for pin in &board.pins {
if let Some(label) = pin.label.as_deref()
&& let Some(prev) = seen.insert(label, pin.dio)
{
return Err(anyhow!(
"board '{}' reuses label '{}' on DIO{} and DIO{}",
board.name,
label,
prev,
pin.dio
));
}
}
Ok(())
}