diff --git a/.gitignore b/.gitignore index f805e81..958a081 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,6 @@ # Debug files *.dSYM/ *.su + +# Rust +target/ diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index fae1209..9ff9204 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,8 +1,18 @@ -# image: scorpil/rust:stable +image: scorpil/rust:stable stages: - test +cargo:test: + stage: test + script: + - ci/run-cargo-test.sh + +rustfmt: + stage: test + script: + - ci/run-rustfmt.sh + shellcheck: stage: test image: ubuntu:yakkety @@ -13,4 +23,4 @@ shellcheck: - export LANGUAGE=en_US:en - export LC_ALL=en_US.UTF-8 script: - - find . -type f -name '*.sh' -print0 | xargs -n 1 -0 shellcheck --color + - ci/run-shellcheck.sh diff --git a/V1/led5/Cargo.lock b/V1/led5/Cargo.lock new file mode 100644 index 0000000..152edd2 --- /dev/null +++ b/V1/led5/Cargo.lock @@ -0,0 +1,66 @@ +[root] +name = "led5" +version = "0.1.0" +dependencies = [ + "chan 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)", + "chan-signal 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "bit-set" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bit-vec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "bit-vec" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "chan" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "chan-signal" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "chan 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "lazy_static" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "libc" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rand" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[metadata] +"checksum bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9bf6104718e80d7b26a68fdbacff3481cfc05df670821affc7e9cbc1884400c" +"checksum bit-vec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "5b97c2c8e8bbb4251754f559df8af22fb264853c7d009084a576cdf12565089d" +"checksum chan 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)" = "f93bfe971116428a9066c1c3c69a09ae3ef69432f8418be28ab50f96783e6a50" +"checksum chan-signal 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0f3bb6c3bc387004ad914f0c5b7f33ace8bf7604bbec35f228b1a017f52cd3a0" +"checksum lazy_static 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "4732c563b9a21a406565c4747daa7b46742f082911ae4753f390dc9ec7ee1a97" +"checksum libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "88ee81885f9f04bff991e306fea7c1c60a5f0f9e409e99f6b40e3311a3363135" +"checksum rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "022e0636ec2519ddae48154b028864bdce4eaf7d35226ab8e65c611be97b189d" diff --git a/V1/led5/Cargo.toml b/V1/led5/Cargo.toml new file mode 100644 index 0000000..345cf6b --- /dev/null +++ b/V1/led5/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "led5" +version = "0.1.0" +authors = ["Simon Wörner "] + +[dependencies] +chan = ">=0.1.19" +chan-signal = ">=0.2.0" diff --git a/V1/led5/src/main.rs b/V1/led5/src/main.rs new file mode 100644 index 0000000..36aee08 --- /dev/null +++ b/V1/led5/src/main.rs @@ -0,0 +1,152 @@ +#[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 btn_tick = chan::tick(Duration::from_millis(50)); + let led_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! { + btn_tick.recv() => { + //#[cfg(debug_assertions)] + //println!("btn_tick"); + + // switch enabled if button state changed + let btn = get_value(GPIO_PORT_BTN) == GPIO_BTN_ON; + if btn && btn != btn_last { + enabled = !enabled; + } + + btn_last = btn; + }, + led_tick.recv() => { + #[cfg(debug_assertions)] + println!("led_tick"); + + // blink led if enabled + if enabled { + led_on = !led_on; + } else { + led_on = false; + } + + // set led state + if led_on { + set_value(GPIO_PORT_LED, GPIO_LED_ON); + } + else { + set_value(GPIO_PORT_LED, GPIO_LED_OFF); + } + }, + rdone.recv() => { + // unexport + unexport(GPIO_PORT_BTN); + unexport(GPIO_PORT_LED); + return; + }, + } + } +} diff --git a/ci/run-cargo-test.sh b/ci/run-cargo-test.sh new file mode 100755 index 0000000..bc151bb --- /dev/null +++ b/ci/run-cargo-test.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +ERROR=0 + +while IFS= read -r -d '' f; do + dir="$(dirname "${f}")" + + echo "run 'cargo test' in ${dir}" + cd "${dir}" && cargo test + + if [[ $? -ne 0 ]]; then + ERROR=1 + fi +done < <(find . -type f -name 'Cargo.toml' -print0) + +exit ${ERROR} diff --git a/ci/run-rustfmt.sh b/ci/run-rustfmt.sh new file mode 100755 index 0000000..37403d1 --- /dev/null +++ b/ci/run-rustfmt.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +ERROR=0 + +while IFS= read -r -d '' f; do + echo "${f}" + + if [ "$(rustfmt --write-mode=diff "$f")" != $'' ] ; then + ERROR=1 + fi +done < <(find . -type f -name '*.rs' -print0) + +exit ${ERROR} diff --git a/ci/run-shellcheck.sh b/ci/run-shellcheck.sh new file mode 100755 index 0000000..4a2de49 --- /dev/null +++ b/ci/run-shellcheck.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +find . -type f -name '*.sh' -print0 | xargs -n 1 -0 shellcheck --color