blob: 7bb1f659a92831ba3585f4e06b8fe6031d2243dc [file] [log] [blame]
// SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
// SPDX-FileCopyrightText: 2022 Linaro Ltd.
// SPDX-FileCopyrightText: 2022 Viresh Kumar <viresh.kumar@linaro.org>
use std::sync::{Arc, Mutex};
use std::time::Duration;
use gpiosim_sys::{Pull, Sim, Value as SimValue};
use libgpiod::{
chip::Chip,
line::{self, Bias, Direction, Drive, Edge, EventClock, Offset, SettingVal, Value},
request, Result,
};
pub(crate) struct TestConfig {
sim: Arc<Mutex<Sim>>,
chip: Option<Chip>,
request: Option<request::Request>,
rconfig: request::Config,
lconfig: line::Config,
lsettings: Option<line::Settings>,
}
impl TestConfig {
pub(crate) fn new(ngpio: usize) -> Result<Self> {
Ok(Self {
sim: Arc::new(Mutex::new(Sim::new(Some(ngpio), None, true)?)),
chip: None,
request: None,
rconfig: request::Config::new().unwrap(),
lconfig: line::Config::new().unwrap(),
lsettings: Some(line::Settings::new().unwrap()),
})
}
pub(crate) fn set_pull(&self, offsets: &[Offset], pulls: &[Pull]) {
for i in 0..pulls.len() {
self.sim
.lock()
.unwrap()
.set_pull(offsets[i], pulls[i])
.unwrap();
}
}
pub(crate) fn rconfig_set_consumer(&mut self, consumer: &str) {
self.rconfig.set_consumer(consumer).unwrap();
}
pub(crate) fn lconfig_val(&mut self, dir: Option<Direction>, val: Option<Value>) {
let mut settings = Vec::new();
if let Some(dir) = dir {
settings.push(SettingVal::Direction(dir));
}
if let Some(val) = val {
settings.push(SettingVal::OutputValue(val));
}
if !settings.is_empty() {
self.lsettings().set_prop(&settings).unwrap();
}
}
pub(crate) fn lconfig_bias(&mut self, dir: Direction, bias: Option<Bias>) {
let settings = vec![SettingVal::Direction(dir), SettingVal::Bias(bias)];
self.lsettings().set_prop(&settings).unwrap();
}
pub(crate) fn lconfig_clock(&mut self, clock: EventClock) {
let settings = vec![SettingVal::EventClock(clock)];
self.lsettings().set_prop(&settings).unwrap();
}
pub(crate) fn lconfig_debounce(&mut self, duration: Duration) {
let settings = vec![
SettingVal::Direction(Direction::Input),
SettingVal::DebouncePeriod(duration),
];
self.lsettings().set_prop(&settings).unwrap();
}
pub(crate) fn lconfig_drive(&mut self, dir: Direction, drive: Drive) {
let settings = vec![SettingVal::Direction(dir), SettingVal::Drive(drive)];
self.lsettings().set_prop(&settings).unwrap();
}
pub(crate) fn lconfig_edge(&mut self, dir: Option<Direction>, edge: Option<Edge>) {
let mut settings = Vec::new();
if let Some(dir) = dir {
settings.push(SettingVal::Direction(dir));
}
settings.push(SettingVal::EdgeDetection(edge));
self.lsettings().set_prop(&settings).unwrap();
}
pub(crate) fn lconfig_add_settings(&mut self, offsets: &[Offset]) {
self.lconfig
.add_line_settings(offsets, self.lsettings.take().unwrap())
.unwrap();
}
pub(crate) fn request_lines(&mut self) -> Result<()> {
let chip = Chip::open(&self.sim.lock().unwrap().dev_path())?;
self.request = Some(chip.request_lines(Some(&self.rconfig), &self.lconfig)?);
self.chip = Some(chip);
Ok(())
}
pub(crate) fn sim(&self) -> Arc<Mutex<Sim>> {
self.sim.clone()
}
pub(crate) fn sim_val(&self, offset: Offset) -> Result<SimValue> {
self.sim.lock().unwrap().val(offset)
}
pub(crate) fn chip(&self) -> &Chip {
self.chip.as_ref().unwrap()
}
pub(crate) fn lsettings(&mut self) -> &mut line::Settings {
self.lsettings.as_mut().unwrap()
}
pub(crate) fn request(&mut self) -> &mut request::Request {
self.request.as_mut().unwrap()
}
}
impl Drop for TestConfig {
fn drop(&mut self) {
// Explicit freeing is important to make sure "request" get freed
// before "sim" and "chip".
self.request = None;
}
}