espforge_lib/resolver/strategies/
hardware.rs

1//use std::u8;
2
3use crate::register_strategy;
4use crate::resolver::ParameterType;
5use crate::resolver::strategies::{ParameterStrategy, ResolutionContext};
6use anyhow::{Result, anyhow};
7use espforge_macros::auto_register_param_strategy;
8use serde_yaml_ng::Value;
9
10/// Strategy for Hardware References (GPIO, SPI, etc.)
11#[derive(Default)]
12#[auto_register_param_strategy(
13    ParameterType::GpioRef,
14    ParameterType::SpiRef,
15    ParameterType::I2cRef,
16    ParameterType::UartRef
17)]
18pub struct HardwareStrategy;
19
20impl ParameterStrategy for HardwareStrategy {
21    fn resolve(&self, value: &Value, ctx: &ResolutionContext) -> Result<Value> {
22        let ref_name = self.extract_name(value)?;
23
24        let hardware = ctx.hardware.ok_or_else(|| {
25            anyhow!("Hardware configuration (esp32) is required for hardware references")
26        })?;
27
28        // Try to find it in GPIO
29        if let Some(gpio_config) = hardware.gpio.get(ref_name) {
30            let mut map = serde_yaml_ng::Mapping::new();
31            map.insert(Value::from("pin"), Value::from(gpio_config.pin));
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}