Nareshkumar Rao 7 months ago
parent
commit
0b8395137e
  1. 17
      src/actuators.rs
  2. 8
      src/config.rs
  3. 98
      src/dht11.rs
  4. 3
      src/error.rs
  5. 75
      src/io.rs
  6. 16
      src/main.rs
  7. 15
      src/sensors.rs

17
src/actuators.rs

@ -0,0 +1,17 @@
use crate::{
config::*,
io::{Relay, RelaySwitchState},
GenericResult,
};
pub fn switch_lights(relay: &mut Relay, state: RelaySwitchState) -> GenericResult<()> {
relay.switch(LIGHT_RELAY_PIN, state)
}
pub fn switch_fan(relay: &mut Relay, state: RelaySwitchState) -> GenericResult<()> {
relay.switch(FAN_RELAY_PIN, state)
}
pub fn switch_water_pump(relay: &mut Relay, state: RelaySwitchState) -> GenericResult<()> {
relay.switch(WATER_PUMP_RELAY_PIN, state)
}

8
src/config.rs

@ -0,0 +1,8 @@
pub const LOGIC_LEVEL: f32 = 3.3;
pub const THERMISTOR_ANALOG_PIN: u8 = 0;
pub const THERMISTOR_VOLTAGE_DIVIDER_RESISTANCE: f32 = 9_700.;
pub const LIGHT_RELAY_PIN: u8 = 0;
pub const FAN_RELAY_PIN: u8 = 1;
pub const WATER_PUMP_RELAY_PIN: u8 = 2;
pub const RELAY_GPIO_PINS: [Option<u8>; 4] = [Some(17), Some(27), Some(22), None];

98
src/dht11.rs

@ -1,98 +0,0 @@
use std::{error::Error, time::Duration};
use rppal::gpio::Gpio;
pub struct Dht11Data {
pub temperature: f32,
pub humidity: f32,
}
pub struct Dht11Sensor {
pin: rppal::gpio::IoPin,
}
impl Dht11Sensor {
pub fn new(pin: u8) -> Result<Dht11Sensor, Box<dyn Error>> {
let pin = Gpio::new()?.get(pin)?.into_io(rppal::gpio::Mode::Input);
Ok(Dht11Sensor { pin })
}
fn expect_pulse(&mut self, expected_level: bool) -> Result<u32, Box<dyn Error>> {
let _guard = interrupts::disable();
let mut count: u32 = 0;
let mut rtclock = linux_realtime::Clock::new()?;
loop {
if self.pin.is_high() != expected_level {
break;
}
if count >= 1000 {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
"Timeout while reading pulse",
)
.into());
}
count += 1;
rtclock.sleep(Duration::from_micros(1))?;
}
Ok(count)
}
pub fn read(&mut self) -> Result<Dht11Data, Box<dyn Error>> {
use rppal::gpio::{Bias, Mode};
let mut data = [0; 5];
let mut cycles: [u32; 80] = [0; 80];
let mut rtclock = linux_realtime::Clock::new()?;
self.pin.set_mode(Mode::Input);
self.pin.set_bias(Bias::PullUp);
rtclock.sleep(Duration::from_millis(1))?;
self.pin.set_mode(Mode::Output);
self.pin.set_low();
rtclock.sleep(Duration::from_millis(20))?;
// Timing Critical Code
self.pin.set_mode(Mode::Input);
self.pin.set_bias(Bias::PullUp);
rtclock.sleep(Duration::from_micros(55))?;
self.expect_pulse(false)?;
self.expect_pulse(true)?;
for i in (0..80).step_by(2) {
cycles[i] = self.expect_pulse(false)?;
cycles[i + 1] = self.expect_pulse(true)?;
}
for i in 0..40 {
let low_cycles = cycles[2 * i];
let high_cycles = cycles[2 * i + 1];
data[i / 8] <<= 1;
if high_cycles > low_cycles {
data[i / 8] |= 1;
}
}
if data[4] != ((data[0] + data[1] + data[2] + data[3]) & 0xFF) {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
"DHT Checksum Failure",
)
.into());
}
let mut temperature = data[2] as f32;
if data[3] & 0x80 != 0 {
temperature = -1. - temperature;
}
temperature += ((data[3] & 0x0F) as f32) * 0.1;
let mut humidity = data[0] as f32;
humidity += (data[1] as f32) * 0.1;
Ok(Dht11Data {
temperature,
humidity,
})
}
}

3
src/error.rs

@ -0,0 +1,3 @@
use std::error::Error;
type GenericResult<T> = Result<T, Box<dyn Error>>;

75
src/io.rs

@ -0,0 +1,75 @@
use ads1x1x::{Ads1x1x, ChannelSelection, DynamicOneShot};
use nb::block;
use rppal::gpio::{Gpio, OutputPin};
use crate::{config::*, GenericResult};
pub fn get_input_voltage(pin: u8) -> GenericResult<f32> {
const ADS1115_DEFAULT_RANGE: f32 = 2.048;
let adc = rppal::i2c::I2c::new()?;
let mut adc = Ads1x1x::new_ads1115(adc, ads1x1x::SlaveAddr::Alternative(false, false));
let channel: ChannelSelection = match pin {
0 => ChannelSelection::SingleA0,
1 => ChannelSelection::SingleA1,
2 => ChannelSelection::SingleA2,
3 => ChannelSelection::SingleA3,
_ => return Err(format!("Pin {} not available. Only 0-3", pin).into()),
};
let result = block!(adc.read(channel)).map_err(|e| format!("{:?}", e))?;
let result = result as f32;
let result = result / i16::MAX as f32 * ADS1115_DEFAULT_RANGE;
Ok(result)
}
pub struct Relay {
relay_pins: [Option<rppal::gpio::OutputPin>; RELAY_GPIO_PINS.len()],
}
pub enum RelaySwitchState {
On,
Off,
}
impl Relay {
pub fn new() -> GenericResult<Relay> {
let mut output_pins = RELAY_GPIO_PINS.map(|pin| {
pin.and_then(|pin| {
let result =
(|| -> GenericResult<OutputPin> { Ok(Gpio::new()?.get(pin)?.into_output()) })();
result.ok()
})
});
for pin in output_pins.iter_mut().flatten() {
// The relay turns ON on LOW
pin.set_high();
}
Ok(Relay {
relay_pins: output_pins,
})
}
pub fn toggle(&mut self, pin: u8) -> GenericResult<()> {
let pin = self.get_output_pin(pin)?;
pin.toggle();
Ok(())
}
pub fn switch(&mut self, pin: u8, state: RelaySwitchState) -> GenericResult<()> {
let pin = self.get_output_pin(pin)?;
match state {
RelaySwitchState::On => pin.set_low(),
RelaySwitchState::Off => pin.set_high(),
}
Ok(())
}
fn get_output_pin(&mut self, pin: u8) -> GenericResult<&mut OutputPin> {
Ok(self
.relay_pins
.get_mut(pin as usize)
.ok_or(format!(
"Pin {} not within pin array with length {}",
pin,
RELAY_GPIO_PINS.len()
))?
.as_mut()
.ok_or("Pin not configured.")?)
}
}

16
src/main.rs

@ -1,11 +1,15 @@
use std::{error::Error, io, thread, time::Duration};
#![allow(dead_code)]
use std::{error::Error, thread, time::Duration};
use ads1x1x::{Ads1x1x, ChannelSelection, DynamicOneShot}; use ads1x1x::{Ads1x1x, ChannelSelection, DynamicOneShot};
use nb::block; use nb::block;
use rppal::{
gpio::{Gpio, OutputPin},
i2c::I2c,
};
use rppal::gpio::{Gpio, OutputPin};
mod actuators;
mod config;
mod error;
mod io;
mod sensors;
type GenericResult<T> = Result<T, Box<dyn Error>>; type GenericResult<T> = Result<T, Box<dyn Error>>;
@ -37,7 +41,7 @@ fn main() -> GenericResult<()> {
loop { loop {
println!("Enter command: "); println!("Enter command: ");
let mut input_string = String::new(); let mut input_string = String::new();
io::stdin().read_line(&mut input_string)?;
std::io::stdin().read_line(&mut input_string)?;
match process_command(input_string, &mut program_state) { match process_command(input_string, &mut program_state) {
Ok(to_exit) => { Ok(to_exit) => {

15
src/sensors.rs

@ -0,0 +1,15 @@
use crate::{config::*, io::get_input_voltage, GenericResult};
pub fn get_temperature() -> GenericResult<f32> {
const THERMISTOR_NOMINAL_RESISTANCE: f32 = 10_000.;
const THERMISTOR_NOMINAL_TEMPERATURE: f32 = 298.15;
const THERMISTOR_CONSTANT: f32 = 3950.;
let voltage = get_input_voltage(THERMISTOR_ANALOG_PIN)?;
let resistance = (LOGIC_LEVEL / voltage - 1.) * THERMISTOR_VOLTAGE_DIVIDER_RESISTANCE;
let temperature = 1.
/ ((1. / THERMISTOR_NOMINAL_TEMPERATURE)
+ (1. / THERMISTOR_CONSTANT * f32::ln(resistance / THERMISTOR_NOMINAL_RESISTANCE)))
- 273.15;
Ok(temperature)
}
Loading…
Cancel
Save