This repository has been archived by the owner on Feb 15, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
817cf6a
commit 33ba6ed
Showing
4 changed files
with
158 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
/target | ||
Cargo.lock | ||
.idea/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
[package] | ||
name = "pi-gpio-readout" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
[dependencies] | ||
tracing = "0.1.36" | ||
tracing-subscriber = "0.3.15" | ||
anyhow = "1" | ||
rppal = "0.13.1" | ||
|
||
[dependencies.clap] | ||
version = "3.2.17" | ||
features = ["derive"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
use clap::{Parser, ValueEnum}; | ||
use tracing::Level; | ||
|
||
#[derive(Debug, Parser)] | ||
pub struct Args { | ||
/// Set the level of verbosity. | ||
/// When this argument is not given, the INFO level is used. | ||
/// When it is provided once, the DEBUG level is used. | ||
/// Otherwhise the TRACE level is used | ||
#[clap(short, parse(from_occurrences))] | ||
verbose: usize, | ||
/// The pin to read out. | ||
/// When this is unspecified, all of the Pi's pins will be read | ||
#[clap(long, short)] | ||
pub pin: Option<u8>, | ||
/// The input mode to use for all pins | ||
#[clap(short, long, value_enum)] | ||
pub input_mode: Option<InputMode>, | ||
/// Should the value be printed again if | ||
/// it's value is equal to the previous value from that pin. | ||
/// When unspecified, this defaults to true. | ||
#[clap(short, long)] | ||
pub reprint_if_previous_equal: Option<bool>, | ||
} | ||
|
||
#[derive(Debug, Clone, ValueEnum)] | ||
pub enum InputMode { | ||
Regular, | ||
PullUp, | ||
PullDown, | ||
} | ||
|
||
impl Args { | ||
pub fn get_tracing_level(&self) -> Level { | ||
match self.verbose { | ||
0 => Level::INFO, | ||
1 => Level::DEBUG, | ||
_ => Level::TRACE, | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
use std::collections::HashMap; | ||
use std::sync::mpsc::{Receiver, Sender}; | ||
use std::thread; | ||
use clap::Parser; | ||
use rppal::gpio::{Gpio, InputPin, Level}; | ||
use tracing::{debug, info}; | ||
use crate::args::{Args, InputMode}; | ||
use anyhow::Result; | ||
|
||
mod args; | ||
|
||
fn main() { | ||
let args = Args::parse(); | ||
configure_tracing(&args); | ||
info!("Starting {} v{}", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION")); | ||
|
||
defer_main(&args).expect("Error"); | ||
} | ||
|
||
fn defer_main(args: &Args) -> Result<()> { | ||
let input_mode = args.input_mode.as_ref().unwrap_or(&InputMode::Regular); | ||
|
||
info!("Configuring GPIO pins"); | ||
|
||
let gpio = Gpio::new()?; | ||
let mut pins = HashMap::with_capacity(28); | ||
|
||
if let Some(pin) = args.pin { | ||
pins.insert(pin, get_pin(&gpio, pin, input_mode)?); | ||
} else { | ||
// The RPI has 27 GPIO pins | ||
for i in 0..28 { | ||
pins.insert(i, get_pin(&gpio, i, input_mode)?); | ||
} | ||
} | ||
|
||
info!("Starting readout"); | ||
|
||
// We print on a different thread to avoid the IO delays caused by printing to stdout | ||
let (tx, rx): (Sender<(u8, Level)>, Receiver<_>) = std::sync::mpsc::channel(); | ||
let reprint_if_eq = args.reprint_if_previous_equal.unwrap_or(true); | ||
|
||
thread::spawn(move || { | ||
let mut prev_values: [Option<Level>; 28] = [None; 28]; | ||
|
||
loop { | ||
match rx.recv() { | ||
Ok(v) => { | ||
// If the condition evaluates to true, | ||
// we shouldn't print the value if it is equal to the previous value | ||
if !reprint_if_eq { | ||
// SAFETY: there are only 27 pins, so the idx | ||
// will never exceed 27. | ||
let prev_value = unsafe { prev_values.get_unchecked(v.0 as usize) }; | ||
|
||
// There is a previous value stored, check it for equality | ||
// to the current level. We cant combine these if's yet. | ||
// waiting on the if-let-else feature. | ||
if let Some(prev_value) = prev_value { | ||
if prev_value.eq(&v.1) { | ||
continue; | ||
} | ||
} | ||
|
||
prev_values[v.0 as usize] = Some(v.1); | ||
} | ||
|
||
info!("Pin {}: {}", v.0, v.1); | ||
}, | ||
Err(e) => debug!("Recv Error: {e}"), | ||
} | ||
} | ||
}); | ||
|
||
loop { | ||
for (idx, pin) in pins.iter_mut() { | ||
let level = pin.read(); | ||
tx.send((*idx, level)).expect("RX channel closed"); | ||
} | ||
} | ||
} | ||
|
||
fn get_pin(gpio: &Gpio, pin: u8, mode: &InputMode) -> Result<InputPin> { | ||
let pin = gpio.get(pin)?; | ||
Ok(match mode { | ||
InputMode::Regular => pin.into_input(), | ||
InputMode::PullDown => pin.into_input_pulldown(), | ||
InputMode::PullUp => pin.into_input_pullup(), | ||
}) | ||
} | ||
|
||
|
||
|
||
fn configure_tracing(args: &Args) { | ||
let sub = tracing_subscriber::fmt() | ||
.compact() | ||
.with_max_level(args.get_tracing_level()) | ||
.finish(); | ||
tracing::subscriber::set_global_default(sub).expect("Configuring global tracing subscriber"); | ||
} |