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 }