mirror of
				https://github.com/Djeeberjr/fw-anwesenheit.git
				synced 2025-11-03 23:24:10 +00:00 
			
		
		
		
	use anyhow for errors
This commit is contained in:
		
							parent
							
								
									efd096a149
								
							
						
					
					
						commit
						4781570f8e
					
				
							
								
								
									
										7
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										7
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							@ -41,6 +41,12 @@ dependencies = [
 | 
			
		||||
 "libc",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "anyhow"
 | 
			
		||||
version = "1.0.98"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "async-stream"
 | 
			
		||||
version = "0.3.6"
 | 
			
		||||
@ -419,6 +425,7 @@ dependencies = [
 | 
			
		||||
name = "fw-anwesenheit"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "anyhow",
 | 
			
		||||
 "chrono",
 | 
			
		||||
 "gpio",
 | 
			
		||||
 "log",
 | 
			
		||||
 | 
			
		||||
@ -22,4 +22,5 @@ rppal = { version = "0.22.1", features = ["hal"] }
 | 
			
		||||
smart-leds = "0.3"
 | 
			
		||||
ws2812-spi = "0.3"
 | 
			
		||||
rgb = "0.8.50"
 | 
			
		||||
anyhow = "1.0.98"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,8 @@
 | 
			
		||||
use anyhow::Result;
 | 
			
		||||
use log::error;
 | 
			
		||||
use rgb::RGB8;
 | 
			
		||||
use smart_leds::colors::{GREEN, RED};
 | 
			
		||||
use std::{error::Error, time::Duration};
 | 
			
		||||
use std::time::Duration;
 | 
			
		||||
use tokio::{join, time::sleep};
 | 
			
		||||
 | 
			
		||||
use crate::hardware::{Buzzer, StatusLed};
 | 
			
		||||
@ -41,18 +42,14 @@ impl<B: Buzzer, L: StatusLed> Feedback<B, L> {
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async fn blink_led_for_duration(
 | 
			
		||||
        led: &mut L,
 | 
			
		||||
        color: RGB8,
 | 
			
		||||
        duration: Duration,
 | 
			
		||||
    ) -> Result<(), Box<dyn Error>> {
 | 
			
		||||
    async fn blink_led_for_duration(led: &mut L, color: RGB8, duration: Duration) -> Result<()> {
 | 
			
		||||
        led.turn_on(color)?;
 | 
			
		||||
        sleep(duration).await;
 | 
			
		||||
        led.turn_off()?;
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async fn beep_ack(buzzer: &mut B) -> Result<(), Box<dyn Error>> {
 | 
			
		||||
    async fn beep_ack(buzzer: &mut B) -> Result<()> {
 | 
			
		||||
        buzzer
 | 
			
		||||
            .modulated_tone(1200.0, Duration::from_millis(100))
 | 
			
		||||
            .await?;
 | 
			
		||||
@ -63,7 +60,7 @@ impl<B: Buzzer, L: StatusLed> Feedback<B, L> {
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async fn beep_nak(buzzer: &mut B) -> Result<(), Box<dyn Error>> {
 | 
			
		||||
    async fn beep_nak(buzzer: &mut B) -> Result<()> {
 | 
			
		||||
        buzzer
 | 
			
		||||
            .modulated_tone(600.0, Duration::from_millis(150))
 | 
			
		||||
            .await?;
 | 
			
		||||
@ -81,7 +78,7 @@ pub type FeedbackImpl = Feedback<MockBuzzer, MockLed>;
 | 
			
		||||
pub type FeedbackImpl = Feedback<GPIOBuzzer, SpiLed>;
 | 
			
		||||
 | 
			
		||||
impl FeedbackImpl {
 | 
			
		||||
    pub fn new() -> Result<Self, Box<dyn Error>> {
 | 
			
		||||
    pub fn new() -> Result<Self> {
 | 
			
		||||
        #[cfg(feature = "mock_pi")]
 | 
			
		||||
        {
 | 
			
		||||
            Ok(Feedback {
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,6 @@
 | 
			
		||||
use anyhow::Result;
 | 
			
		||||
use rppal::pwm::{Channel, Polarity, Pwm};
 | 
			
		||||
use std::{error::Error, time::Duration};
 | 
			
		||||
use std::time::Duration;
 | 
			
		||||
use tokio::time::sleep;
 | 
			
		||||
 | 
			
		||||
use crate::hardware::Buzzer;
 | 
			
		||||
@ -26,11 +27,7 @@ impl GPIOBuzzer {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Buzzer for GPIOBuzzer {
 | 
			
		||||
    async fn modulated_tone(
 | 
			
		||||
        &mut self,
 | 
			
		||||
        frequency_hz: f64,
 | 
			
		||||
        duration: Duration,
 | 
			
		||||
    ) -> Result<(), Box<dyn Error>> {
 | 
			
		||||
    async fn modulated_tone(&mut self, frequency_hz: f64, duration: Duration) -> Result<()> {
 | 
			
		||||
        self.pwm.set_frequency(frequency_hz, 0.5)?; // 50% duty cycle (square wave)
 | 
			
		||||
        self.pwm.enable()?;
 | 
			
		||||
        sleep(duration).await;
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,5 @@
 | 
			
		||||
use std::{error::Error, time::Duration};
 | 
			
		||||
 | 
			
		||||
use crate::hotspot::{HotspotError};
 | 
			
		||||
use anyhow::Result;
 | 
			
		||||
use std::time::Duration;
 | 
			
		||||
 | 
			
		||||
#[cfg(feature = "mock_pi")]
 | 
			
		||||
use crate::mock::MockHotspot;
 | 
			
		||||
@ -9,9 +8,9 @@ use crate::mock::MockHotspot;
 | 
			
		||||
use crate::hotspot::NMHotspot;
 | 
			
		||||
 | 
			
		||||
pub trait StatusLed {
 | 
			
		||||
    fn turn_off(&mut self) -> Result<(), Box<dyn Error>>;
 | 
			
		||||
    fn turn_off(&mut self) -> Result<()>;
 | 
			
		||||
 | 
			
		||||
    fn turn_on(&mut self, color: rgb::RGB8) -> Result<(), Box<dyn Error>>;
 | 
			
		||||
    fn turn_on(&mut self, color: rgb::RGB8) -> Result<()>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub trait Buzzer {
 | 
			
		||||
@ -19,22 +18,18 @@ pub trait Buzzer {
 | 
			
		||||
        &mut self,
 | 
			
		||||
        frequency_hz: f64,
 | 
			
		||||
        duration: Duration,
 | 
			
		||||
    ) -> impl Future<Output = Result<(), Box<dyn Error>>> + std::marker::Send;
 | 
			
		||||
    ) -> impl Future<Output = Result<()>> + std::marker::Send;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub trait Hotspot {
 | 
			
		||||
    fn enable_hotspot(
 | 
			
		||||
        &self,
 | 
			
		||||
    ) -> impl std::future::Future<Output = Result<(), HotspotError>> + std::marker::Send;
 | 
			
		||||
    fn enable_hotspot(&self) -> impl std::future::Future<Output = Result<()>> + std::marker::Send;
 | 
			
		||||
 | 
			
		||||
    fn disable_hotspot(
 | 
			
		||||
        &self,
 | 
			
		||||
    ) -> impl std::future::Future<Output = Result<(), HotspotError>> + std::marker::Send;
 | 
			
		||||
    fn disable_hotspot(&self) -> impl std::future::Future<Output = Result<()>> + std::marker::Send;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Create a struct to manage the hotspot
 | 
			
		||||
/// Respects the `mock_pi` flag.
 | 
			
		||||
pub fn create_hotspot() -> Result<impl Hotspot, HotspotError> {
 | 
			
		||||
pub fn create_hotspot() -> Result<impl Hotspot> {
 | 
			
		||||
    #[cfg(feature = "mock_pi")]
 | 
			
		||||
    {
 | 
			
		||||
        Ok(MockHotspot {})
 | 
			
		||||
 | 
			
		||||
@ -1,9 +1,6 @@
 | 
			
		||||
use log::{error, trace, warn};
 | 
			
		||||
use std::{
 | 
			
		||||
    env,
 | 
			
		||||
    fmt::{self},
 | 
			
		||||
    process::Output,
 | 
			
		||||
};
 | 
			
		||||
use anyhow::{Result, anyhow};
 | 
			
		||||
use log::{trace, warn};
 | 
			
		||||
use std::env;
 | 
			
		||||
use tokio::process::Command;
 | 
			
		||||
 | 
			
		||||
use crate::hardware::Hotspot;
 | 
			
		||||
@ -13,36 +10,6 @@ const CON_NAME: &str = "fwa-hotspot";
 | 
			
		||||
const PASSWORD: &str = "a9LG2kUVrsRRVUo1";
 | 
			
		||||
const IPV4_ADDRES: &str = "192.168.4.1/24";
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
pub enum HotspotError {
 | 
			
		||||
    IoError(std::io::Error),
 | 
			
		||||
    NonZeroExit(Output),
 | 
			
		||||
    PasswordToShort,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl fmt::Display for HotspotError {
 | 
			
		||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
			
		||||
        match self {
 | 
			
		||||
            HotspotError::IoError(err) => {
 | 
			
		||||
                write!(f, "Failed to run hotspot command. I/O error: {err}")
 | 
			
		||||
            }
 | 
			
		||||
            HotspotError::NonZeroExit(output) => {
 | 
			
		||||
                let stdout = String::from_utf8_lossy(&output.stdout);
 | 
			
		||||
                let stderr = String::from_utf8_lossy(&output.stderr);
 | 
			
		||||
                write!(
 | 
			
		||||
                    f,
 | 
			
		||||
                    "Failed to run hotspot command.\nStdout: {stdout}\nStderr: {stderr}",
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
            HotspotError::PasswordToShort => {
 | 
			
		||||
                write!(f, "The password must be at leat 8 characters long")
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl std::error::Error for HotspotError {}
 | 
			
		||||
 | 
			
		||||
/// NetworkManager Hotspot
 | 
			
		||||
pub struct NMHotspot {
 | 
			
		||||
    ssid: String,
 | 
			
		||||
@ -52,7 +19,7 @@ pub struct NMHotspot {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl NMHotspot {
 | 
			
		||||
    pub fn new_from_env() -> Result<Self, HotspotError> {
 | 
			
		||||
    pub fn new_from_env() -> Result<Self> {
 | 
			
		||||
        let ssid = env::var("HOTSPOT_SSID").unwrap_or(SSID.to_owned());
 | 
			
		||||
        let password = env::var("HOTSPOT_PW").unwrap_or_else(|_| {
 | 
			
		||||
            warn!("HOTSPOT_PW not set. Using default password");
 | 
			
		||||
@ -60,8 +27,7 @@ impl NMHotspot {
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        if password.len() < 8 {
 | 
			
		||||
            error!("Hotspot PW is to short");
 | 
			
		||||
            return Err(HotspotError::PasswordToShort);
 | 
			
		||||
            return Err(anyhow!("Hotspot password to short"));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Ok(NMHotspot {
 | 
			
		||||
@ -72,7 +38,7 @@ impl NMHotspot {
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async fn create_hotspot(&self) -> Result<(), HotspotError> {
 | 
			
		||||
    async fn create_hotspot(&self) -> Result<()> {
 | 
			
		||||
        let cmd = Command::new("nmcli")
 | 
			
		||||
            .args(["device", "wifi", "hotspot"])
 | 
			
		||||
            .arg("con-name")
 | 
			
		||||
@ -82,14 +48,13 @@ impl NMHotspot {
 | 
			
		||||
            .arg("password")
 | 
			
		||||
            .arg(&self.password)
 | 
			
		||||
            .output()
 | 
			
		||||
            .await
 | 
			
		||||
            .map_err(HotspotError::IoError)?;
 | 
			
		||||
            .await?;
 | 
			
		||||
 | 
			
		||||
        trace!("nmcli (std): {}", String::from_utf8_lossy(&cmd.stdout));
 | 
			
		||||
        trace!("nmcli (err): {}", String::from_utf8_lossy(&cmd.stderr));
 | 
			
		||||
 | 
			
		||||
        if !cmd.status.success() {
 | 
			
		||||
            return Err(HotspotError::NonZeroExit(cmd));
 | 
			
		||||
            return Err(anyhow!("nmcli command had non-zero exit code"));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let cmd = Command::new("nmcli")
 | 
			
		||||
@ -101,24 +66,22 @@ impl NMHotspot {
 | 
			
		||||
            .arg("ipv4.addresses")
 | 
			
		||||
            .arg(&self.ipv4)
 | 
			
		||||
            .output()
 | 
			
		||||
            .await
 | 
			
		||||
            .map_err(HotspotError::IoError)?;
 | 
			
		||||
            .await?;
 | 
			
		||||
 | 
			
		||||
        if !cmd.status.success() {
 | 
			
		||||
            return Err(HotspotError::NonZeroExit(cmd));
 | 
			
		||||
            return Err(anyhow!("nmcli command had non-zero exit code"));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Checks if the connection already exists
 | 
			
		||||
    async fn exists(&self) -> Result<bool, HotspotError> {
 | 
			
		||||
    async fn exists(&self) -> Result<bool> {
 | 
			
		||||
        let cmd = Command::new("nmcli")
 | 
			
		||||
            .args(["connection", "show"])
 | 
			
		||||
            .arg(&self.con_name)
 | 
			
		||||
            .output()
 | 
			
		||||
            .await
 | 
			
		||||
            .map_err(HotspotError::IoError)?;
 | 
			
		||||
            .await?;
 | 
			
		||||
 | 
			
		||||
        trace!("nmcli (std): {}", String::from_utf8_lossy(&cmd.stdout));
 | 
			
		||||
        trace!("nmcli (err): {}", String::from_utf8_lossy(&cmd.stderr));
 | 
			
		||||
@ -128,7 +91,7 @@ impl NMHotspot {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Hotspot for NMHotspot {
 | 
			
		||||
    async fn enable_hotspot(&self) -> Result<(), HotspotError> {
 | 
			
		||||
    async fn enable_hotspot(&self) -> Result<()> {
 | 
			
		||||
        if !self.exists().await? {
 | 
			
		||||
            self.create_hotspot().await?;
 | 
			
		||||
        }
 | 
			
		||||
@ -137,32 +100,30 @@ impl Hotspot for NMHotspot {
 | 
			
		||||
            .args(["connection", "up"])
 | 
			
		||||
            .arg(&self.con_name)
 | 
			
		||||
            .output()
 | 
			
		||||
            .await
 | 
			
		||||
            .map_err(HotspotError::IoError)?;
 | 
			
		||||
            .await?;
 | 
			
		||||
 | 
			
		||||
        trace!("nmcli (std): {}", String::from_utf8_lossy(&cmd.stdout));
 | 
			
		||||
        trace!("nmcli (err): {}", String::from_utf8_lossy(&cmd.stderr));
 | 
			
		||||
 | 
			
		||||
        if !cmd.status.success() {
 | 
			
		||||
            return Err(HotspotError::NonZeroExit(cmd));
 | 
			
		||||
            return Err(anyhow!("nmcli command had non-zero exit code"));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async fn disable_hotspot(&self) -> Result<(), HotspotError> {
 | 
			
		||||
    async fn disable_hotspot(&self) -> Result<()> {
 | 
			
		||||
        let cmd = Command::new("nmcli")
 | 
			
		||||
            .args(["connection", "down"])
 | 
			
		||||
            .arg(&self.con_name)
 | 
			
		||||
            .output()
 | 
			
		||||
            .await
 | 
			
		||||
            .map_err(HotspotError::IoError)?;
 | 
			
		||||
            .await?;
 | 
			
		||||
 | 
			
		||||
        trace!("nmcli (std): {}", String::from_utf8_lossy(&cmd.stdout));
 | 
			
		||||
        trace!("nmcli (err): {}", String::from_utf8_lossy(&cmd.stderr));
 | 
			
		||||
 | 
			
		||||
        if !cmd.status.success() {
 | 
			
		||||
            return Err(HotspotError::NonZeroExit(cmd));
 | 
			
		||||
            return Err(anyhow!("nmcli command had non-zero exit code"));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Ok(())
 | 
			
		||||
 | 
			
		||||
@ -1,11 +1,8 @@
 | 
			
		||||
use serde::{Deserialize, Serialize};
 | 
			
		||||
use std::{
 | 
			
		||||
    collections::{HashMap, HashSet},
 | 
			
		||||
    error::Error,
 | 
			
		||||
};
 | 
			
		||||
use tokio::fs;
 | 
			
		||||
 | 
			
		||||
use crate::{id_mapping::IDMapping, tally_id::TallyID};
 | 
			
		||||
use anyhow::{Result, anyhow};
 | 
			
		||||
use serde::{Deserialize, Serialize};
 | 
			
		||||
use std::collections::{HashMap, HashSet};
 | 
			
		||||
use tokio::fs;
 | 
			
		||||
 | 
			
		||||
/// Represents a single day that IDs can attend
 | 
			
		||||
#[derive(Deserialize, Serialize)]
 | 
			
		||||
@ -30,7 +27,7 @@ impl IDStore {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Creats a new `IDStore` from a json file
 | 
			
		||||
    pub async fn new_from_json(filepath: &str) -> Result<Self, Box<dyn Error>> {
 | 
			
		||||
    pub async fn new_from_json(filepath: &str) -> Result<Self> {
 | 
			
		||||
        let read_string = fs::read_to_string(filepath).await?;
 | 
			
		||||
        Ok(serde_json::from_str(&read_string)?)
 | 
			
		||||
    }
 | 
			
		||||
@ -59,14 +56,14 @@ impl IDStore {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Writes the store to a json file
 | 
			
		||||
    pub async fn export_json(&self, filepath: &str) -> Result<(), Box<dyn Error + Send + Sync>> {
 | 
			
		||||
    pub async fn export_json(&self, filepath: &str) -> Result<()> {
 | 
			
		||||
        fs::write(filepath, serde_json::to_string(&self)?).await?;
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Export the store to a csv file.
 | 
			
		||||
    /// With days in the rows and IDs in the collum.
 | 
			
		||||
    pub fn export_csv(&self) -> Result<String, Box<dyn Error>> {
 | 
			
		||||
    pub fn export_csv(&self) -> Result<String> {
 | 
			
		||||
        let mut csv = String::new();
 | 
			
		||||
        let seperator = ";";
 | 
			
		||||
        let mut user_ids: HashSet<TallyID> = HashSet::new();
 | 
			
		||||
@ -100,7 +97,7 @@ impl IDStore {
 | 
			
		||||
                let was_there: bool = self
 | 
			
		||||
                    .days
 | 
			
		||||
                    .get(day)
 | 
			
		||||
                    .ok_or("Failed to access day")?
 | 
			
		||||
                    .ok_or(anyhow!("Failed to access day"))?
 | 
			
		||||
                    .ids
 | 
			
		||||
                    .contains(user_id);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										11
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								src/main.rs
									
									
									
									
									
								
							@ -6,7 +6,7 @@ use hardware::{Hotspot, create_hotspot};
 | 
			
		||||
use id_store::IDStore;
 | 
			
		||||
use log::{error, info, warn};
 | 
			
		||||
use pm3::run_pm3;
 | 
			
		||||
use std::{env, error::Error, sync::Arc, time::Duration};
 | 
			
		||||
use std::{env, sync::Arc, time::Duration};
 | 
			
		||||
use tally_id::TallyID;
 | 
			
		||||
use tokio::{
 | 
			
		||||
    fs,
 | 
			
		||||
@ -17,6 +17,7 @@ use tokio::{
 | 
			
		||||
    try_join,
 | 
			
		||||
};
 | 
			
		||||
use webserver::start_webserver;
 | 
			
		||||
use anyhow::Result;
 | 
			
		||||
 | 
			
		||||
mod activity_fairing;
 | 
			
		||||
mod feedback;
 | 
			
		||||
@ -39,7 +40,7 @@ async fn run_webserver<H>(
 | 
			
		||||
    store: Arc<Mutex<IDStore>>,
 | 
			
		||||
    id_channel: Sender<String>,
 | 
			
		||||
    hotspot: Arc<Mutex<H>>,
 | 
			
		||||
) -> Result<(), Box<dyn Error>>
 | 
			
		||||
) -> Result<()>
 | 
			
		||||
where
 | 
			
		||||
    H: Hotspot + Send + Sync + 'static,
 | 
			
		||||
{
 | 
			
		||||
@ -59,7 +60,7 @@ where
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async fn load_or_create_store() -> Result<IDStore, Box<dyn Error>> {
 | 
			
		||||
async fn load_or_create_store() -> Result<IDStore> {
 | 
			
		||||
    if fs::try_exists(STORE_PATH).await? {
 | 
			
		||||
        info!("Loading data from file");
 | 
			
		||||
        IDStore::new_from_json(STORE_PATH).await
 | 
			
		||||
@ -89,7 +90,7 @@ async fn handle_ids_loop(
 | 
			
		||||
    id_store: Arc<Mutex<IDStore>>,
 | 
			
		||||
    hotspot: Arc<Mutex<impl Hotspot>>,
 | 
			
		||||
    mut user_feedback: FeedbackImpl,
 | 
			
		||||
) -> Result<(), Box<dyn Error>> {
 | 
			
		||||
) -> Result<()> {
 | 
			
		||||
    while let Ok(tally_id_string) = id_channel.recv().await {
 | 
			
		||||
        let tally_id = TallyID(tally_id_string);
 | 
			
		||||
 | 
			
		||||
@ -123,7 +124,7 @@ async fn handle_ids_loop(
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[tokio::main]
 | 
			
		||||
async fn main() -> Result<(), Box<dyn Error>> {
 | 
			
		||||
async fn main() -> Result<()> {
 | 
			
		||||
    logger::setup_logger();
 | 
			
		||||
 | 
			
		||||
    info!("Starting application");
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										18
									
								
								src/mock.rs
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								src/mock.rs
									
									
									
									
									
								
							@ -1,6 +1,6 @@
 | 
			
		||||
use std::{error::Error, time::Duration};
 | 
			
		||||
 | 
			
		||||
use anyhow::Result;
 | 
			
		||||
use log::debug;
 | 
			
		||||
use std::time::Duration;
 | 
			
		||||
use tokio::time::sleep;
 | 
			
		||||
 | 
			
		||||
use crate::hardware::{Buzzer, Hotspot, StatusLed};
 | 
			
		||||
@ -8,11 +8,7 @@ use crate::hardware::{Buzzer, Hotspot, StatusLed};
 | 
			
		||||
pub struct MockBuzzer {}
 | 
			
		||||
 | 
			
		||||
impl Buzzer for MockBuzzer {
 | 
			
		||||
    async fn modulated_tone(
 | 
			
		||||
        &mut self,
 | 
			
		||||
        frequency_hz: f64,
 | 
			
		||||
        duration: Duration,
 | 
			
		||||
    ) -> Result<(), Box<dyn Error>> {
 | 
			
		||||
    async fn modulated_tone(&mut self, frequency_hz: f64, duration: Duration) -> Result<()> {
 | 
			
		||||
        debug!("MockBuzzer: modulte tone: {frequency_hz} Hz");
 | 
			
		||||
        sleep(duration).await;
 | 
			
		||||
        Ok(())
 | 
			
		||||
@ -22,12 +18,12 @@ impl Buzzer for MockBuzzer {
 | 
			
		||||
pub struct MockLed {}
 | 
			
		||||
 | 
			
		||||
impl StatusLed for MockLed {
 | 
			
		||||
    fn turn_off(&mut self) -> Result<(), Box<dyn std::error::Error>> {
 | 
			
		||||
    fn turn_off(&mut self) -> Result<()> {
 | 
			
		||||
        debug!("Turn mock LED off");
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn turn_on(&mut self, color: rgb::RGB8) -> Result<(), Box<dyn std::error::Error>> {
 | 
			
		||||
    fn turn_on(&mut self, color: rgb::RGB8) -> Result<()> {
 | 
			
		||||
        debug!("Turn mock LED on to: {color}");
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
@ -36,12 +32,12 @@ impl StatusLed for MockLed {
 | 
			
		||||
pub struct MockHotspot {}
 | 
			
		||||
 | 
			
		||||
impl Hotspot for MockHotspot {
 | 
			
		||||
    async fn enable_hotspot(&self) -> Result<(), crate::hotspot::HotspotError> {
 | 
			
		||||
    async fn enable_hotspot(&self) -> Result<()> {
 | 
			
		||||
        debug!("Mockhotspot: Enable hotspot");
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async fn disable_hotspot(&self) -> Result<(), crate::hotspot::HotspotError> {
 | 
			
		||||
    async fn disable_hotspot(&self) -> Result<()> {
 | 
			
		||||
        debug!("Mockhotspot: Disable hotspot");
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										10
									
								
								src/pm3.rs
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								src/pm3.rs
									
									
									
									
									
								
							@ -1,6 +1,6 @@
 | 
			
		||||
use anyhow::{Result, anyhow};
 | 
			
		||||
use log::{debug, info, trace, warn};
 | 
			
		||||
use std::env;
 | 
			
		||||
use std::error::Error;
 | 
			
		||||
use std::process::Stdio;
 | 
			
		||||
use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};
 | 
			
		||||
use tokio::process::Command;
 | 
			
		||||
@ -11,7 +11,7 @@ use tokio::sync::broadcast;
 | 
			
		||||
/// Runs the pm3 binary and monitors it's output
 | 
			
		||||
/// The pm3 binary is ether set in the env var PM3_BIN or found in the path
 | 
			
		||||
/// The ouput is parsed and send via the `tx` channel
 | 
			
		||||
pub async fn run_pm3(tx: broadcast::Sender<String>) -> Result<(), Box<dyn Error>> {
 | 
			
		||||
pub async fn run_pm3(tx: broadcast::Sender<String>) -> Result<()> {
 | 
			
		||||
    kill_orphans().await;
 | 
			
		||||
 | 
			
		||||
    let pm3_path = match env::var("PM3_BIN") {
 | 
			
		||||
@ -32,8 +32,8 @@ pub async fn run_pm3(tx: broadcast::Sender<String>) -> Result<(), Box<dyn Error>
 | 
			
		||||
        .stdin(Stdio::piped())
 | 
			
		||||
        .spawn()?;
 | 
			
		||||
 | 
			
		||||
    let stdout = cmd.stdout.take().ok_or("Failed to get stdout")?;
 | 
			
		||||
    let mut stdin = cmd.stdin.take().ok_or("Failed to get stdin")?;
 | 
			
		||||
    let stdout = cmd.stdout.take().ok_or(anyhow!("Failed to get stdout"))?;
 | 
			
		||||
    let mut stdin = cmd.stdin.take().ok_or(anyhow!("Failed to get stdin"))?;
 | 
			
		||||
 | 
			
		||||
    let mut reader = BufReader::new(stdout).lines();
 | 
			
		||||
 | 
			
		||||
@ -65,7 +65,7 @@ pub async fn run_pm3(tx: broadcast::Sender<String>) -> Result<(), Box<dyn Error>
 | 
			
		||||
    if status.success() {
 | 
			
		||||
        Ok(())
 | 
			
		||||
    } else {
 | 
			
		||||
        Err("PM3 exited with a non-zero exit code".into())
 | 
			
		||||
        Err(anyhow!("PM3 exited with a non-zero exit code"))
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
use anyhow::Result;
 | 
			
		||||
use rppal::spi::{Bus, Mode, SlaveSelect, Spi};
 | 
			
		||||
use smart_leds::SmartLedsWrite;
 | 
			
		||||
use std::error::Error;
 | 
			
		||||
use ws2812_spi::Ws2812;
 | 
			
		||||
 | 
			
		||||
use crate::hardware::StatusLed;
 | 
			
		||||
@ -20,13 +20,13 @@ impl SpiLed {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl StatusLed for SpiLed {
 | 
			
		||||
    fn turn_off(&mut self) -> Result<(), Box<dyn Error>> {
 | 
			
		||||
    fn turn_off(&mut self) -> Result<()> {
 | 
			
		||||
        self.controller
 | 
			
		||||
            .write(vec![rgb::RGB8::new(0, 0, 0)].into_iter())?;
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn turn_on(&mut self, color: rgb::RGB8) -> Result<(), Box<dyn Error>> {
 | 
			
		||||
    fn turn_on(&mut self, color: rgb::RGB8) -> Result<()> {
 | 
			
		||||
        self.controller.write(vec![color].into_iter())?;
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user