diff --git a/Cargo.lock b/Cargo.lock index d050f0a..7b97223 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -273,6 +273,16 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +[[package]] +name = "embedded-hal" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff" +dependencies = [ + "nb 0.1.3", + "void", +] + [[package]] name = "encoding_rs" version = "0.8.35" @@ -403,7 +413,9 @@ dependencies = [ "serde", "serde_json", "simplelog", + "smart-leds", "tokio", + "ws2812-spi", ] [[package]] @@ -753,6 +765,21 @@ dependencies = [ "version_check", ] +[[package]] +name = "nb" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" +dependencies = [ + "nb 1.1.0", +] + +[[package]] +name = "nb" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" + [[package]] name = "nu-ansi-term" version = "0.46.0" @@ -1037,6 +1064,15 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +[[package]] +name = "rgb" +version = "0.8.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57397d16646700483b67d2dd6511d79318f9d057fdbd21a4066aeac8b41d310a" +dependencies = [ + "bytemuck", +] + [[package]] name = "rocket" version = "0.5.1" @@ -1315,6 +1351,24 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" +[[package]] +name = "smart-leds" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38dd45fa275f70b4110eac5f5182611ad384f88bb22b68b9a9c3cafd7015290b" +dependencies = [ + "smart-leds-trait", +] + +[[package]] +name = "smart-leds-trait" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebf6d833fa93f16a1c1874e62c2aebe8567e5bdd436d59bf543ed258b6f7a8e3" +dependencies = [ + "rgb", +] + [[package]] name = "socket2" version = "0.5.9" @@ -1634,6 +1688,12 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + [[package]] name = "walkdir" version = "2.5.0" @@ -1982,6 +2042,17 @@ dependencies = [ "bitflags", ] +[[package]] +name = "ws2812-spi" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6c2ba0d6c0ea9c117487411e93dc5dacaafc2c17698677a03d1c67901d4c70a" +dependencies = [ + "embedded-hal", + "nb 0.1.3", + "smart-leds-trait", +] + [[package]] name = "yansi" version = "1.0.1" diff --git a/Cargo.toml b/Cargo.toml index c3178f6..41e2ed0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,6 @@ edition = "2024" chrono = { version = "0.4.40", features = ["serde"] } gpio = "0.4.1" regex = "1.11.1" -rppal = "0.22.1" serde = { version = "1.0.219", features = ["derive"] } serde_json = "1.0.140" rocket = "0.5.1" @@ -16,5 +15,9 @@ rust-embed = "8.7.0" log = "0.4.27" simplelog = "0.12.2" +rppal = "0.22.1" +smart-leds = "0.3" +ws2812-spi = "0.3" + [target.armv7-unknown-linux-gnueabihf] linker = "arm-linux-gnueabihf-gcc" diff --git a/buzzer.py b/buzzer.py new file mode 100644 index 0000000..c39f070 --- /dev/null +++ b/buzzer.py @@ -0,0 +1,24 @@ +import RPi.GPIO as GPIO +import time + +BUZZER_PIN = 26 + +def beep(frequency, duration): + pwm = GPIO.PWM(BUZZER_PIN, frequency) + pwm.start(50) # 50 % duty cycle + time.sleep(duration) + pwm.stop() + +def main(): + GPIO.setmode(GPIO.BCM) + GPIO.setup(BUZZER_PIN, GPIO.OUT) + + try: + beep(523, 0.3) # C5 + beep(659, 0.3) # E5 + beep(784, 0.3) # G5 + finally: + GPIO.cleanup() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/src/buzzer.rs b/src/buzzer.rs index 7030749..c5b8158 100644 --- a/src/buzzer.rs +++ b/src/buzzer.rs @@ -1,46 +1,49 @@ -use rppal::gpio::Gpio; -use std::{thread, time}; +pub mod buzzer { + use rppal::gpio::Gpio; + use std::{thread, time}; -/// Emits a sound on a passive buzzer. -pub fn modulated_tone(pin_num: u8, carrier_hz: u32, sound_hz: u32, duration_ms: u64) { - let gpio = Gpio::new().expect("GPIO konnte nicht initialisiert werden"); - let mut pin = gpio.get(pin_num).expect("Pin konnte nicht geöffnet werden").into_output(); - let carrier_period = time::Duration::from_micros((1_000_000.0 / carrier_hz as f64 / 2.0) as u64); - let mod_period = 1_000.0 / sound_hz as f64; // in ms - let total_cycles = duration_ms as f64 / mod_period; + /// Emits a sound on a passive buzzer. + pub fn modulated_tone(pin_num: u8, carrier_hz: u32, sound_hz: u32, duration_ms: u64) { + let gpio = Gpio::new().expect("GPIO konnte nicht initialisiert werden"); + let mut pin = gpio.get(pin_num).expect("Pin konnte nicht geöffnet werden").into_output(); - for _ in 0..total_cycles as u64 { - // Modulation on: Carrier on for mod_period / 2 - let cycles_on = (carrier_hz as f64 * (mod_period / 2.0) / 1000.0) as u64; - for _ in 0..cycles_on { - pin.set_high(); - thread::sleep(carrier_period); - pin.set_low(); - thread::sleep(carrier_period); + let carrier_period = time::Duration::from_micros((1_000_000.0 / carrier_hz as f64 / 2.0) as u64); + let mod_period = 1_000.0 / sound_hz as f64; // in ms + let total_cycles = duration_ms as f64 / mod_period; + + for _ in 0..total_cycles as u64 { + // Modulation on: Carrier on for mod_period / 2 + let cycles_on = (carrier_hz as f64 * (mod_period / 2.0) / 1000.0) as u64; + for _ in 0..cycles_on { + pin.set_high(); + thread::sleep(carrier_period); + pin.set_low(); + thread::sleep(carrier_period); + } + + // Modulation off: Carrier on for mod_period / 2 + let pause = time::Duration::from_millis((mod_period / 2.0) as u64); + thread::sleep(pause); } + } - // Modulation off: Carrier on for mod_period / 2 - let pause = time::Duration::from_millis((mod_period / 2.0) as u64); - thread::sleep(pause); + pub fn beep_ack() { + // GPIO 17, carrier = 2300 Hz, sound = 440 Hz, Dauer = 1 sec + modulated_tone(4, 2300, 500, 500); + modulated_tone(4, 2300, 700, 500); + } + + pub fn beep_nak() { + // GPIO 17, carrier = 2300 Hz, sound = 440 Hz, duration = 1 sec + modulated_tone(4, 2300, 700, 500); + modulated_tone(4, 2300, 500, 500); + } + + pub fn beep_unnkown(){ + modulated_tone(4, 2300, 500, 500); + modulated_tone(4, 2300, 500, 500); + modulated_tone(4, 2300, 500, 500); } } -pub fn beep_ack() { - // GPIO 17, carrier = 2300 Hz, sound = 440 Hz, Dauer = 1 sec - modulated_tone(4, 2300, 500, 500); - modulated_tone(4, 2300, 700, 500); -} - -pub fn beep_nak() { - // GPIO 17, carrier = 2300 Hz, sound = 440 Hz, duration = 1 sec - modulated_tone(4, 2300, 700, 500); - modulated_tone(4, 2300, 500, 500); -} - -pub fn beep_unnkown(){ - modulated_tone(4, 2300, 500, 500); - modulated_tone(4, 2300, 500, 500); - modulated_tone(4, 2300, 500, 500); -} - diff --git a/src/color.rs b/src/color.rs new file mode 100644 index 0000000..ce32ed5 --- /dev/null +++ b/src/color.rs @@ -0,0 +1,39 @@ +#[derive(Clone, Copy)] +pub struct Color { + pub r: u8, + pub g: u8, + pub b: u8, +} + +impl Color { + pub fn to_grb(self) -> [u8; 3] { + [self.g, self.r, self.b] + } +} + +#[derive(Debug, Clone, Copy)] +pub enum NamedColor { + Red, + Green, + Blue, + White, + Off, + Yellow, + Cyan, + Magenta, +} + +impl From for Color { + fn from(named: NamedColor) -> Self { + match named { + NamedColor::Red => Color { r: 255, g: 0, b: 0 }, + NamedColor::Green => Color { r: 0, g: 255, b: 0 }, + NamedColor::Blue => Color { r: 0, g: 0, b: 255 }, + NamedColor::White => Color { r: 255, g: 255, b: 255 }, + NamedColor::Off => Color { r: 0, g: 0, b: 0 }, + NamedColor::Yellow => Color { r: 255, g: 255, b: 0 }, + NamedColor::Cyan => Color { r: 0, g: 255, b: 255 }, + NamedColor::Magenta => Color { r: 255, g: 0, b: 255 }, + } + } +} diff --git a/src/id_store.rs b/src/id_store.rs index e255652..f6717b4 100644 --- a/src/id_store.rs +++ b/src/id_store.rs @@ -4,6 +4,11 @@ use std::{ error::Error, fmt::Display, }; + +use crate::led::Led; +use tokio::fs; + +use crate::led::Led; use tokio::fs; /// Represents the ID that is stored on the Tally @@ -130,7 +135,12 @@ impl AttendanceDay { return false; } self.ids.push(id); - true + + + buzzer::beep_ack(); + led.set_named_color_time(NamedColor::Green, 1); //led is green for 1 sec + + return true; } } diff --git a/src/led.rs b/src/led.rs new file mode 100644 index 0000000..e849313 --- /dev/null +++ b/src/led.rs @@ -0,0 +1,28 @@ +use rppal::spi::{Bus, Mode, SlaveSelect, Spi}; +use smart_leds::{SmartLedsWrite, RGB8}; +use ws2812_spi::Ws2812; + + +pub struct Led { + controller: Ws2812, +} + +impl Led { + pub fn new() -> Result> { + let spi = Spi::new(Bus::Spi0, SlaveSelect::Ss0, 3_000_000, Mode::Mode0)?; + let controller = Ws2812::new(spi); + Ok(Led { controller }) + } + + pub fn turn_green_on(&mut self) -> Result<(), Box> { + let green = [RGB8 { r: 0, g: 255, b: 0 }]; + self.controller.write(green.iter().cloned())?; + Ok(()) + } + + pub fn turn_off(&mut self) -> Result<(), Box> { + let off = [RGB8 { r: 0, g: 0, b: 0 }]; + self.controller.write(off.iter().cloned())?; + Ok(()) + } +} diff --git a/src/main.rs b/src/main.rs index cd29d46..fc7c409 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,6 +13,10 @@ mod id_store; mod parser; mod pm3; mod webserver; +mod color; +mod led; +mod buzzer; + const STORE_PATH: &str = "./data.json"; @@ -85,6 +89,10 @@ async fn main() -> Result<(), Box> { } }); + tokio::spawn(async move { + + }) + match start_webserver(store.clone()).await { Ok(()) => {} Err(e) => {