mirror of
				https://github.com/Djeeberjr/fw-anwesenheit.git
				synced 2025-11-03 23:24:10 +00:00 
			
		
		
		
	added buzzer
This commit is contained in:
		
							parent
							
								
									a9bbc61300
								
							
						
					
					
						commit
						ad009f987d
					
				
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@ -1 +1 @@
 | 
			
		||||
/target
 | 
			
		||||
/target
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										33
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										33
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							@ -79,9 +79,18 @@ name = "fw-anwesenheit"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "chrono",
 | 
			
		||||
 "gpio",
 | 
			
		||||
 "regex",
 | 
			
		||||
 "serde",
 | 
			
		||||
 "serde_json",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "gpio"
 | 
			
		||||
version = "0.4.1"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "4fe6783270536547ac473c9d2ae5a7e0e715ea43f29004ced47fbd1c1372d2c7"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "iana-time-zone"
 | 
			
		||||
version = "0.1.63"
 | 
			
		||||
@ -106,6 +115,12 @@ dependencies = [
 | 
			
		||||
 "cc",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "itoa"
 | 
			
		||||
version = "1.0.15"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "js-sys"
 | 
			
		||||
version = "0.3.77"
 | 
			
		||||
@ -202,6 +217,12 @@ version = "1.0.20"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "ryu"
 | 
			
		||||
version = "1.0.20"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "serde"
 | 
			
		||||
version = "1.0.219"
 | 
			
		||||
@ -222,6 +243,18 @@ dependencies = [
 | 
			
		||||
 "syn",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "serde_json"
 | 
			
		||||
version = "1.0.140"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "itoa",
 | 
			
		||||
 "memchr",
 | 
			
		||||
 "ryu",
 | 
			
		||||
 "serde",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "shlex"
 | 
			
		||||
version = "1.3.0"
 | 
			
		||||
 | 
			
		||||
@ -5,4 +5,7 @@ edition = "2024"
 | 
			
		||||
 | 
			
		||||
[dependencies]
 | 
			
		||||
chrono = { version = "0.4.40", features = ["serde"] }
 | 
			
		||||
gpio = "0.4.1"
 | 
			
		||||
regex = "1.11.1"
 | 
			
		||||
serde = { version = "1.0.219", features = ["derive"] }
 | 
			
		||||
serde_json = "1.0.140"
 | 
			
		||||
 | 
			
		||||
@ -1,34 +1,34 @@
 | 
			
		||||
@startuml
 | 
			
		||||
actor user
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
main -> pm3 :start
 | 
			
		||||
loop
 | 
			
		||||
    pm3 -> pm3 : look for HITAG
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
user -> pm3 :show HITAG
 | 
			
		||||
 | 
			
		||||
pm3 -> parser : parse ID
 | 
			
		||||
parser -> pm3 : return ID
 | 
			
		||||
 | 
			
		||||
pm3 --> main : send ID
 | 
			
		||||
 | 
			
		||||
loop
 | 
			
		||||
    main -> main : look for IDs
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
main -> idstore : send ID 
 | 
			
		||||
idstore -> System : ask for  day
 | 
			
		||||
alt
 | 
			
		||||
    System -> idstore : return attendence_day
 | 
			
		||||
else
 | 
			
		||||
    create collections attendence_day
 | 
			
		||||
        idstore -> attendence_day : create new attendence_day
 | 
			
		||||
 
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
idstore -> attendence_day : add ID
 | 
			
		||||
attendence_day -> system : save json
 | 
			
		||||
 | 
			
		||||
@startuml
 | 
			
		||||
actor user
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
main -> pm3 :start
 | 
			
		||||
loop
 | 
			
		||||
    pm3 -> pm3 : look for HITAG
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
user -> pm3 :show HITAG
 | 
			
		||||
 | 
			
		||||
pm3 -> parser : parse ID
 | 
			
		||||
parser -> pm3 : return ID
 | 
			
		||||
 | 
			
		||||
pm3 --> main : send ID
 | 
			
		||||
 | 
			
		||||
loop
 | 
			
		||||
    main -> main : look for IDs
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
main -> idstore : send ID 
 | 
			
		||||
idstore -> System : ask for  day
 | 
			
		||||
alt
 | 
			
		||||
    System -> idstore : return attendence_day
 | 
			
		||||
else
 | 
			
		||||
    create collections attendence_day
 | 
			
		||||
        idstore -> attendence_day : create new attendence_day
 | 
			
		||||
 
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
idstore -> attendence_day : add ID
 | 
			
		||||
attendence_day -> system : save json
 | 
			
		||||
 | 
			
		||||
@enduml
 | 
			
		||||
							
								
								
									
										40
									
								
								src/buzzer.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								src/buzzer.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,40 @@
 | 
			
		||||
use rppal::gpio::Gpio;
 | 
			
		||||
use std::{thread, time};
 | 
			
		||||
 | 
			
		||||
/// Gibt einen Ton auf einem passiven Buzzer aus.
 | 
			
		||||
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;
 | 
			
		||||
 | 
			
		||||
    for _ in 0..total_cycles as u64 {
 | 
			
		||||
        // Modulations-Ein: Träger an für 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);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Modulations-Aus: Träger aus für mod_period / 2
 | 
			
		||||
        let pause = time::Duration::from_millis((mod_period / 2.0) as u64);
 | 
			
		||||
        thread::sleep(pause);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn beep_ack() {
 | 
			
		||||
    // GPIO 17, Träger = 2300 Hz, Ton = 440 Hz, Dauer = 1 Sekunde
 | 
			
		||||
    modulated_tone(4, 2300, 500, 500);
 | 
			
		||||
    modulated_tone(4, 2300, 700, 500);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn beep_nak() {
 | 
			
		||||
        // GPIO 17, Träger = 2300 Hz, Ton = 440 Hz, Dauer = 1 Sekunde
 | 
			
		||||
        modulated_tone(4, 2300, 700, 500);
 | 
			
		||||
        modulated_tone(4, 2300, 500, 500);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										144
									
								
								src/id_store.rs
									
									
									
									
									
								
							
							
						
						
									
										144
									
								
								src/id_store.rs
									
									
									
									
									
								
							@ -1,67 +1,77 @@
 | 
			
		||||
use std::collections::HashMap;
 | 
			
		||||
 | 
			
		||||
#[derive(PartialEq, Eq)]
 | 
			
		||||
struct TellyID (String);
 | 
			
		||||
 | 
			
		||||
struct AttendanceDay {
 | 
			
		||||
    date: String,
 | 
			
		||||
    ids: Vec<TellyID>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct IDStore {
 | 
			
		||||
    days: HashMap<String,AttendanceDay>
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl IDStore {
 | 
			
		||||
    fn new() -> Self {
 | 
			
		||||
        IDStore{
 | 
			
		||||
            days: HashMap::new(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn add_id(&mut self, id: TellyID){
 | 
			
		||||
        let day = self.get_current_day();
 | 
			
		||||
 | 
			
		||||
        day.add_id(id);
 | 
			
		||||
 | 
			
		||||
        self.clean_map();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn get_current_day(&mut self) -> &mut AttendanceDay {
 | 
			
		||||
        let current_day = get_day_str();
 | 
			
		||||
 | 
			
		||||
        if self.days.contains_key(¤t_day) {
 | 
			
		||||
            return self.days.get_mut(¤t_day).unwrap();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        self.days.insert(current_day.clone(), AttendanceDay::new(¤t_day.clone()));
 | 
			
		||||
 | 
			
		||||
        self.days.get_mut(¤t_day.clone()).unwrap()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn clean_map(&mut self){
 | 
			
		||||
       todo!()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl AttendanceDay {
 | 
			
		||||
    fn new(day: &str) -> Self{
 | 
			
		||||
        Self{
 | 
			
		||||
            date: day.to_owned(),
 | 
			
		||||
            ids: Vec::new(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn add_id(&mut self, id: TellyID){
 | 
			
		||||
        if self.ids.contains(&id) {
 | 
			
		||||
            return
 | 
			
		||||
        } 
 | 
			
		||||
 | 
			
		||||
        self.ids.push(id);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn get_day_str() -> String {
 | 
			
		||||
    let now = chrono::offset::Local::now();
 | 
			
		||||
    now.format("%Y-%m-%d").to_string()
 | 
			
		||||
}
 | 
			
		||||
use std::{collections::HashMap, error::Error, fs::{self, read_to_string}, result};
 | 
			
		||||
use serde::{Deserialize, Serialize};
 | 
			
		||||
 | 
			
		||||
#[derive(PartialEq, Eq)]
 | 
			
		||||
#[derive(Deserialize, Serialize)]
 | 
			
		||||
struct TellyID (String);
 | 
			
		||||
 | 
			
		||||
#[derive(Deserialize, Serialize)]
 | 
			
		||||
struct AttendanceDay {
 | 
			
		||||
    date: String,
 | 
			
		||||
    ids: Vec<TellyID>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Deserialize, Serialize)]
 | 
			
		||||
struct IDStore {
 | 
			
		||||
    days: HashMap<String,AttendanceDay>
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl IDStore {
 | 
			
		||||
    
 | 
			
		||||
    fn new() -> Self {
 | 
			
		||||
        IDStore{
 | 
			
		||||
            days: HashMap::new(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn new_from_json(filepath:&str) -> Result<Self, Box<dyn Error>>{
 | 
			
		||||
        let readed_string = fs::read_to_string(filepath)?;
 | 
			
		||||
        Ok(serde_json::from_str(&readed_string)?)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn add_id(&mut self, id: TellyID){
 | 
			
		||||
        let day = self.get_current_day();
 | 
			
		||||
 | 
			
		||||
        day.add_id(id);
 | 
			
		||||
    
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn get_current_day(&mut self) -> &mut AttendanceDay {
 | 
			
		||||
        let current_day = get_day_str();
 | 
			
		||||
 | 
			
		||||
        if self.days.contains_key(¤t_day) {
 | 
			
		||||
            return self.days.get_mut(¤t_day).unwrap();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        self.days.insert(current_day.clone(), AttendanceDay::new(¤t_day.clone()));
 | 
			
		||||
 | 
			
		||||
        self.days.get_mut(¤t_day.clone()).unwrap()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn export_jason(&self, filepath:&str) -> Result <(), Box<dyn Error>> {
 | 
			
		||||
 | 
			
		||||
        // Serialize it to a JSON string and safe it in filepath file
 | 
			
		||||
        Ok(fs::write("attendence_list.json", serde_json::to_string(&self)?)?)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl AttendanceDay {
 | 
			
		||||
    fn new(day: &str) -> Self{
 | 
			
		||||
        Self{
 | 
			
		||||
            date: day.to_owned(),
 | 
			
		||||
            ids: Vec::new(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn add_id(&mut self, id: TellyID){
 | 
			
		||||
        if self.ids.contains(&id) {
 | 
			
		||||
            return
 | 
			
		||||
        } 
 | 
			
		||||
        self.ids.push(id);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn get_day_str() -> String {
 | 
			
		||||
    let now = chrono::offset::Local::now();
 | 
			
		||||
    now.format("%Y-%m-%d").to_string()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										19
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								src/main.rs
									
									
									
									
									
								
							@ -1,9 +1,10 @@
 | 
			
		||||
use pm3::run_pm3;
 | 
			
		||||
 | 
			
		||||
mod parser;
 | 
			
		||||
mod pm3;
 | 
			
		||||
mod id_store;
 | 
			
		||||
 | 
			
		||||
fn main() {
 | 
			
		||||
    run_pm3().unwrap();
 | 
			
		||||
}
 | 
			
		||||
use pm3::run_pm3;
 | 
			
		||||
 | 
			
		||||
mod parser;
 | 
			
		||||
mod pm3;
 | 
			
		||||
mod id_store;
 | 
			
		||||
mod buzzer;
 | 
			
		||||
 | 
			
		||||
fn main() {
 | 
			
		||||
    run_pm3().unwrap();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,8 @@
 | 
			
		||||
use regex::Regex;
 | 
			
		||||
 | 
			
		||||
pub fn parse_line(line: &str) -> Option<String> {
 | 
			
		||||
    let regex = Regex::new(r"(?m)^\[\+\] UID.... (.*)$").unwrap();
 | 
			
		||||
    let result = regex.captures(line);
 | 
			
		||||
 | 
			
		||||
    result.map(|c| c.get(1).unwrap().as_str().to_owned())
 | 
			
		||||
}
 | 
			
		||||
use regex::Regex;
 | 
			
		||||
 | 
			
		||||
pub fn parse_line(line: &str) -> Option<String> {
 | 
			
		||||
    let regex = Regex::new(r"(?m)^\[\+\] UID.... (.*)$").unwrap();
 | 
			
		||||
    let result = regex.captures(line);
 | 
			
		||||
 | 
			
		||||
    result.map(|c| c.get(1).unwrap().as_str().to_owned())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										76
									
								
								src/pm3.rs
									
									
									
									
									
								
							
							
						
						
									
										76
									
								
								src/pm3.rs
									
									
									
									
									
								
							@ -1,38 +1,38 @@
 | 
			
		||||
use std::error::Error;
 | 
			
		||||
use std::process::{Command, Stdio};
 | 
			
		||||
use std::io::{self, BufRead};
 | 
			
		||||
 | 
			
		||||
pub fn run_pm3() -> Result<(), Box<dyn Error>> {
 | 
			
		||||
    let mut cmd = Command::new("stdbuf")
 | 
			
		||||
        .arg("-oL")
 | 
			
		||||
        .arg("pm3")
 | 
			
		||||
        .arg("-c")
 | 
			
		||||
        .arg("lf hitag reader -@")
 | 
			
		||||
        .stdout(Stdio::piped())
 | 
			
		||||
        .spawn()?;
 | 
			
		||||
 | 
			
		||||
    let stdout = cmd.stdout.take().ok_or("Failed to get stdout")?;
 | 
			
		||||
    let reader = io::BufReader::new(stdout);
 | 
			
		||||
 | 
			
		||||
    for line_result in reader.lines() {
 | 
			
		||||
        match line_result {
 | 
			
		||||
            Ok(line) => {
 | 
			
		||||
                let parse_result = super::parser::parse_line(&line);
 | 
			
		||||
                if let Some(uid) = parse_result {
 | 
			
		||||
                    println!("UID: {}",uid);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            Err(e) => {
 | 
			
		||||
                eprintln!("{}",e);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let status = cmd.wait().expect("Failed to wait on child");
 | 
			
		||||
 | 
			
		||||
    if status.success() {
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }else {
 | 
			
		||||
        Err("pm3 had non zero exit code".into())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
use std::error::Error;
 | 
			
		||||
use std::process::{Command, Stdio};
 | 
			
		||||
use std::io::{self, BufRead};
 | 
			
		||||
 | 
			
		||||
pub fn run_pm3() -> Result<(), Box<dyn Error>> {
 | 
			
		||||
    let mut cmd = Command::new("stdbuf")
 | 
			
		||||
        .arg("-oL")
 | 
			
		||||
        .arg("pm3")
 | 
			
		||||
        .arg("-c")
 | 
			
		||||
        .arg("lf hitag reader -@")
 | 
			
		||||
        .stdout(Stdio::piped())
 | 
			
		||||
        .spawn()?;
 | 
			
		||||
 | 
			
		||||
    let stdout = cmd.stdout.take().ok_or("Failed to get stdout")?;
 | 
			
		||||
    let reader = io::BufReader::new(stdout);
 | 
			
		||||
 | 
			
		||||
    for line_result in reader.lines() {
 | 
			
		||||
        match line_result {
 | 
			
		||||
            Ok(line) => {
 | 
			
		||||
                let parse_result = super::parser::parse_line(&line);
 | 
			
		||||
                if let Some(uid) = parse_result {
 | 
			
		||||
                    println!("UID: {}",uid);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            Err(e) => {
 | 
			
		||||
                eprintln!("{}",e);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let status = cmd.wait().expect("Failed to wait on child");
 | 
			
		||||
 | 
			
		||||
    if status.success() {
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }else {
 | 
			
		||||
        Err("pm3 had non zero exit code".into())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user