Move relay drivers from common to controller

This commit is contained in:
Tobias Reisinger 2024-05-05 23:46:38 +02:00
parent e9ea0b625d
commit 340c4e9f15
Signed by: serguzim
GPG key ID: 13AD60C237A28DFE
9 changed files with 181 additions and 17 deletions

BIN
Cargo.lock generated

Binary file not shown.

View file

@ -3,7 +3,6 @@ use std::time::{Duration, Instant};
use actix::{Actor, Context, Handler, Message}; use actix::{Actor, Context, Handler, Message};
use emgauwa_common::constants; use emgauwa_common::constants;
use emgauwa_common::drivers::RelayDriver;
use emgauwa_common::errors::EmgauwaError; use emgauwa_common::errors::EmgauwaError;
use emgauwa_common::models::Controller; use emgauwa_common::models::Controller;
use emgauwa_common::types::RelayStates; use emgauwa_common::types::RelayStates;
@ -11,6 +10,7 @@ use futures::executor::block_on;
use sqlx::{Pool, Sqlite}; use sqlx::{Pool, Sqlite};
use tokio::sync::Notify; use tokio::sync::Notify;
use crate::drivers::RelayDriver;
use crate::settings::Settings; use crate::settings::Settings;
#[derive(Message)] #[derive(Message)]

31
src/drivers/gpio.rs Normal file
View file

@ -0,0 +1,31 @@
use rppal::gpio::{Gpio, OutputPin};
use crate::drivers::RelayDriver;
use crate::errors::EmgauwaControllerError;
pub struct GpioDriver {
pub gpio: OutputPin,
pub inverted: bool,
}
impl GpioDriver {
pub fn new(pin: u8, inverted: bool) -> Result<Self, EmgauwaControllerError> {
let gpio = Gpio::new()?.get(pin)?.into_output();
Ok(Self { gpio, inverted })
}
}
impl RelayDriver for GpioDriver {
fn set(&mut self, value: bool) -> Result<(), EmgauwaControllerError> {
if self.get_high(value) {
self.gpio.set_high();
} else {
self.gpio.set_low();
}
Ok(())
}
fn get_inverted(&self) -> bool {
self.inverted
}
}

View file

@ -1,4 +1,21 @@
pub use gpio::GpioDriver;
pub use null::NullDriver;
pub use piface::PiFaceDriver;
use serde::{Deserialize, Deserializer}; use serde::{Deserialize, Deserializer};
use crate::errors::EmgauwaControllerError;
mod gpio;
mod null;
mod piface;
pub trait RelayDriver {
fn get_high(&self, value: bool) -> bool {
value ^ self.get_inverted()
}
fn set(&mut self, value: bool) -> Result<(), EmgauwaControllerError>;
fn get_inverted(&self) -> bool;
}
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub enum Driver { pub enum Driver {

22
src/drivers/null.rs Normal file
View file

@ -0,0 +1,22 @@
use crate::drivers::RelayDriver;
use crate::errors::EmgauwaControllerError;
pub struct NullDriver {
pub pin: u8,
}
impl NullDriver {
pub fn new(pin: u8) -> Self {
Self { pin }
}
}
impl RelayDriver for NullDriver {
fn set(&mut self, _value: bool) -> Result<(), EmgauwaControllerError> {
Ok(())
}
fn get_inverted(&self) -> bool {
false
}
}

48
src/drivers/piface.rs Normal file
View file

@ -0,0 +1,48 @@
use rppal_pfd::{
ChipSelect, HardwareAddress, OutputPin, PiFaceDigital, PiFaceDigitalError, SpiBus, SpiMode,
};
use crate::drivers::RelayDriver;
use crate::errors::EmgauwaControllerError;
pub struct PiFaceDriver {
pub pfd_pin: OutputPin,
}
impl PiFaceDriver {
pub fn new(pin: u8, pfd: &Option<PiFaceDigital>) -> Result<Self, EmgauwaControllerError> {
let pfd = pfd.as_ref().ok_or(EmgauwaControllerError::Hardware(String::from(
"PiFaceDigital not initialized",
)))?;
let pfd_pin = pfd.get_output_pin(pin)?;
Ok(Self { pfd_pin })
}
pub fn init_piface() -> Result<PiFaceDigital, EmgauwaControllerError> {
let mut pfd = PiFaceDigital::new(
HardwareAddress::new(0)?,
SpiBus::Spi0,
ChipSelect::Cs0,
100_000,
SpiMode::Mode0,
)?;
pfd.init()?;
Ok(pfd)
}
}
impl RelayDriver for PiFaceDriver {
fn set(&mut self, value: bool) -> Result<(), EmgauwaControllerError> {
if self.get_high(value) {
self.pfd_pin.set_high().map_err(PiFaceDigitalError::from)?;
} else {
self.pfd_pin.set_low().map_err(PiFaceDigitalError::from)?;
}
Ok(())
}
fn get_inverted(&self) -> bool {
false
}
}

50
src/errors.rs Normal file
View file

@ -0,0 +1,50 @@
use std::fmt::{Display, Formatter};
use rppal::gpio;
use rppal_mcp23s17::Mcp23s17Error;
use rppal_pfd::PiFaceDigitalError;
use emgauwa_common::errors::EmgauwaError;
#[derive(Debug)]
pub enum EmgauwaControllerError {
Hardware(String),
}
impl Display for EmgauwaControllerError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", EmgauwaError::from(self))
}
}
impl From<gpio::Error> for EmgauwaControllerError {
fn from(value: gpio::Error) -> Self {
Self::Hardware(value.to_string())
}
}
impl From<PiFaceDigitalError> for EmgauwaControllerError {
fn from(value: PiFaceDigitalError) -> Self {
match value {
PiFaceDigitalError::Mcp23s17Error { source } => match source {
Mcp23s17Error::SpiError { source } => Self::Hardware(source.to_string()),
_ => Self::Hardware(source.to_string()),
},
PiFaceDigitalError::GpioError { source } => Self::Hardware(source.to_string()),
_ => Self::Hardware(value.to_string()),
}
}
}
impl From<&EmgauwaControllerError> for EmgauwaError {
fn from(value: &EmgauwaControllerError) -> Self {
match value {
EmgauwaControllerError::Hardware(value) => EmgauwaError::Hardware(value.to_string()),
}
}
}
impl From<EmgauwaControllerError> for EmgauwaError {
fn from(value: EmgauwaControllerError) -> Self {
EmgauwaError::from(&value)
}
}

View file

@ -14,11 +14,12 @@ use crate::settings::Settings;
use crate::ws::run_ws_loop; use crate::ws::run_ws_loop;
mod app_state; mod app_state;
mod driver; mod drivers;
mod relay_loop; mod relay_loop;
mod settings; mod settings;
mod utils; mod utils;
mod ws; mod ws;
mod errors;
async fn create_this_controller( async fn create_this_controller(
conn: &mut PoolConnection<Sqlite>, conn: &mut PoolConnection<Sqlite>,
@ -42,9 +43,7 @@ async fn create_this_relay(
let relay = DbRelay::create( let relay = DbRelay::create(
conn, conn,
&settings_relay.name, &settings_relay.name,
settings_relay.number.ok_or(EmgauwaError::Internal( settings_relay.number,
"Relay number is missing".to_string(),
))?,
this_controller, this_controller,
) )
.await?; .await?;
@ -87,9 +86,7 @@ async fn main() -> Result<(), std::io::Error> {
if DbRelay::get_by_controller_and_num( if DbRelay::get_by_controller_and_num(
&mut conn, &mut conn,
&db_controller, &db_controller,
relay.number.ok_or(EmgauwaError::Internal( relay.number,
"Relay number is missing".to_string(),
))?,
) )
.await .await
.map_err(EmgauwaError::from)? .map_err(EmgauwaError::from)?

View file

@ -1,15 +1,14 @@
use emgauwa_common::errors::EmgauwaError; use emgauwa_common::errors::EmgauwaError;
use emgauwa_common::{drivers, settings}; use emgauwa_common::settings;
use rppal_pfd::PiFaceDigital; use rppal_pfd::PiFaceDigital;
use serde_derive::Deserialize; use serde_derive::Deserialize;
use crate::drivers;
use crate::driver::Driver;
#[derive(Clone, Debug, Deserialize)] #[derive(Clone, Debug, Deserialize)]
#[serde(default)] #[serde(default)]
#[allow(unused)] #[allow(unused)]
pub struct Relay { pub struct Relay {
pub driver: Driver, pub driver: drivers::Driver,
pub name: String, pub name: String,
pub number: i64, pub number: i64,
pub pin: u8, pub pin: u8,
@ -47,8 +46,8 @@ impl Default for Settings {
impl Default for Relay { impl Default for Relay {
fn default() -> Self { fn default() -> Self {
Relay { Relay {
driver: Driver::Gpio, driver: drivers::Driver::Gpio,
number: None, number: 0,
name: String::from("Relay"), name: String::from("Relay"),
pin: 0, pin: 0,
inverted: false, inverted: false,
@ -84,9 +83,9 @@ impl Relay {
pfd: &mut Option<PiFaceDigital>, pfd: &mut Option<PiFaceDigital>,
) -> Result<Box<dyn drivers::RelayDriver>, EmgauwaError> { ) -> Result<Box<dyn drivers::RelayDriver>, EmgauwaError> {
let driver: Box<dyn drivers::RelayDriver> = match self.driver { let driver: Box<dyn drivers::RelayDriver> = match self.driver {
Driver::Null => Box::new(drivers::NullDriver::new(self.pin)), drivers::Driver::Null => Box::new(drivers::NullDriver::new(self.pin)),
Driver::Gpio => Box::new(drivers::GpioDriver::new(self.pin, self.inverted)?), drivers::Driver::Gpio => Box::new(drivers::GpioDriver::new(self.pin, self.inverted)?),
Driver::PiFace => { drivers::Driver::PiFace => {
if pfd.is_none() { if pfd.is_none() {
*pfd = Some(drivers::PiFaceDriver::init_piface()?); *pfd = Some(drivers::PiFaceDriver::init_piface()?);
} }