142 lines
3.9 KiB
Rust
142 lines
3.9 KiB
Rust
#[macro_use]
|
|
extern crate chan;
|
|
extern crate chan_signal;
|
|
|
|
use std::io::prelude::*;
|
|
use std::fs::File;
|
|
use std::thread;
|
|
use std::thread::JoinHandle;
|
|
use std::path::Path;
|
|
use std::time::Duration;
|
|
|
|
use chan_signal::Signal;
|
|
|
|
static GPIO_PORT_BTN: &'static str = "17";
|
|
static GPIO_PORT_LED: &'static str = "18";
|
|
|
|
static GPIO_DIRECTION_IN: &'static str = "in";
|
|
static GPIO_DIRECTION_OUT: &'static str = "out";
|
|
|
|
static GPIO_BTN_ON: &'static str = "0";
|
|
//static GPIO_BTN_OFF: &'static str = "1";
|
|
|
|
static GPIO_LED_ON: &'static str = "0";
|
|
static GPIO_LED_OFF: &'static str = "1";
|
|
|
|
fn write(path: &str, value: &str) {
|
|
let mut file = File::create(Path::new(path))
|
|
.expect(format!("Open file '{}' failed", path).as_str());
|
|
|
|
file.write_all(value.as_bytes())
|
|
.expect(format!("Write value '{}' to '{}' file failed", value, path).as_str());
|
|
|
|
#[cfg(debug_assertions)]
|
|
println!("Wrote value '{}' to '{}'.", value, path);
|
|
}
|
|
fn read(path: &str) -> String {
|
|
let mut file = File::open(Path::new(path))
|
|
.expect(format!("Open file '{}' failed", path).as_str());
|
|
let mut contents = String::new();
|
|
|
|
file.read_to_string(&mut contents)
|
|
.expect(format!("Read from '{}' file failed", path).as_str());
|
|
|
|
#[cfg(debug_assertions)]
|
|
println!("Read value '{}' from '{}'.", contents, path);
|
|
|
|
contents
|
|
}
|
|
|
|
fn export(port: &str) {
|
|
write("/sys/class/gpio/export", port)
|
|
}
|
|
fn unexport(port: &str) {
|
|
write("/sys/class/gpio/unexport", port)
|
|
}
|
|
|
|
fn set_direction(port: &str, direction: &str) {
|
|
write(format!("/sys/class/gpio/gpio{}/direction", port).as_str(), direction);
|
|
}
|
|
|
|
fn set_value(port: &str, value: &str) {
|
|
write(format!("/sys/class/gpio/gpio{}/value", port).as_str(), value);
|
|
}
|
|
fn get_value(port: &str) -> String {
|
|
String::from(read(format!("/sys/class/gpio/gpio{}/value", port).as_str()).trim())
|
|
}
|
|
|
|
fn main() {
|
|
let signal = chan_signal::notify(&[Signal::INT, Signal::TERM]);
|
|
let (sdone, rdone) = chan::sync(0);
|
|
let (spanic, rpanic) = chan::sync(0);
|
|
let worker = thread::Builder::new()
|
|
.name("worker".to_string())
|
|
.spawn(move || run(rdone))
|
|
.expect("Create worker thread failed");
|
|
let watchdog = thread::Builder::new()
|
|
.name("watchdog".to_string())
|
|
.spawn(move || watchdog(worker, spanic))
|
|
.expect("Create watchdog thread failed");
|
|
|
|
chan_select! {
|
|
rpanic.recv() => { },
|
|
signal.recv() -> signal => {
|
|
#[cfg(debug_assertions)]
|
|
println!("received signal: {:?}", signal);
|
|
|
|
sdone.send(());
|
|
}
|
|
}
|
|
|
|
watchdog.join().expect("Watchdog thread paniced");
|
|
}
|
|
|
|
fn watchdog(thread: JoinHandle<()>, _spanic: chan::Sender<()>) {
|
|
thread.join().expect("Thread paniced");
|
|
}
|
|
|
|
fn run(rdone: chan::Receiver<()>) {
|
|
// init
|
|
export(GPIO_PORT_BTN);
|
|
export(GPIO_PORT_LED);
|
|
set_direction(GPIO_PORT_BTN, GPIO_DIRECTION_IN);
|
|
set_direction(GPIO_PORT_LED, GPIO_DIRECTION_OUT);
|
|
|
|
let tick = chan::tick(Duration::from_millis(1000 / 5));
|
|
let mut btn_last = false;
|
|
let mut led_on = false;
|
|
let mut enabled = true;
|
|
|
|
loop {
|
|
chan_select! {
|
|
tick.recv() => {
|
|
#[cfg(debug_assertions)]
|
|
println!("tick");
|
|
|
|
// switch enabled if button state changed
|
|
let btn = get_value(GPIO_PORT_BTN) == GPIO_BTN_ON;
|
|
if btn && btn != btn_last {
|
|
enabled = !enabled;
|
|
}
|
|
|
|
// set led state
|
|
if led_on {
|
|
set_value(GPIO_PORT_LED, GPIO_LED_ON);
|
|
}
|
|
else {
|
|
set_value(GPIO_PORT_LED, GPIO_LED_OFF);
|
|
}
|
|
|
|
btn_last = btn;
|
|
led_on = !led_on;
|
|
},
|
|
rdone.recv() => {
|
|
// unexport
|
|
unexport(GPIO_PORT_BTN);
|
|
unexport(GPIO_PORT_LED);
|
|
return;
|
|
},
|
|
}
|
|
}
|
|
}
|