/ firmware / src / config / board.rs
board.rs
  1  //! Hardware configuration — changes per PCB revision.
  2  //!
  3  //! GPIO pins, I2C bus layout, sensor topology, RS485 buses,
  4  //! SD card SPI pins, button GPIOs, LED GPIO.
  5  
  6  pub const PLATFORM: &str = "esp32s3";
  7  
  8  pub mod led {
  9      pub const GPIO: u8 = 38;
 10      pub const COUNT: u8 = 1;
 11  }
 12  
 13  pub mod i2c {
 14      pub struct BusConfig {
 15          pub sda_gpio: u8,
 16          pub scl_gpio: u8,
 17      }
 18      pub const FREQUENCY_KHZ: u32 = 100;
 19      pub const LEGACY_POWER_GPIO: u8 = 5;
 20      pub const BUS_0: BusConfig = BusConfig {
 21          sda_gpio: 8,
 22          scl_gpio: 9,
 23      };
 24      pub const BUS_1: BusConfig = BusConfig {
 25          sda_gpio: 17,
 26          scl_gpio: 18,
 27      };
 28      pub const MUX_ADDR: u8 = 0x70;
 29      pub const DIRECT_CHANNEL: i8 = -1;
 30      pub const ANY_MUX_CHANNEL: i8 = -2;
 31  }
 32  
 33  #[derive(Clone, Copy, PartialEq, Eq)]
 34  pub enum I2CSensorKind {
 35      TemperatureHumidityCHT832X,
 36      TemperatureHumiditySHT3X,
 37      VoltageADS1115,
 38      CurrentINA228,
 39      CarbonDioxideSCD30,
 40      CarbonDioxideSCD4X,
 41      RtcDS3231,
 42      EepromAT24C32,
 43  }
 44  
 45  #[derive(Clone, Copy)]
 46  pub struct I2CSensorConfig {
 47      pub name: &'static str,
 48      pub model: &'static str,
 49      pub kind: I2CSensorKind,
 50      pub bus_index: u8,
 51      pub address: u8,
 52      pub mux_channel: i8,
 53  }
 54  
 55  pub mod i2c_topology {
 56      use super::{I2CSensorConfig, I2CSensorKind};
 57  
 58      pub const DEVICES: &[I2CSensorConfig] = &[
 59          I2CSensorConfig {
 60              name: "ds3231_0",
 61              model: "DS3231",
 62              kind: I2CSensorKind::RtcDS3231,
 63              bus_index: 0,
 64              address: 0x68,
 65              mux_channel: super::i2c::DIRECT_CHANNEL,
 66          },
 67          I2CSensorConfig {
 68              name: "eeprom_0",
 69              model: "AT24C32",
 70              kind: I2CSensorKind::EepromAT24C32,
 71              bus_index: 1,
 72              address: 0x50,
 73              mux_channel: super::i2c::DIRECT_CHANNEL,
 74          },
 75          I2CSensorConfig {
 76              name: "voltage_0",
 77              model: "ADS1115",
 78              kind: I2CSensorKind::VoltageADS1115,
 79              bus_index: 1,
 80              address: 0x48,
 81              mux_channel: super::i2c::ANY_MUX_CHANNEL,
 82          },
 83          I2CSensorConfig {
 84              name: "scd30_0",
 85              model: "SCD30",
 86              kind: I2CSensorKind::CarbonDioxideSCD30,
 87              bus_index: 1,
 88              address: 0x61,
 89              mux_channel: super::i2c::DIRECT_CHANNEL,
 90          },
 91          I2CSensorConfig {
 92              name: "scd4x_0",
 93              model: "SCD4x",
 94              kind: I2CSensorKind::CarbonDioxideSCD4X,
 95              bus_index: 1,
 96              address: 0x62,
 97              mux_channel: super::i2c::DIRECT_CHANNEL,
 98          },
 99          I2CSensorConfig {
100              name: "temperature_and_humidity_mux",
101              model: "CHT832X",
102              kind: I2CSensorKind::TemperatureHumidityCHT832X,
103              bus_index: 1,
104              address: 0x44,
105              mux_channel: super::i2c::ANY_MUX_CHANNEL,
106          },
107          I2CSensorConfig {
108              name: "temperature_and_humidity_0",
109              model: "SHT31",
110              kind: I2CSensorKind::TemperatureHumiditySHT3X,
111              bus_index: 0,
112              address: 0x44,
113              mux_channel: super::i2c::DIRECT_CHANNEL,
114          },
115          I2CSensorConfig {
116              name: "temperature_and_humidity_1",
117              model: "SHT31",
118              kind: I2CSensorKind::TemperatureHumiditySHT3X,
119              bus_index: 1,
120              address: 0x44,
121              mux_channel: super::i2c::DIRECT_CHANNEL,
122          },
123      ];
124  
125      pub fn find_by_address(address: u8) -> Option<&'static I2CSensorConfig> {
126          DEVICES.iter().find(|d| d.address == address)
127      }
128  
129      pub fn devices_of_kind(kind: I2CSensorKind) -> impl Iterator<Item = &'static I2CSensorConfig> {
130          DEVICES.iter().filter(move |d| d.kind == kind)
131      }
132  
133      pub fn first_device_of_kind(kind: I2CSensorKind) -> Option<&'static I2CSensorConfig> {
134          devices_of_kind(kind).next()
135      }
136  }
137  
138  pub mod rs485 {
139      pub struct BusConfig {
140          pub tx_gpio: i8,
141          pub rx_gpio: i8,
142          pub de_re_gpio: i8,
143          pub baud_rate: u32,
144      }
145      pub const CHANNEL_COUNT: u8 = 2;
146      pub const BUS_0: BusConfig = BusConfig {
147          tx_gpio: 45,
148          rx_gpio: 48,
149          de_re_gpio: 47,
150          baud_rate: 9600,
151      };
152      pub const BUS_1: BusConfig = BusConfig {
153          tx_gpio: 40,
154          rx_gpio: 39,
155          de_re_gpio: 41,
156          baud_rate: 4800,
157      };
158  }
159  
160  #[derive(Clone, Copy, PartialEq, Eq)]
161  pub enum ModbusSensorKind {
162      WindSpeed,
163      WindDirection,
164      SolarRadiation,
165      SoilProbe,
166  }
167  
168  #[derive(Clone, Copy)]
169  pub struct ModbusSensorConfig {
170      pub name: &'static str,
171      pub model: &'static str,
172      pub kind: ModbusSensorKind,
173      pub channel: u8,
174      pub slave_id: u8,
175      pub register_address: u16,
176  }
177  
178  pub mod modbus_topology {
179      use super::{ModbusSensorConfig, ModbusSensorKind};
180  
181      pub const DEVICES: &[ModbusSensorConfig] = &[
182          ModbusSensorConfig {
183              name: "wind_speed_0",
184              model: "DFRobot SEN0483",
185              kind: ModbusSensorKind::WindSpeed,
186              channel: 0,
187              slave_id: 20,
188              register_address: 0,
189          },
190          ModbusSensorConfig {
191              name: "wind_direction_0",
192              model: "DFRobot SEN0482",
193              kind: ModbusSensorKind::WindDirection,
194              channel: 0,
195              slave_id: 30,
196              register_address: 0,
197          },
198      ];
199  
200      pub fn find_by_kind(kind: ModbusSensorKind) -> Option<&'static ModbusSensorConfig> {
201          DEVICES.iter().find(|d| d.kind == kind)
202      }
203  }
204  
205  pub mod sd_card {
206      pub const CS_GPIO: u32 = 10;
207      pub const MOSI_GPIO: u32 = 11;
208      pub const SCK_GPIO: u32 = 12;
209      pub const MISO_GPIO: u32 = 13;
210      pub const SPI_INIT_FREQUENCY_KHZ: u32 = 400;
211  }
212  
213  pub mod eeprom {
214      pub const I2C_ADDR: u8 = 0x50;
215      pub const PAGE_SIZE: u16 = 32;
216      pub const TOTAL_SIZE: u16 = 4096;
217  }
218  
219  pub mod temperature_humidity {
220      pub const I2C_ADDR: u8 = 0x44;
221      pub const SHT3X_RESET_GPIO_PIN: u8 = 4;
222  }
223  
224  pub mod voltage {
225      pub const I2C_ADDR: u8 = 0x48;
226  }
227  
228  pub mod buttons {
229      pub const GPIO_1: i8 = -1;
230      pub const GPIO_2: i8 = 4;
231      pub const GPIO_3: i8 = 42;
232      pub const COUNT: u8 = 3;
233  }