Refactor HAL modules: update async support in Water module and reorganize detect_sensors logic
- Replaced `Blocking` with `Async` for ADC operations in `Water` module. - Improved `detect_sensors` implementation with better structure for sensor messages and autodetection. - Updated tank ADC sampling to yield between readings, improving efficiency.
This commit is contained in:
@@ -396,6 +396,145 @@ impl<'a> BoardInteraction<'a> for V4<'a> {
|
|||||||
res
|
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<Voltage> {
|
||||||
|
self.charger.get_mptt_voltage()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_mptt_current(&mut self) -> FatResult<Current> {
|
||||||
|
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<PlantControllerConfig> {
|
||||||
|
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<BackupHeader> {
|
||||||
|
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::<BackupHeader>(&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<Detection> {
|
async fn detect_sensors(&mut self, request: Detection) -> FatResult<Detection> {
|
||||||
self.can_power.set_high();
|
self.can_power.set_high();
|
||||||
Timer::after_millis(500).await;
|
Timer::after_millis(500).await;
|
||||||
@@ -473,145 +612,6 @@ impl<'a> BoardInteraction<'a> for V4<'a> {
|
|||||||
|
|
||||||
res
|
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<Voltage> {
|
|
||||||
self.charger.get_mptt_voltage()
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_mptt_current(&mut self) -> FatResult<Current> {
|
|
||||||
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<PlantControllerConfig> {
|
|
||||||
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<BackupHeader> {
|
|
||||||
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::<BackupHeader>(&header_page_buffer[..]);
|
|
||||||
info!("decoding header: {:?}", info);
|
|
||||||
let (header, _) = info.context("Could not read backup header")?;
|
|
||||||
Ok(header)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn wait_for_can_measurements(
|
async fn wait_for_can_measurements(
|
||||||
|
|||||||
@@ -9,13 +9,15 @@ use esp_hal::pcnt::channel::CtrlMode::Keep;
|
|||||||
use esp_hal::pcnt::channel::EdgeMode::{Hold, Increment};
|
use esp_hal::pcnt::channel::EdgeMode::{Hold, Increment};
|
||||||
use esp_hal::pcnt::unit::Unit;
|
use esp_hal::pcnt::unit::Unit;
|
||||||
use esp_hal::peripherals::GPIO5;
|
use esp_hal::peripherals::GPIO5;
|
||||||
use esp_hal::Blocking;
|
use esp_hal::Async;
|
||||||
use esp_println::println;
|
use esp_println::println;
|
||||||
use onewire::{ds18b20, Device, DeviceSearch, OneWire, DS18B20};
|
use onewire::{ds18b20, Device, DeviceSearch, OneWire, DS18B20};
|
||||||
|
|
||||||
|
unsafe impl Send for TankSensor<'_> {}
|
||||||
|
|
||||||
pub struct TankSensor<'a> {
|
pub struct TankSensor<'a> {
|
||||||
one_wire_bus: OneWire<Flex<'a>>,
|
one_wire_bus: OneWire<Flex<'a>>,
|
||||||
tank_channel: Adc<'a, ADC1<'a>, Blocking>,
|
tank_channel: Adc<'a, ADC1<'a>, Async>,
|
||||||
tank_power: Output<'a>,
|
tank_power: Output<'a>,
|
||||||
tank_pin: AdcPin<GPIO5<'a>, ADC1<'a>, AdcCalLine<ADC1<'a>>>,
|
tank_pin: AdcPin<GPIO5<'a>, ADC1<'a>, AdcCalLine<ADC1<'a>>>,
|
||||||
flow_counter: Unit<'a, 1>,
|
flow_counter: Unit<'a, 1>,
|
||||||
@@ -35,7 +37,7 @@ impl<'a> TankSensor<'a> {
|
|||||||
let mut adc1_config = AdcConfig::new();
|
let mut adc1_config = AdcConfig::new();
|
||||||
let tank_pin =
|
let tank_pin =
|
||||||
adc1_config.enable_pin_with_cal::<_, AdcCalLine<_>>(gpio5, Attenuation::_11dB);
|
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);
|
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];
|
let mut store = [0_u16; TANK_MULTI_SAMPLE];
|
||||||
for sample in store.iter_mut() {
|
for sample in store.iter_mut() {
|
||||||
let value = self.tank_channel.read_oneshot(&mut self.tank_pin);
|
*sample = self.tank_channel.read_oneshot(&mut self.tank_pin).await;
|
||||||
//force yield
|
//force yield between successful samples
|
||||||
Timer::after_millis(10).await;
|
Timer::after_millis(10).await;
|
||||||
match value {
|
|
||||||
Ok(v) => *sample = v,
|
|
||||||
Err(e) => {
|
|
||||||
bail!("ADC Hardware error: {:?}", e);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
self.tank_power.set_low();
|
self.tank_power.set_low();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user