espforge_lib/resolver/strategies/
hardware.rs

1use crate::register_strategy;
2use crate::resolver::ParameterType;
3use crate::resolver::strategies::{ParameterStrategy, ResolutionContext};
4use anyhow::{Result, anyhow};
5use espforge_macros::auto_register_param_strategy;
6use serde_yaml_ng::Value;
7
8/// references in yaml configuration
9#[derive(Default)]
10#[auto_register_param_strategy(
11    ParameterType::GpioRef,
12    ParameterType::SpiRef,
13    ParameterType::I2cRef,
14    ParameterType::UartRef
15)]
16pub struct HardwareStrategy;
17
18impl ParameterStrategy for HardwareStrategy {
19    fn resolve(&self, value: &Value, ctx: &ResolutionContext) -> Result<Value> {
20        let ref_name = self.extract_name(value)?;
21
22        let hardware = ctx.hardware.ok_or_else(|| {
23            anyhow!("Hardware configuration (esp32) is required for hardware references")
24        })?;
25
26        // Try to find it in GPIO
27        if let Some(gpio_config) = hardware.gpio.get(ref_name) {
28            let mut map = serde_yaml_ng::Mapping::new();
29            map.insert(Value::from("pin"), Value::from(gpio_config.pin));
30            map.insert(Value::from("pullup"), Value::from(gpio_config.pullup));
31            map.insert(Value::from("pulldown"), Value::from(gpio_config.pulldown));
32            return Ok(Value::Mapping(map));
33        }
34
35        // Try to find it in SPI
36        if let Some(spi_config) = hardware.spi.get(ref_name) {
37            let mut map = serde_yaml_ng::Mapping::new();
38            map.insert(Value::from("miso"), Value::from(spi_config.miso));
39            map.insert(Value::from("mosi"), Value::from(spi_config.mosi));
40            map.insert(Value::from("sck"), Value::from(spi_config.sck));
41            if let Some(cs) = spi_config.cs {
42                map.insert(Value::from("cs"), Value::from(cs));
43            } else {
44                map.insert(Value::from("cs"), Value::from(u8::MAX)); // Indicator for no CS
45            }
46            return Ok(Value::Mapping(map));
47        }
48
49        if let Some(i2c_config) = hardware.i2c.get(ref_name) {
50            return Ok(i2c_config.clone());
51        }
52
53        if let Some(uart_config) = hardware.uart.get(ref_name) {
54            return Ok(uart_config.clone());
55        }
56
57        Err(anyhow!(
58            "Undefined Hardware Reference: '${}' (checked gpio, spi)",
59            ref_name
60        ))
61    }
62}
63
64impl HardwareStrategy {
65    fn extract_name<'a>(&self, value: &'a Value) -> Result<&'a str> {
66        let val_str = value
67            .as_str()
68            .ok_or_else(|| anyhow!("Reference value must be a string"))?;
69
70        val_str
71            .strip_prefix('$')
72            .ok_or_else(|| anyhow!("Hardware reference must start with '$', got: {}", val_str))
73    }
74}