use std::collections::HashMap;
use std::env;
use std::fs::{self, File, OpenOptions};
use std::io::{BufRead, BufReader, Write};
use std::path::Path;
use std::process::Command;
use crate::{FifoConfig, Profile};
pub fn gen_regs_yaml(files: &Vec<String>, replacements: &HashMap<&str, String>) {
let out_dir = env::var("OUT_DIR").unwrap();
let output_path = Path::new(&out_dir).join("usb_regs.yaml");
let mut output_file = File::create(&output_path).unwrap();
for file_path in files {
let content = fs::read_to_string(file_path).unwrap();
let mut modified_content = content.clone();
for (key, value) in replacements {
modified_content = modified_content.replace(*key, value);
}
write!(output_file, "{modified_content}\n").unwrap();
}
}
pub fn gen_usb_pac() {
let out_dir = env::var("OUT_DIR").expect("OUT_DIR environment variable not set");
let input_path = Path::new(&out_dir).join("usb_regs.yaml");
let output_path = Path::new(&out_dir).join("usb_regs.tmp");
let yaml2pac_status = Command::new("yaml2pac")
.arg("-i")
.arg(input_path.to_str().unwrap())
.arg("-o")
.arg(output_path.to_str().unwrap())
.status()
.unwrap();
if !yaml2pac_status.success() {
panic!(
"yaml2pac command failed: {}",
yaml2pac_status.code().unwrap()
);
}
let rustfmt_status = Command::new("rustfmt")
.arg(output_path.to_str().unwrap())
.status()
.expect("Failed to execute rustfmt");
if !rustfmt_status.success() {
panic!(
"rustfmt command failed: {}",
yaml2pac_status.code().unwrap()
);
}
let file = File::open(output_path).unwrap();
let reader = BufReader::new(file);
let mut output_file = OpenOptions::new()
.write(true)
.create(true)
.truncate(true)
.open(Path::new(&out_dir).join("regs.rs"))
.unwrap();
let lines = reader.lines().skip(4);
for line in lines {
output_file.write_all(line.unwrap().as_bytes()).unwrap();
output_file.write_all(b"\n").unwrap();
}
}
pub fn gen_info(profile: &Profile) {
let out_dir = env::var("OUT_DIR").unwrap();
let output_path = Path::new(&out_dir).join("_generated.rs");
let mut file = File::create(output_path).unwrap();
writeln!(file, "// This file is generated by build_src/gen.rs").unwrap();
writeln!(file, "use crate::info::EpDirection;").unwrap();
writeln!(file, "use crate::info::EpInfo;").unwrap();
if let Some(base_address) = profile.base_address {
let insert_content = format!(
r#"pub struct UsbInstance;
impl crate::MusbInstance for UsbInstance {{
fn regs() -> crate::regs::Usb {{
unsafe {{ crate::regs::Usb::from_ptr(({base_address:#x}) as _ ) }}
}}
}}
"#
);
file.write_all(insert_content.as_bytes()).unwrap();
}
writeln!(file, "pub const ENDPOINTS: [EpInfo; {}] = [", profile.endpoints.len()).unwrap();
for ep in &profile.endpoints {
writeln!(file, " EpInfo {{").unwrap();
writeln!(file, " ep_direction: EpDirection::{:?},", ep.ep_direction).unwrap();
writeln!(file, " max_packet_size: {},", ep.max_packet_size).unwrap();
writeln!(file, " }},").unwrap();
}
writeln!(file, "];").unwrap();
match &profile.fifo {
FifoConfig::Fixed(_) => {}
FifoConfig::Dynamic(config) => {
writeln!(
file,
"pub const TOTAL_FIFO_SIZE: u16 = {};",
config.total_size
)
.unwrap();
}
}
}