diff --git a/Software/MainBoard/rust/src/hal/v4_hal.rs b/Software/MainBoard/rust/src/hal/v4_hal.rs index 5a9bc3e..327e521 100644 --- a/Software/MainBoard/rust/src/hal/v4_hal.rs +++ b/Software/MainBoard/rust/src/hal/v4_hal.rs @@ -396,6 +396,145 @@ impl<'a> BoardInteraction<'a> for V4<'a> { res } + async fn general_fault(&mut self, enable: bool) { + hold_disable(23); + self.general_fault.set_level(enable.into()); + hold_enable(23); + } + + async fn test(&mut self) -> Result<(), FatError> { + self.general_fault(true).await; + Timer::after_millis(100).await; + self.general_fault(false).await; + Timer::after_millis(500).await; + self.extra1.set_high(); + Timer::after_millis(500).await; + self.extra1.set_low(); + Timer::after_millis(500).await; + self.extra2.set_high(); + Timer::after_millis(500).await; + self.extra2.set_low(); + Timer::after_millis(500).await; + self.light(true).await?; + Timer::after_millis(500).await; + self.light(false).await?; + Timer::after_millis(500).await; + for i in 0..PLANT_COUNT { + self.fault(i, true).await?; + Timer::after_millis(500).await; + self.fault(i, false).await?; + Timer::after_millis(500).await; + } + for i in 0..PLANT_COUNT { + self.pump(i, true).await?; + Timer::after_millis(100).await; + self.pump(i, false).await?; + Timer::after_millis(100).await; + } + let moisture = self.measure_moisture_hz().await?; + for plant in 0..PLANT_COUNT { + let a = moisture.sensor_a_hz[plant].unwrap_or(0.0) as u32; + let b = moisture.sensor_b_hz[plant].unwrap_or(0.0) as u32; + log(LogMessage::TestSensor, a, b, &(plant + 1).to_string(), ""); + } + Timer::after_millis(10).await; + Ok(()) + } + + fn set_config(&mut self, config: PlantControllerConfig) { + self.config = config; + } + + async fn get_mptt_voltage(&mut self) -> FatResult { + self.charger.get_mptt_voltage() + } + + async fn get_mptt_current(&mut self) -> FatResult { + self.charger.get_mppt_current() + } + + async fn can_power(&mut self, state: bool) -> FatResult<()> { + if state && self.can_power.is_set_low() { + self.can_power.set_high(); + } else { + self.can_power.set_low(); + } + Ok(()) + } + + async fn backup_config(&mut self, controller_config: &PlantControllerConfig) -> FatResult<()> { + let mut buffer: [u8; 4096 - BACKUP_HEADER_MAX_SIZE] = [0; 4096 - BACKUP_HEADER_MAX_SIZE]; + let length = postcard::to_slice(controller_config, &mut buffer)?.len(); + info!("Writing backup config of size {}", length); + let mut checksum = X25.digest(); + checksum.update(&buffer[..length]); + let mut header_page_buffer = [0_u8; BACKUP_HEADER_MAX_SIZE]; + + let time = self.rtc_module.get_rtc_time().await?.timestamp_millis(); + let header = BackupHeader { + crc16: checksum.finalize(), + timestamp: time, + size: length as u16, + }; + info!("Header is {:?}", header); + postcard::to_slice(&header, &mut header_page_buffer)?; + info!("Header is serialized"); + self.get_rtc_module().write(0, &header_page_buffer)?; + info!("Header written"); + let mut to_write = length; + let mut chunk: usize = 0; + + while to_write > 0 { + self.progress(chunk as u32).await; + let start = chunk * EEPROM_PAGE; + let end = start + min(EEPROM_PAGE, to_write); + let part = &buffer[start..end]; + info!( + "Writing chunk {} of size {} to offset {}", + chunk, + part.len(), + start + ); + to_write -= part.len(); + self.get_rtc_module() + .write((BACKUP_HEADER_MAX_SIZE + chunk * EEPROM_PAGE) as u32, part)?; + chunk += 1; + } + info!("Backup complete"); + self.clear_progress().await; + Ok(()) + } + async fn read_backup(&mut self) -> FatResult { + let info = self.backup_info().await?; + let mut store = alloc::vec![0_u8; info.size as usize]; + self.rtc_module + .read(BACKUP_HEADER_MAX_SIZE as u32, store.as_mut_slice())?; + info!("Read backup data of size {}", store.len()); + let mut checksum = X25.digest(); + info!("Calculating CRC"); + checksum.update(&store[..]); + let crc = checksum.finalize(); + info!("CRC is {:04x}", crc); + if crc != info.crc16 { + warn!("CRC mismatch in backup data"); + bail!("CRC mismatch in backup data") + } + info!("CRC is correct"); + let decoded = postcard::from_bytes(&store[..])?; + info!("Backup data decoded"); + Ok(decoded) + } + + async fn backup_info(&mut self) -> FatResult { + let mut header_page_buffer = [0_u8; BACKUP_HEADER_MAX_SIZE]; + self.get_rtc_module().read(0, &mut header_page_buffer)?; + info!("Read header page"); + let info = postcard::take_from_bytes::(&header_page_buffer[..]); + info!("decoding header: {:?}", info); + let (header, _) = info.context("Could not read backup header")?; + Ok(header) + } + async fn detect_sensors(&mut self, request: Detection) -> FatResult { self.can_power.set_high(); Timer::after_millis(500).await; @@ -473,145 +612,6 @@ impl<'a> BoardInteraction<'a> for V4<'a> { res } - - async fn general_fault(&mut self, enable: bool) { - hold_disable(23); - self.general_fault.set_level(enable.into()); - hold_enable(23); - } - - async fn test(&mut self) -> Result<(), FatError> { - self.general_fault(true).await; - Timer::after_millis(100).await; - self.general_fault(false).await; - Timer::after_millis(500).await; - self.extra1.set_high(); - Timer::after_millis(500).await; - self.extra1.set_low(); - Timer::after_millis(500).await; - self.extra2.set_high(); - Timer::after_millis(500).await; - self.extra2.set_low(); - Timer::after_millis(500).await; - self.light(true).await?; - Timer::after_millis(500).await; - self.light(false).await?; - Timer::after_millis(500).await; - for i in 0..PLANT_COUNT { - self.fault(i, true).await?; - Timer::after_millis(500).await; - self.fault(i, false).await?; - Timer::after_millis(500).await; - } - for i in 0..PLANT_COUNT { - self.pump(i, true).await?; - Timer::after_millis(100).await; - self.pump(i, false).await?; - Timer::after_millis(100).await; - } - let moisture = self.measure_moisture_hz().await?; - for plant in 0..PLANT_COUNT { - let a = moisture.sensor_a_hz[plant].unwrap_or(0.0) as u32; - let b = moisture.sensor_b_hz[plant].unwrap_or(0.0) as u32; - log(LogMessage::TestSensor, a, b, &(plant + 1).to_string(), ""); - } - Timer::after_millis(10).await; - Ok(()) - } - - fn set_config(&mut self, config: PlantControllerConfig) { - self.config = config; - } - - async fn get_mptt_voltage(&mut self) -> FatResult { - self.charger.get_mptt_voltage() - } - - async fn get_mptt_current(&mut self) -> FatResult { - self.charger.get_mppt_current() - } - - async fn can_power(&mut self, state: bool) -> FatResult<()> { - if state && self.can_power.is_set_low() { - self.can_power.set_high(); - } else { - self.can_power.set_low(); - } - Ok(()) - } - async fn backup_config(&mut self, controller_config: &PlantControllerConfig) -> FatResult<()> { - let mut buffer: [u8; 4096 - BACKUP_HEADER_MAX_SIZE] = [0; 4096 - BACKUP_HEADER_MAX_SIZE]; - let length = postcard::to_slice(controller_config, &mut buffer)?.len(); - info!("Writing backup config of size {}", length); - let mut checksum = X25.digest(); - checksum.update(&buffer[..length]); - let mut header_page_buffer = [0_u8; BACKUP_HEADER_MAX_SIZE]; - - let time = self.rtc_module.get_rtc_time().await?.timestamp_millis(); - let header = BackupHeader { - crc16: checksum.finalize(), - timestamp: time, - size: length as u16, - }; - info!("Header is {:?}", header); - postcard::to_slice(&header, &mut header_page_buffer)?; - info!("Header is serialized"); - self.get_rtc_module().write(0, &header_page_buffer)?; - info!("Header written"); - let mut to_write = length; - let mut chunk: usize = 0; - - while to_write > 0 { - self.progress(chunk as u32).await; - let start = chunk * EEPROM_PAGE; - let end = start + min(EEPROM_PAGE, to_write); - let part = &buffer[start..end]; - info!( - "Writing chunk {} of size {} to offset {}", - chunk, - part.len(), - start - ); - to_write -= part.len(); - self.get_rtc_module() - .write((BACKUP_HEADER_MAX_SIZE + chunk * EEPROM_PAGE) as u32, part)?; - chunk += 1; - } - info!("Backup complete"); - self.clear_progress().await; - Ok(()) - } - - async fn read_backup(&mut self) -> FatResult { - let info = self.backup_info().await?; - let mut store = alloc::vec![0_u8; info.size as usize]; - self.rtc_module - .read(BACKUP_HEADER_MAX_SIZE as u32, store.as_mut_slice())?; - info!("Read backup data of size {}", store.len()); - let mut checksum = X25.digest(); - info!("Calculating CRC"); - checksum.update(&store[..]); - let crc = checksum.finalize(); - info!("CRC is {:04x}", crc); - if crc != info.crc16 { - warn!("CRC mismatch in backup data"); - bail!("CRC mismatch in backup data") - } - info!("CRC is correct"); - let decoded = postcard::from_bytes(&store[..])?; - info!("Backup data decoded"); - Ok(decoded) - } - - async fn backup_info(&mut self) -> FatResult { - let mut header_page_buffer = [0_u8; BACKUP_HEADER_MAX_SIZE]; - self.get_rtc_module().read(0, &mut header_page_buffer)?; - info!("Read header page"); - let info = postcard::take_from_bytes::(&header_page_buffer[..]); - info!("decoding header: {:?}", info); - let (header, _) = info.context("Could not read backup header")?; - Ok(header) - } } async fn wait_for_can_measurements( diff --git a/Software/MainBoard/rust/src/hal/water.rs b/Software/MainBoard/rust/src/hal/water.rs index d63e9bd..0c58f55 100644 --- a/Software/MainBoard/rust/src/hal/water.rs +++ b/Software/MainBoard/rust/src/hal/water.rs @@ -9,13 +9,15 @@ use esp_hal::pcnt::channel::CtrlMode::Keep; use esp_hal::pcnt::channel::EdgeMode::{Hold, Increment}; use esp_hal::pcnt::unit::Unit; use esp_hal::peripherals::GPIO5; -use esp_hal::Blocking; +use esp_hal::Async; use esp_println::println; use onewire::{ds18b20, Device, DeviceSearch, OneWire, DS18B20}; +unsafe impl Send for TankSensor<'_> {} + pub struct TankSensor<'a> { one_wire_bus: OneWire>, - tank_channel: Adc<'a, ADC1<'a>, Blocking>, + tank_channel: Adc<'a, ADC1<'a>, Async>, tank_power: Output<'a>, tank_pin: AdcPin, ADC1<'a>, AdcCalLine>>, flow_counter: Unit<'a, 1>, @@ -35,7 +37,7 @@ impl<'a> TankSensor<'a> { let mut adc1_config = AdcConfig::new(); let tank_pin = adc1_config.enable_pin_with_cal::<_, AdcCalLine<_>>(gpio5, Attenuation::_11dB); - let tank_channel = Adc::new(adc1, adc1_config); + let tank_channel = Adc::new(adc1, adc1_config).into_async(); let one_wire_bus = OneWire::new(one_wire_pin, false); @@ -139,15 +141,9 @@ impl<'a> TankSensor<'a> { let mut store = [0_u16; TANK_MULTI_SAMPLE]; for sample in store.iter_mut() { - let value = self.tank_channel.read_oneshot(&mut self.tank_pin); - //force yield + *sample = self.tank_channel.read_oneshot(&mut self.tank_pin).await; + //force yield between successful samples Timer::after_millis(10).await; - match value { - Ok(v) => *sample = v, - Err(e) => { - bail!("ADC Hardware error: {:?}", e); - } - }; } self.tank_power.set_low();