feat: implement gpio
This commit is contained in:
parent
b84d93d0b5
commit
c503a195b2
4 changed files with 183 additions and 4 deletions
7
Cargo.lock
generated
7
Cargo.lock
generated
|
@ -137,6 +137,12 @@ dependencies = [
|
|||
"minimal-lexical",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.20.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
|
||||
|
||||
[[package]]
|
||||
name = "prettyplease"
|
||||
version = "0.2.25"
|
||||
|
@ -314,5 +320,6 @@ dependencies = [
|
|||
"bindgen",
|
||||
"cc",
|
||||
"glob",
|
||||
"once_cell",
|
||||
"thiserror",
|
||||
]
|
||||
|
|
|
@ -4,6 +4,7 @@ version = "0.1.0"
|
|||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
once_cell = "1.20.2"
|
||||
thiserror = "1.0.65"
|
||||
|
||||
[build-dependencies]
|
||||
|
|
166
src/gpio.rs
166
src/gpio.rs
|
@ -2,35 +2,193 @@ use std::sync::Mutex;
|
|||
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::ffi;
|
||||
use crate::{
|
||||
ensure_library_setup,
|
||||
ffi::{self, HIGH, INPUT, LOW, OUTPUT, PUD_DOWN, PUD_OFF, PUD_UP, PWM_OUTPUT},
|
||||
};
|
||||
|
||||
static PINS_HANDED_OUT: Mutex<Vec<i32>> = Mutex::new(Vec::new());
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum GpioError {
|
||||
#[error("could not parse value {0} into type")]
|
||||
ValueParseError(i32),
|
||||
#[error("pin {0} is in mode {1:?} when it should be in mode {2:?}")]
|
||||
WrongPinModeError(i32, PinMode, PinMode),
|
||||
#[error("mode {0:?} is unsupported")]
|
||||
UnsupportedModeError(PinMode),
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum PinRetrievalError {
|
||||
#[error("pin {0} has already been retrieved")]
|
||||
AlreadyRetrieved(i32),
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Debug, Clone, Copy)]
|
||||
pub enum PinMode {
|
||||
Input,
|
||||
Output,
|
||||
PwmOutput,
|
||||
Uninitialized,
|
||||
}
|
||||
|
||||
impl TryFrom<i32> for PinMode {
|
||||
type Error = GpioError;
|
||||
|
||||
fn try_from(value: i32) -> Result<Self, Self::Error> {
|
||||
match value as u32 {
|
||||
INPUT => Ok(PinMode::Input),
|
||||
OUTPUT => Ok(PinMode::Output),
|
||||
PWM_OUTPUT => Ok(PinMode::PwmOutput),
|
||||
_ => Err(GpioError::ValueParseError(value)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PinMode> for i32 {
|
||||
fn from(value: PinMode) -> Self {
|
||||
match value {
|
||||
PinMode::Input => INPUT as i32,
|
||||
PinMode::Output => OUTPUT as i32,
|
||||
PinMode::PwmOutput => PWM_OUTPUT as i32,
|
||||
PinMode::Uninitialized => panic!("tried to make use of uninitialized pin"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Debug, Clone, Copy)]
|
||||
pub enum PullUpMode {
|
||||
Off,
|
||||
Up,
|
||||
Down,
|
||||
}
|
||||
|
||||
impl TryFrom<i32> for PullUpMode {
|
||||
type Error = GpioError;
|
||||
|
||||
fn try_from(value: i32) -> Result<Self, Self::Error> {
|
||||
match value as u32 {
|
||||
PUD_OFF => Ok(PullUpMode::Off),
|
||||
PUD_UP => Ok(PullUpMode::Up),
|
||||
PUD_DOWN => Ok(PullUpMode::Down),
|
||||
_ => Err(GpioError::ValueParseError(value)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PullUpMode> for i32 {
|
||||
fn from(value: PullUpMode) -> Self {
|
||||
match value {
|
||||
PullUpMode::Down => PUD_DOWN as i32,
|
||||
PullUpMode::Up => PUD_UP as i32,
|
||||
PullUpMode::Off => PUD_OFF as i32,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Debug, Clone, Copy)]
|
||||
pub enum PinState {
|
||||
Low,
|
||||
High,
|
||||
}
|
||||
|
||||
impl TryFrom<i32> for PinState {
|
||||
type Error = GpioError;
|
||||
|
||||
fn try_from(value: i32) -> Result<Self, Self::Error> {
|
||||
match value as u32 {
|
||||
HIGH => Ok(PinState::High),
|
||||
LOW => Ok(PinState::Low),
|
||||
_ => Err(GpioError::ValueParseError(value)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PinState> for i32 {
|
||||
fn from(value: PinState) -> Self {
|
||||
match value {
|
||||
PinState::Low => LOW as i32,
|
||||
PinState::High => HIGH as i32,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Pin {
|
||||
pin_id: i32,
|
||||
pin_mode: PinMode,
|
||||
}
|
||||
|
||||
impl Pin {
|
||||
pub fn new(pin_id: i32) -> Result<Self, PinRetrievalError> {
|
||||
ensure_library_setup!();
|
||||
|
||||
let can_retrieve = !PINS_HANDED_OUT
|
||||
.lock()
|
||||
.expect("failed to obtain pin list lock")
|
||||
.contains(&pin_id);
|
||||
|
||||
if can_retrieve {
|
||||
Ok(Self { pin_id })
|
||||
Ok(Self {
|
||||
pin_id,
|
||||
pin_mode: PinMode::Uninitialized,
|
||||
})
|
||||
} else {
|
||||
Err(PinRetrievalError::AlreadyRetrieved(pin_id))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_gpio_mode(&mut self) -> i32 {
|
||||
unsafe { ffi::orangepi_get_gpio_mode(self.pin_id) }
|
||||
fn ensure_pin_mode(&mut self, mode: PinMode) -> Result<(), GpioError> {
|
||||
if self.pin_mode != mode {
|
||||
Err(GpioError::WrongPinModeError(
|
||||
self.pin_id,
|
||||
self.pin_mode,
|
||||
mode,
|
||||
))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_gpio_mode(&mut self) -> Result<PinMode, GpioError> {
|
||||
ensure_library_setup!();
|
||||
|
||||
unsafe { ffi::orangepi_get_gpio_mode(self.pin_id).try_into() }
|
||||
}
|
||||
|
||||
pub fn set_gpio_mode(&mut self, mode: PinMode) -> Result<(), GpioError> {
|
||||
ensure_library_setup!();
|
||||
|
||||
if mode == PinMode::PwmOutput || mode == PinMode::Uninitialized {
|
||||
return Err(GpioError::UnsupportedModeError(mode));
|
||||
}
|
||||
|
||||
unsafe {
|
||||
ffi::pinMode(self.pin_id, mode.into());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn digital_read(&mut self) -> Result<PinState, GpioError> {
|
||||
ensure_library_setup!();
|
||||
|
||||
self.ensure_pin_mode(PinMode::Input)?;
|
||||
|
||||
unsafe { ffi::orangepi_digitalRead(self.pin_id).try_into() }
|
||||
}
|
||||
|
||||
pub fn digital_write(&mut self, value: PinState) -> Result<bool, GpioError> {
|
||||
ensure_library_setup!();
|
||||
|
||||
self.ensure_pin_mode(PinMode::Output)?;
|
||||
|
||||
unsafe { Ok(ffi::orangepi_digitalWrite(self.pin_id, value.into()) == 0) }
|
||||
}
|
||||
|
||||
pub fn pull_up_down_control(&mut self, mode: PullUpMode) {
|
||||
ensure_library_setup!();
|
||||
|
||||
unsafe { ffi::pullUpDnControl(self.pin_id, mode.into()) }
|
||||
}
|
||||
}
|
||||
|
|
13
src/lib.rs
13
src/lib.rs
|
@ -1,2 +1,15 @@
|
|||
use once_cell::sync::Lazy;
|
||||
|
||||
mod ffi;
|
||||
pub mod gpio;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! ensure_library_setup {
|
||||
() => {
|
||||
if !*$crate::LIBRARY_SETUP_COMPLETE {
|
||||
panic!("wiringOP library failed to set up");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static LIBRARY_SETUP_COMPLETE: Lazy<bool> = Lazy::new(|| unsafe { ffi::wiringPiSetupGpio() == 0 });
|
||||
|
|
Loading…
Reference in a new issue