Skip to content

Commit

Permalink
Add embedded clock config parser in rust
Browse files Browse the repository at this point in the history
  • Loading branch information
lmbollen committed Dec 21, 2023
1 parent 88e6fa3 commit dae550d
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 1 deletion.
19 changes: 18 additions & 1 deletion firmware-binaries/examples/hello/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@

use ufmt::uwriteln;

use bittide_sys::clock_config;
use bittide_sys::i2c::I2CError;
use bittide_sys::si534x::SI534X;
use bittide_sys::uart::Uart;

#[cfg(not(test))]
use riscv_rt::entry;

Expand Down Expand Up @@ -48,6 +48,23 @@ fn main() -> ! {
}

uwriteln!(uart, "Going in echo mode!").unwrap();

// Parse config.csv using bittide::clock_config
let config = include_str!("config.csv");
let mut parser = clock_config::ClockConfigParser::new();
for line in config.lines() {
if !parser.is_done() {
match parser.parse_line(line) {
Ok(Some((addr, data))) => {
uwriteln!(uart, "{:04x} {:04x}", addr, data).unwrap();
}
Ok(None) => uwriteln!(uart, "{}", line).unwrap(),
Err(e) => {
uwriteln!(uart, "Error: {}", e).unwrap();
}
}
}
}
loop {
let c = uart.receive();
uart.send(c);
Expand Down
81 changes: 81 additions & 0 deletions firmware-support/bittide-sys/src/clock_config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
#[derive(Debug, Copy, Clone, PartialEq)]
enum FilePart {
PreambleHeader,
Preamble,
PostPreambleDelay,
Config,
PostambleHeader,
Postamble,
Done,
}

/// Create a class that implements the statemachine for parsing the clock configuration file.
pub struct ClockConfigParser {
part: FilePart,
}
impl ClockConfigParser {
/// Create a new parser.
pub fn new() -> Self {
Self {
part: FilePart::PreambleHeader,
}
}

/// Parse a line of the clock configuration file.
pub fn parse_line(&mut self, line: &str) -> Result<Option<(u16, u16)>, &'static str> {
let (next_state, result) = parse_line(self.part, line);
self.part = next_state;
result
}

/// Check if the parser is done.
pub fn is_done(&self) -> bool {
self.part == FilePart::Done
}
}
fn parse_line(part: FilePart, line: &str) -> (FilePart, Result<Option<(u16, u16)>, &'static str>) {
let next_state = match (part, line) {
(FilePart::PreambleHeader, _) if line.contains("Start configuration preamble") => {
FilePart::Preamble
}
(FilePart::Preamble, _) if line.contains("End configuration preamble") => {
FilePart::PostPreambleDelay
}
(FilePart::PostPreambleDelay, _) if line.contains("Start configuration registers") => {
FilePart::Config
}
(FilePart::Config, _) if line.contains("End configuration registers") => FilePart::PostambleHeader,
(FilePart::PostambleHeader, _) if line.contains("Start configuration postamble") => {
FilePart::Postamble
}
(FilePart::Postamble, _) if line.contains("End configuration postamble") => {
FilePart::Postamble
}
_ => part.clone(),
};
let result = match part {
FilePart::Preamble | FilePart::Config | FilePart::Postamble => {
parse_address_data(line).map(Some)
}
FilePart::Done => Err("State machine is already done."),
_ => Ok(None),
};
(next_state, result)
}

fn parse_address_data(line: &str) -> Result<(u16, u16), &'static str> {
let mut parts = line.split(',');
let address = parts.next().ok_or("Missing address")?;
let data = parts.next().ok_or("Missing data")?;
let address = parse_hex(address)?;
let data = parse_hex(data)?;
Ok((address, data))
}

fn parse_hex(hex_string: &str) -> Result<u16, &'static str> {
if hex_string.starts_with("0x") {
u16::from_str_radix(&hex_string[2..], 16).map_err(|_| "Invalid hex number")
} else {
Err("Hex number must start with '0x'")
}
}
1 change: 1 addition & 0 deletions firmware-support/bittide-sys/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use fdt::Fdt;
use utils::matches_fdt_name;

pub mod callisto;
pub mod clock_config;
pub mod clock_control;
pub mod gather_unit;
pub mod i2c;
Expand Down

0 comments on commit dae550d

Please sign in to comment.