mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-26 10:21:52 +00:00
add lifeline
This commit is contained in:
2
lifeline/.gitignore
vendored
Normal file
2
lifeline/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/target
|
||||
**/*.rs.bk
|
||||
6
lifeline/Cargo.lock
generated
Normal file
6
lifeline/Cargo.lock
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "lifeline"
|
||||
version = "0.1.0"
|
||||
|
||||
9
lifeline/Cargo.toml
Normal file
9
lifeline/Cargo.toml
Normal file
@@ -0,0 +1,9 @@
|
||||
[package]
|
||||
name = "lifeline"
|
||||
version = "0.1.0"
|
||||
authors = ["Keagan McClelland <keagan.mcclelland@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
10
lifeline/lifeline.service
Normal file
10
lifeline/lifeline.service
Normal file
@@ -0,0 +1,10 @@
|
||||
[Unit]
|
||||
Description=Boot process for system reset.
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/local/bin/lifeline
|
||||
RemainAfterExit=true
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
1
lifeline/rustfmt.toml
Normal file
1
lifeline/rustfmt.toml
Normal file
@@ -0,0 +1 @@
|
||||
max_width = 120
|
||||
14
lifeline/src/main.rs
Normal file
14
lifeline/src/main.rs
Normal file
@@ -0,0 +1,14 @@
|
||||
use std::time::Duration;
|
||||
|
||||
mod sound;
|
||||
|
||||
use sound::{notes::*, Song};
|
||||
|
||||
const SUCCESS_SONG: Song = Song(&[(Some(A_4), Duration::from_millis(100))]);
|
||||
|
||||
fn main() {
|
||||
std::fs::write("/sys/class/pwm/pwmchip0/export", "0").unwrap();
|
||||
let res = SUCCESS_SONG.play();
|
||||
std::fs::write("/sys/class/pwm/pwmchip0/unexport", "0").unwrap();
|
||||
res.unwrap();
|
||||
}
|
||||
93
lifeline/src/sound.rs
Normal file
93
lifeline/src/sound.rs
Normal file
@@ -0,0 +1,93 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::io::Error;
|
||||
use std::time::Duration;
|
||||
|
||||
pub mod notes {
|
||||
pub const A_4: f64 = 440.0;
|
||||
pub const B_4: f64 = 493.88;
|
||||
pub const C_5: f64 = 523.25;
|
||||
pub const D_5: f64 = 587.33;
|
||||
pub const E_5: f64 = 659.25;
|
||||
pub const F_5: f64 = 698.46;
|
||||
pub const G_5: f64 = 783.99;
|
||||
pub const A_5: f64 = 880.00;
|
||||
pub const B_5: f64 = 987.77;
|
||||
pub const E_6: f64 = 1318.51;
|
||||
}
|
||||
|
||||
pub fn freq_to_period(freq: f64) -> Duration {
|
||||
Duration::from_secs(1).div_f64(freq)
|
||||
}
|
||||
|
||||
pub fn play(freq: f64) -> Result<(), Error> {
|
||||
// set freq
|
||||
let period = freq_to_period(freq);
|
||||
let period_bytes = std::fs::read("/sys/class/pwm/pwmchip0/pwm0/period")?;
|
||||
if period_bytes == b"0\n" {
|
||||
std::fs::write("/sys/class/pwm/pwmchip0/pwm0/period", format!("{}", 1000))?;
|
||||
}
|
||||
std::fs::write("/sys/class/pwm/pwmchip0/pwm0/duty_cycle", "0")?;
|
||||
std::fs::write("/sys/class/pwm/pwmchip0/pwm0/period", format!("{}", period.as_nanos()))?;
|
||||
std::fs::write(
|
||||
"/sys/class/pwm/pwmchip0/pwm0/duty_cycle",
|
||||
format!("{}", (period / 2).as_nanos()),
|
||||
)?;
|
||||
// enable the thing
|
||||
std::fs::write("/sys/class/pwm/pwmchip0/pwm0/enable", "1")?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn stop() -> Result<(), Error> {
|
||||
// disable the thing
|
||||
std::fs::write("/sys/class/pwm/pwmchip0/pwm0/enable", "0")?;
|
||||
// sleep small amount
|
||||
std::thread::sleep(Duration::from_micros(30));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn play_for_duration(freq: f64, duration: Duration) -> Result<(), Error> {
|
||||
play(freq)?;
|
||||
std::thread::sleep(duration);
|
||||
stop()
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Song<'a>(pub &'a [(Option<f64>, Duration)]);
|
||||
impl<'a> Song<'a> {
|
||||
pub fn play(&self) -> Result<(), Error> {
|
||||
for (note, duration) in self.0 {
|
||||
if let Some(note) = note {
|
||||
play_for_duration(*note, *duration)?;
|
||||
} else {
|
||||
std::thread::sleep(*duration);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Song<'static> {
|
||||
pub fn play_while<T, F: FnOnce() -> T>(&'static self, f: F) -> T {
|
||||
let run = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(true));
|
||||
let t_run = run.clone();
|
||||
let handle = std::thread::spawn(move || -> Result<(), Error> {
|
||||
while t_run.load(std::sync::atomic::Ordering::SeqCst) {
|
||||
self.play()?;
|
||||
}
|
||||
Ok(())
|
||||
});
|
||||
let res = f();
|
||||
run.store(false, std::sync::atomic::Ordering::SeqCst);
|
||||
let e = handle.join().unwrap().err();
|
||||
if let Some(e) = e {
|
||||
eprintln!("ERROR PLAYING SOUND: {}\n{:?}", e, e);
|
||||
}
|
||||
res
|
||||
}
|
||||
}
|
||||
impl<'a> From<&'a [(Option<f64>, Duration)]> for Song<'a> {
|
||||
fn from(t: &'a [(Option<f64>, Duration)]) -> Self {
|
||||
Song(t)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user