use std::fmt;
use std::str::FromStr;
mod data;
pub mod pack;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum Port {
A,
B,
C,
D,
E,
F,
G,
H,
}
impl Port {
pub const fn letter(self) -> char {
match self {
Port::A => 'A',
Port::B => 'B',
Port::C => 'C',
Port::D => 'D',
Port::E => 'E',
Port::F => 'F',
Port::G => 'G',
Port::H => 'H',
}
}
const fn from_letter(c: char) -> Option<Port> {
match c {
'A' | 'a' => Some(Port::A),
'B' | 'b' => Some(Port::B),
'C' | 'c' => Some(Port::C),
'D' | 'd' => Some(Port::D),
'E' | 'e' => Some(Port::E),
'F' | 'f' => Some(Port::F),
'G' | 'g' => Some(Port::G),
'H' | 'h' => Some(Port::H),
_ => None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Pin {
pub port: Port,
pub number: u8,
}
impl Pin {
pub const fn new(port: Port, number: u8) -> Pin {
Pin { port, number }
}
}
impl fmt::Display for Pin {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "P{}{}", self.port.letter(), self.number)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ParsePinError(String);
impl fmt::Display for ParsePinError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "invalid pin name: {:?} (expected e.g. \"PA7\")", self.0)
}
}
impl std::error::Error for ParsePinError {}
impl FromStr for Pin {
type Err = ParsePinError;
fn from_str(s: &str) -> Result<Pin, ParsePinError> {
let err = || ParsePinError(s.to_string());
let rest = s
.strip_prefix('P')
.or_else(|| s.strip_prefix('p'))
.ok_or_else(err)?;
let mut chars = rest.chars();
let port = chars.next().and_then(Port::from_letter).ok_or_else(err)?;
let number: u8 = chars.as_str().parse().map_err(|_| err())?;
if number > 15 {
return Err(err());
}
Ok(Pin { port, number })
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct AfMapping {
pub pin: Pin,
pub af: u8,
pub peripheral: &'static str,
pub signal: &'static str,
}
#[derive(Debug, Clone, Copy)]
pub struct Database {
entries: &'static [AfMapping],
}
impl Database {
pub const fn f446re() -> Database {
Database {
entries: data::F446RE,
}
}
pub const fn f411re() -> Database {
Database {
entries: data::F411RE,
}
}
pub fn has_peripheral(&self, peripheral: &str) -> bool {
self.entries.iter().any(|m| m.peripheral == peripheral)
}
pub fn lookup(&self, pin: Pin, af: u8) -> impl Iterator<Item = &AfMapping> {
self.entries
.iter()
.filter(move |m| m.pin == pin && m.af == af)
}
pub fn alt_functions(&self, pin: Pin) -> impl Iterator<Item = &AfMapping> {
self.entries.iter().filter(move |m| m.pin == pin)
}
pub fn pins(&self) -> Vec<Pin> {
let mut pins: Vec<Pin> = self.entries.iter().map(|m| m.pin).collect();
pins.sort_unstable();
pins.dedup();
pins
}
pub fn find_af(&self, pin: Pin, peripheral: &str, signal: &str) -> Option<u8> {
self.entries
.iter()
.find(|m| m.pin == pin && m.peripheral == peripheral && m.signal == signal)
.map(|m| m.af)
}
}
#[cfg(test)]
mod tests;