raspberry-web 0.1.3

Web server for controlling GPIO pins on the Raspberry Pi
Documentation
use crate::errors::RpWebError;
use crate::utilities::i32_to_u8;
use parking_lot::Mutex;
#[cfg(target_arch = "arm")]
use rppal::gpio::Gpio;
use std::sync::Arc;

#[cfg(not(target_arch = "arm"))]
pub type GpioArcMutex = Arc<Mutex<i32>>;

#[cfg(target_arch = "arm")]
pub type GpioArcMutex = Arc<Mutex<Gpio>>;

#[cfg(not(target_arch = "arm"))]
pub fn create_gpio_arc_mutex() -> Result<GpioArcMutex, String> {
    Ok(Arc::new(Mutex::new(0)))
}

#[cfg(target_arch = "arm")]
pub fn create_gpio_arc_mutex() -> Result<GpioArcMutex, RpWebError> {
    let gpio = Gpio::new()?;
    Ok(Arc::new(Mutex::new(gpio)))
}

#[cfg(not(target_arch = "arm"))]
pub fn set_gpio_level_rpi(
    gpio_id: i32, level: &str, gpio_arc_mutex: GpioArcMutex,
) -> Result<(), RpWebError> {
    let _gpio_id_u8 = i32_to_u8(gpio_id)?;
    let mut data = gpio_arc_mutex.lock();
    match level {
        "high" => *data += 1,
        "low" => *data += 1,
        _ => {
            let errs = format!("Invalid level: '{}'", level);
            return Err(RpWebError::new(&errs));
        }
    }
    Ok(())
}

#[cfg(not(target_arch = "arm"))]
pub fn reset_gpio_output_pin_rpi(
    _gpio_id: i32, _gpio_arc_mutex: GpioArcMutex
) -> Result<(), RpWebError> {
    Ok(())
}

#[cfg(target_arch = "arm")]
pub fn reset_gpio_output_pin_rpi(
    gpio_id: i32, gpio_arc_mutex: GpioArcMutex
) -> Result<(), RpWebError> {

    let data = gpio_arc_mutex.lock();
    let gpio_id_u8 = i32_to_u8(gpio_id)?;
    let mut output_pin = (*data).get(gpio_id_u8)?.into_output();
    output_pin.set_reset_on_drop(true);

    Ok(())
}

#[cfg(not(target_arch = "arm"))]
pub fn set_reset_on_drop_false_for_output_pin_rpi(
    _gpio_id: i32, _gpio_arc_mutex: GpioArcMutex
) -> Result<(), RpWebError> {
    Ok(())
}

#[cfg(target_arch = "arm")]
pub fn set_reset_on_drop_false_for_output_pin_rpi(
    gpio_id: i32, gpio_arc_mutex: GpioArcMutex
) -> Result<(), RpWebError> {

    let data = gpio_arc_mutex.lock();
    let gpio_id_u8 = i32_to_u8(gpio_id)?;
    let mut output_pin = (*data).get(gpio_id_u8)?.into_output();
    output_pin.set_reset_on_drop(false);

    Ok(())
}

//#[allow(unused_mut)] // output_pin needs mut but generates a warning
#[cfg(target_arch = "arm")]
pub fn set_gpio_level_rpi(
    gpio_id: i32, level: &str, gpio_arc_mutex: GpioArcMutex,
) -> Result<(), RpWebError> {
    let gpio_id_u8 = i32_to_u8(gpio_id)?;
    let data = gpio_arc_mutex.lock();

    let mut output_pin = (*data).get(gpio_id_u8)?.into_output();

    match level {
        "high" => {
            info!("Set gpio #{} to 'high'", gpio_id_u8);
            output_pin.set_high()
        }
        "low" => {
            info!("Set gpio #{} to 'low'", gpio_id_u8);
            output_pin.set_low()
        }
        _ => {
            let errs = format!("Invalid level: '{}'", level);
            return Err(RpWebError::new(&errs));
        }
    }

    Ok(())
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn set_gpio_level_rpi_high_must_succeed() {
        let gpio_arc_mutex = create_gpio_arc_mutex().expect("Could not acquire GPIO");
        let res = set_gpio_level_rpi(1, "high", gpio_arc_mutex);

        assert!(res.is_ok());
    }

    #[test]
    fn set_gpio_level_rpi_low_must_succeed() {
        let gpio_arc_mutex = create_gpio_arc_mutex().expect("Could not acquire GPIO");
        let res = set_gpio_level_rpi(1, "low", gpio_arc_mutex);

        assert!(res.is_ok());
    }

    #[test]
    fn set_gpio_level_rpi_unknown_must_fail() {
        let gpio_arc_mutex = create_gpio_arc_mutex().expect("Could not acquire GPIO");
        let res = set_gpio_level_rpi(1, "unknown_level", gpio_arc_mutex);

        assert!(res.is_err());
    }
}