use crate::errors::RpWebError;
use crate::settings::GpioConfig;
pub fn vec_option_to_vec(option: &Option<Vec<i32>>) -> Vec<i32> {
match option {
Some(vec) => vec.to_vec(),
None => vec![],
}
}
fn elements_in_both_vecs(u: &Vec<i32>, v: &Vec<i32>) -> Option<Vec<i32>> {
let mut res = vec![];
for &idx in u.iter() {
if v.contains(&idx) {
res.push(idx);
}
}
if !res.is_empty() {
return Some(res);
} else {
return None;
}
}
pub fn validate_setup(gpioconfig: &GpioConfig) -> Result<(), RpWebError> {
let gpios_in_use = vec_option_to_vec(&gpioconfig.gpios_in_use);
let gpios_mode_output = vec_option_to_vec(&gpioconfig.gpios_mode_output);
let gpios_mode_input = vec_option_to_vec(&gpioconfig.gpios_mode_input);
let gpios_level_low = vec_option_to_vec(&gpioconfig.gpios_level_low);
let gpios_level_high = vec_option_to_vec(&gpioconfig.gpios_level_high);
let mut gpio_all_levels: Vec<i32> = vec![];
gpio_all_levels.append(&mut gpios_level_low.to_vec());
gpio_all_levels.append(&mut gpios_level_high.to_vec());
if gpios_in_use.is_empty() {
if !gpio_all_levels.is_empty() {
return Err(RpWebError::new(
"Invalid configuration: gpio_levels_* is set, but gpios_in_use is empty",
));
}
}
if gpios_mode_output.is_empty() {
if !gpio_all_levels.is_empty() {
return Err(RpWebError::new(
"Invalid configuration: gpios_level_* is set, but gpios_mode_output is empty",
));
}
}
for idx in gpio_all_levels.iter() {
if !gpios_in_use.contains(idx) {
let errs = format!(
"Invalid configuration: GPIO #{} is not in_use, but a level is set for it",
idx
);
return Err(RpWebError::new(&errs));
}
if !gpios_mode_output.contains(idx) {
let errs = format!(
"Invalid configuration: GPIO #{} is not configured to OUTPUT, but a level is set for it", idx);
return Err(RpWebError::new(&errs));
}
}
let both_high_and_low_option = elements_in_both_vecs(&gpios_level_low, &gpios_level_high);
if let Some(high_and_low) = both_high_and_low_option {
let errs = format!(
"Invalid configuration: GPIO(s) {:?} in both gpios_level_low and gpios_level_high",
high_and_low
);
return Err(RpWebError::new(&errs));
}
let both_input_and_output_option = elements_in_both_vecs(&gpios_mode_input, &gpios_mode_output);
if let Some(input_and_output) = both_input_and_output_option {
let errs = format!(
"Invalid configuration: GPIO(s) {:?} in both gpios_mode_input and gpios_mode_output",
input_and_output
);
return Err(RpWebError::new(&errs));
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn validation_in_use_none_but_level_set_must_fail() {
let gpioconfig = GpioConfig {
gpios_in_use: None,
gpios_mode_output: Some(vec![1]),
gpios_mode_input: None,
gpios_level_low: Some(vec![1]),
gpios_level_high: None,
};
let res = validate_setup(&gpioconfig);
assert!(res.is_err());
}
#[test]
fn validation_in_use_not_set_but_level_set_must_fail() {
let gpioconfig = GpioConfig {
gpios_in_use: Some(vec![2]),
gpios_mode_output: Some(vec![2]),
gpios_mode_input: None,
gpios_level_low: Some(vec![1]),
gpios_level_high: None,
};
let res = validate_setup(&gpioconfig);
assert!(res.is_err());
}
#[test]
fn validation_mode_output_none_but_level_set_must_fail() {
let gpioconfig = GpioConfig {
gpios_in_use: Some(vec![1]),
gpios_mode_output: None,
gpios_mode_input: None,
gpios_level_low: Some(vec![1]),
gpios_level_high: None,
};
let res = validate_setup(&gpioconfig);
assert!(res.is_err());
}
#[test]
fn validation_mode_output_not_set_but_level_set_must_fail() {
let gpioconfig = GpioConfig {
gpios_in_use: Some(vec![1]),
gpios_mode_output: Some(vec![2]),
gpios_mode_input: None,
gpios_level_low: Some(vec![1]),
gpios_level_high: None,
};
let res = validate_setup(&gpioconfig);
assert!(res.is_err());
}
#[test]
fn validation_in_use_not_set_for_pin_level_set_must_fail() {
let gpioconfig = GpioConfig {
gpios_in_use: Some(vec![1, 2]),
gpios_mode_output: Some(vec![1, 2, 3]),
gpios_mode_input: None,
gpios_level_low: Some(vec![3]),
gpios_level_high: None,
};
let res = validate_setup(&gpioconfig);
assert!(res.is_err());
}
#[test]
fn validation_mode_output_not_set_for_pin_level_high_set_must_fail() {
let gpioconfig = GpioConfig {
gpios_in_use: Some(vec![1, 2, 3]),
gpios_mode_output: Some(vec![1, 2]),
gpios_mode_input: None,
gpios_level_low: Some(vec![3]),
gpios_level_high: None,
};
let res = validate_setup(&gpioconfig);
assert!(res.is_err());
}
#[test]
fn validation_same_pin_high_and_low_must_fail() {
let gpioconfig = GpioConfig {
gpios_in_use: Some(vec![1, 2]),
gpios_mode_output: Some(vec![1, 2]),
gpios_mode_input: None,
gpios_level_low: Some(vec![1]),
gpios_level_high: Some(vec![1]),
};
let res = validate_setup(&gpioconfig);
assert!(res.is_err());
}
#[test]
fn validation_same_pin_input_and_output_must_fail() {
let gpioconfig = GpioConfig {
gpios_in_use: Some(vec![1]),
gpios_mode_output: Some(vec![1]),
gpios_mode_input: Some(vec![1]),
gpios_level_low: None,
gpios_level_high: None,
};
let res = validate_setup(&gpioconfig);
assert!(res.is_err());
}
#[test]
fn validation_valid_setup_must_succeed() {
let gpioconfig = GpioConfig {
gpios_in_use: Some(vec![1, 2, 3]),
gpios_mode_output: Some(vec![1, 2, 3]),
gpios_mode_input: None,
gpios_level_low: Some(vec![1]),
gpios_level_high: Some(vec![2, 3]),
};
let res = validate_setup(&gpioconfig);
assert!(res.is_ok());
}
}