refactored hardware components

detach trait from mock and hardware implementation
This commit is contained in:
Djeeberjr 2025-06-02 14:46:24 +02:00
parent dc8fd22f0f
commit efd096a149
7 changed files with 75 additions and 56 deletions

View File

@ -4,10 +4,10 @@ use smart_leds::colors::{GREEN, RED};
use std::{error::Error, time::Duration};
use tokio::{join, time::sleep};
use crate::{
buzzer::{Buzzer, GPIOBuzzer},
led::{SpiLed, StatusLed},
};
use crate::hardware::{Buzzer, StatusLed};
#[cfg(not(feature = "mock_pi"))]
use crate::{gpio_buzzer::GPIOBuzzer, spi_led::SpiLed};
#[cfg(feature = "mock_pi")]
use crate::mock::{MockBuzzer, MockLed};

View File

@ -1,23 +1,17 @@
use rppal::pwm::{Channel, Error, Polarity, Pwm};
use std::{future::Future, time::Duration};
use rppal::pwm::{Channel, Polarity, Pwm};
use std::{error::Error, time::Duration};
use tokio::time::sleep;
const DEFAULT_PWM_CHANNEL_BUZZER: Channel = Channel::Pwm0; //PWM0 = GPIO18/Physical pin 12
use crate::hardware::Buzzer;
pub trait Buzzer {
fn modulated_tone(
&mut self,
frequency_hz: f64,
duration: Duration,
) -> impl Future<Output = Result<(), Error>> + std::marker::Send;
}
const DEFAULT_PWM_CHANNEL_BUZZER: Channel = Channel::Pwm0; //PWM0 = GPIO18/Physical pin 12
pub struct GPIOBuzzer {
pwm: Pwm,
}
impl GPIOBuzzer {
pub fn new_from_channel(channel: Channel) -> Result<Self, Error> {
pub fn new_from_channel(channel: Channel) -> Result<Self, rppal::pwm::Error> {
// Enable with dummy values; we'll set frequency/duty in the tone method
let duty_cycle: f64 = 0.5;
let pwm = Pwm::with_frequency(channel, 1000.0, duty_cycle, Polarity::Normal, true)?;
@ -26,13 +20,17 @@ impl GPIOBuzzer {
Ok(GPIOBuzzer { pwm })
}
pub fn new_default() -> Result<Self, Error> {
pub fn new_default() -> Result<Self, rppal::pwm::Error> {
Self::new_from_channel(DEFAULT_PWM_CHANNEL_BUZZER)
}
}
impl Buzzer for GPIOBuzzer {
async fn modulated_tone(&mut self, frequency_hz: f64, duration: Duration) -> Result<(), Error> {
async fn modulated_tone(
&mut self,
frequency_hz: f64,
duration: Duration,
) -> Result<(), Box<dyn Error>> {
self.pwm.set_frequency(frequency_hz, 0.5)?; // 50% duty cycle (square wave)
self.pwm.enable()?;
sleep(duration).await;

47
src/hardware.rs Normal file
View File

@ -0,0 +1,47 @@
use std::{error::Error, time::Duration};
use crate::hotspot::{HotspotError};
#[cfg(feature = "mock_pi")]
use crate::mock::MockHotspot;
#[cfg(not(feature = "mock_pi"))]
use crate::hotspot::NMHotspot;
pub trait StatusLed {
fn turn_off(&mut self) -> Result<(), Box<dyn Error>>;
fn turn_on(&mut self, color: rgb::RGB8) -> Result<(), Box<dyn Error>>;
}
pub trait Buzzer {
fn modulated_tone(
&mut self,
frequency_hz: f64,
duration: Duration,
) -> impl Future<Output = Result<(), Box<dyn Error>>> + std::marker::Send;
}
pub trait Hotspot {
fn enable_hotspot(
&self,
) -> impl std::future::Future<Output = Result<(), HotspotError>> + std::marker::Send;
fn disable_hotspot(
&self,
) -> impl std::future::Future<Output = Result<(), HotspotError>> + std::marker::Send;
}
/// Create a struct to manage the hotspot
/// Respects the `mock_pi` flag.
pub fn create_hotspot() -> Result<impl Hotspot, HotspotError> {
#[cfg(feature = "mock_pi")]
{
Ok(MockHotspot {})
}
#[cfg(not(feature = "mock_pi"))]
{
NMHotspot::new_from_env()
}
}

View File

@ -6,6 +6,8 @@ use std::{
};
use tokio::process::Command;
use crate::hardware::Hotspot;
const SSID: &str = "fwa";
const CON_NAME: &str = "fwa-hotspot";
const PASSWORD: &str = "a9LG2kUVrsRRVUo1";
@ -41,16 +43,6 @@ impl fmt::Display for HotspotError {
impl std::error::Error for HotspotError {}
pub trait Hotspot {
fn enable_hotspot(
&self,
) -> impl std::future::Future<Output = Result<(), HotspotError>> + std::marker::Send;
fn disable_hotspot(
&self,
) -> impl std::future::Future<Output = Result<(), HotspotError>> + std::marker::Send;
}
/// NetworkManager Hotspot
pub struct NMHotspot {
ssid: String,

View File

@ -1,6 +1,8 @@
#![allow(dead_code)]
use activity_fairing::{ActivityNotifier, spawn_idle_watcher};
use feedback::{Feedback, FeedbackImpl};
use hotspot::{Hotspot, HotspotError, NMHotspot};
use hardware::{Hotspot, create_hotspot};
use id_store::IDStore;
use log::{error, info, warn};
use pm3::run_pm3;
@ -16,39 +18,23 @@ use tokio::{
};
use webserver::start_webserver;
#[cfg(feature = "mock_pi")]
use mock::MockHotspot;
mod activity_fairing;
mod buzzer;
mod feedback;
mod gpio_buzzer;
mod hardware;
mod hotspot;
mod id_mapping;
mod id_store;
mod led;
mod logger;
mod mock;
mod parser;
mod pm3;
mod spi_led;
mod tally_id;
mod webserver;
const STORE_PATH: &str = "./data.json";
/// Create a struct to manage the hotspot
/// Respects the `mock_pi` flag.
fn create_hotspot() -> Result<impl Hotspot, HotspotError> {
#[cfg(feature = "mock_pi")]
{
Ok(MockHotspot {})
}
#[cfg(not(feature = "mock_pi"))]
{
NMHotspot::new_from_env()
}
}
async fn run_webserver<H>(
store: Arc<Mutex<IDStore>>,
id_channel: Sender<String>,

View File

@ -1,9 +1,9 @@
use std::time::Duration;
use std::{error::Error, time::Duration};
use log::debug;
use tokio::time::sleep;
use crate::{buzzer::Buzzer, hotspot::Hotspot, led::StatusLed};
use crate::hardware::{Buzzer, Hotspot, StatusLed};
pub struct MockBuzzer {}
@ -12,7 +12,7 @@ impl Buzzer for MockBuzzer {
&mut self,
frequency_hz: f64,
duration: Duration,
) -> Result<(), rppal::pwm::Error> {
) -> Result<(), Box<dyn Error>> {
debug!("MockBuzzer: modulte tone: {frequency_hz} Hz");
sleep(duration).await;
Ok(())

View File

@ -3,14 +3,10 @@ use smart_leds::SmartLedsWrite;
use std::error::Error;
use ws2812_spi::Ws2812;
use crate::hardware::StatusLed;
const SPI_CLOCK_SPEED: u32 = 3_800_000;
pub trait StatusLed {
fn turn_off(&mut self) -> Result<(), Box<dyn Error>>;
fn turn_on(&mut self, color: rgb::RGB8) -> Result<(), Box<dyn Error>>;
}
pub struct SpiLed {
controller: Ws2812<Spi>,
}