pub mod codegen;
pub mod config;
pub mod model;
pub mod solver;
use nucleus_db::Database;
pub use codegen::{generate, Generated};
pub use config::{Config, ParseError};
pub use solver::Conflict;
#[derive(Debug, Clone)]
pub struct CheckReport {
pub config: Config,
pub conflicts: Vec<Conflict>,
}
impl CheckReport {
pub fn is_ok(&self) -> bool {
self.conflicts.is_empty()
}
}
pub fn database_for(family: &str) -> Result<Database, UnknownFamily> {
match family {
"STM32F446RE" | "" => Ok(Database::f446re()),
"STM32F411RE" => Ok(Database::f411re()),
other => Err(UnknownFamily(other.to_string())),
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct UnknownFamily(pub String);
impl std::fmt::Display for UnknownFamily {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"unsupported device family {:?}: Nucleus supports STM32F446RE and STM32F411RE",
self.0
)
}
}
impl std::error::Error for UnknownFamily {}
pub fn check(text: &str) -> Result<CheckReport, ParseError> {
let config = config::parse(text)?;
let db = database_for(&config.device.family).unwrap_or_else(|_| Database::f446re());
let conflicts = solver::solve(&config, &db);
Ok(CheckReport { config, conflicts })
}
pub fn check_family(text: &str) -> Result<(CheckReport, Option<UnknownFamily>), ParseError> {
let config = config::parse(text)?;
let family_warning = database_for(&config.device.family).err();
let db = database_for(&config.device.family).unwrap_or_else(|_| Database::f446re());
let conflicts = solver::solve(&config, &db);
Ok((CheckReport { config, conflicts }, family_warning))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn check_reports_ok_for_clean_config() {
let report = check(
r#"
[device]
family = "STM32F446RE"
[peripherals.usart2]
tx = "PA2"
rx = "PA3"
"#,
)
.unwrap();
assert!(report.is_ok());
}
#[test]
fn check_surfaces_conflicts() {
let report = check(
r#"
[peripherals.spi1]
mosi = "PA7"
miso = "PA6"
sck = "PA5"
[peripherals.tim2]
channel1 = "PA5"
"#,
)
.unwrap();
assert!(!report.is_ok());
}
#[test]
fn unknown_family_is_flagged() {
let (_report, warning) = check_family(
r#"
[device]
family = "STM32H750"
"#,
)
.unwrap();
assert_eq!(warning, Some(UnknownFamily("STM32H750".to_string())));
}
#[test]
fn malformed_toml_is_a_parse_error() {
assert!(check("this is not toml = = =").is_err());
}
#[test]
fn database_for_resolves_known_families() {
assert!(database_for("STM32F446RE").is_ok());
assert!(database_for("STM32F411RE").is_ok());
assert!(database_for("").is_ok()); assert!(database_for("STM32H750").is_err());
}
#[test]
fn check_family_resolves_db_for_f411re() {
let (report, warning) = check_family(
"[device]\nfamily = \"STM32F411RE\"\n\n[peripherals.uart4]\ntx = \"PA0\"\nrx = \"PA1\"\n",
)
.unwrap();
assert_eq!(warning, None);
assert!(
report.conflicts.iter().any(|c| matches!(
c,
Conflict::PeripheralUnavailable { peripheral, family }
if peripheral == "UART4" && family == "STM32F411RE"
)),
"got {:?}",
report.conflicts
);
}
}