1use std::{collections::HashMap, env, fs, path::PathBuf, str::FromStr};
6
7use anyhow::Result;
8use enum_as_inner::EnumAsInner;
9use regex::Regex;
10use strum_macros::{Display, EnumIter, EnumString};
11
12#[derive(Debug, Clone, Copy, PartialEq, Display, EnumIter)]
17pub enum Chip {
18 #[strum(to_string = "xtensa_esp32")]
19 Esp32,
20 #[strum(to_string = "xtensa_esp32s2")]
21 Esp32s2,
22 #[strum(to_string = "xtensa_esp32s3")]
23 Esp32s3,
24 #[strum(to_string = "xtensa_lx106")]
25 Esp8266,
26}
27
28impl Chip {
29 fn core_isa_path(&self) -> Result<PathBuf> {
30 let path = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
31 .join("xtensa-overlays")
32 .join(self.to_string())
33 .join("newlib/newlib/libc/sys/xtensa/include/xtensa/config/core-isa.h")
34 .canonicalize()?;
35
36 Ok(path)
37 }
38}
39
40#[derive(Debug, Clone, Copy, PartialEq, EnumString)]
42pub enum InterruptType {
43 #[strum(serialize = "XTHAL_INTTYPE_EXTERN_EDGE")]
44 ExternEdge,
45 #[strum(serialize = "XTHAL_INTTYPE_EXTERN_LEVEL")]
46 ExternLevel,
47 #[strum(serialize = "XTHAL_INTTYPE_NMI")]
48 Nmi,
49 #[strum(serialize = "XTHAL_INTTYPE_PROFILING")]
50 Profiling,
51 #[strum(serialize = "XTHAL_INTTYPE_SOFTWARE")]
52 Software,
53 #[strum(serialize = "XTHAL_INTTYPE_TIMER")]
54 Timer,
55 #[strum(serialize = "XTHAL_TIMER_UNCONFIGURED")]
56 TimerUnconfigured,
57}
58
59#[derive(Debug, Clone, PartialEq, EnumAsInner)]
61pub enum Value {
62 Integer(i64),
63 Interrupt(InterruptType),
64 String(String),
65}
66
67pub fn get_config(chip: Chip) -> Result<HashMap<String, Value>> {
72 let re_define = Regex::new(r"^#define[\s]+([a-zA-Z\d_]+)[\s]+([^\s]+)")?;
73 let re_ident = Regex::new(r"^[a-zA-Z\d_]+$")?;
74 let re_string = Regex::new(r#""([^"]+)""#)?;
75
76 let mut map: HashMap<String, Value> = HashMap::new();
79 for define in find_all_defines(chip)? {
80 if !re_define.is_match(&define) {
81 println!("Define not matched: {}", define);
82 continue;
83 }
84
85 let captures = re_define.captures(&define).unwrap();
86 let identifier = captures.get(1).unwrap().as_str().to_string();
87 let value = captures.get(2).unwrap().as_str().to_string();
88
89 let value = if let Ok(integer) = value.parse::<i64>() {
90 Value::Integer(integer)
92 } else if let Ok(integer) = i64::from_str_radix(&value.replace("0x", ""), 16) {
93 Value::Integer(integer)
95 } else if let Ok(interrupt) = InterruptType::from_str(&value) {
96 Value::Interrupt(interrupt)
98 } else if re_string.is_match(&value) {
99 Value::String(value.replace("\"", ""))
101 } else if re_ident.is_match(&value) && map.contains_key(&value) {
102 map.get(&value).unwrap().to_owned()
104 } else {
105 if chip != Chip::Esp32 && identifier != "XCHAL_USE_MEMCTL" {
107 println!("Unable to process definition: {} = {}", identifier, value);
108 }
109 continue;
110 };
111
112 map.insert(identifier, value);
113 }
114
115 Ok(map)
116}
117
118fn find_all_defines(chip: Chip) -> Result<Vec<String>> {
119 let path = chip.core_isa_path()?;
120 let lines = fs::read_to_string(path)?
121 .lines()
122 .filter_map(|line| {
123 if line.starts_with("#define") {
124 Some(line.to_string())
125 } else {
126 None
127 }
128 })
129 .collect::<Vec<_>>();
130
131 Ok(lines)
132}