use parking_lot::{Mutex, MutexGuard};
use crate::{ChannelValue, Error, Result};
#[cfg(feature = "nv200")]
pub const MAX_CHANNELS: usize = 24;
#[cfg(not(feature = "nv200"))]
pub const MAX_CHANNELS: usize = 16;
pub const CHANNEL_TIMEOUT_MS: u128 = 2_500;
pub const CHANNEL_TIMEOUT_ATTEMPTS: u64 = 10_000;
pub type Channels = [ChannelValue; MAX_CHANNELS];
pub static CHANNELS: Mutex<Channels> = Mutex::new([
ChannelValue::from_inner(0),
ChannelValue::from_inner(0),
ChannelValue::from_inner(0),
ChannelValue::from_inner(0),
ChannelValue::from_inner(0),
ChannelValue::from_inner(0),
ChannelValue::from_inner(0),
ChannelValue::from_inner(0),
ChannelValue::from_inner(0),
ChannelValue::from_inner(0),
ChannelValue::from_inner(0),
ChannelValue::from_inner(0),
ChannelValue::from_inner(0),
ChannelValue::from_inner(0),
ChannelValue::from_inner(0),
ChannelValue::from_inner(0),
ChannelValue::from_inner(0),
#[cfg(feature = "nv200")]
ChannelValue::from_inner(0),
#[cfg(feature = "nv200")]
ChannelValue::from_inner(0),
#[cfg(feature = "nv200")]
ChannelValue::from_inner(0),
#[cfg(feature = "nv200")]
ChannelValue::from_inner(0),
#[cfg(feature = "nv200")]
ChannelValue::from_inner(0),
#[cfg(feature = "nv200")]
ChannelValue::from_inner(0),
#[cfg(feature = "nv200")]
ChannelValue::from_inner(0),
]);
#[cfg(feature = "std")]
pub fn lock_channels() -> Result<MutexGuard<'static, Channels>> {
use crate::std::time;
let now = time::Instant::now();
while now.elapsed().as_millis() < CHANNEL_TIMEOUT_MS {
if let Some(chan_lock) = CHANNELS.try_lock() {
return Ok(chan_lock);
}
}
Err(Error::Timeout("channels lock".into()))
}
#[cfg(not(feature = "std"))]
pub fn lock_channels() -> Result<MutexGuard<'static, Channels>> {
let mut attempts = 0;
while attempts < CHANNEL_TIMEOUT_ATTEMPTS {
if let Some(chan_lock) = CHANNELS.try_lock() {
return Ok(chan_lock);
}
attempts += 1;
}
Err(Error::Timeout("channels lock".into()))
}
pub fn channels<'a>(chan_lock: &'a MutexGuard<'static, Channels>) -> Result<&'a [ChannelValue]> {
let idx = chan_lock
.iter()
.position(|p| p.as_inner() == 0)
.unwrap_or(0);
Ok(chan_lock[..idx].as_ref())
}
pub fn channels_mut<'a>(
chan_lock: &'a mut MutexGuard<'static, Channels>,
) -> Result<&'a mut [ChannelValue]> {
let idx = chan_lock
.iter_mut()
.position(|p| p.as_inner() == 0)
.unwrap_or(0);
Ok(chan_lock[..idx].as_mut())
}
pub fn configure_channels(channels: &[ChannelValue]) -> Result<()> {
let mut chan_lock = lock_channels()?;
configure_channels_with_lock(&mut chan_lock, channels)
}
pub fn configure_channels_with_lock(
chan_lock: &mut MutexGuard<'static, Channels>,
channels: &[ChannelValue],
) -> Result<()> {
let len = channels.len();
if len <= MAX_CHANNELS {
chan_lock[..len]
.iter_mut()
.zip(channels.iter())
.for_each(|(c, &s)| *c = s);
Ok(())
} else {
Err(Error::InvalidLength((len, MAX_CHANNELS)))
}
}
pub fn channel_value(channel: usize) -> Result<ChannelValue> {
channel_value_with_lock(&lock_channels()?, channel)
}
pub fn channel_value_with_lock(
chan_lock: &MutexGuard<'static, Channels>,
channel: usize,
) -> Result<ChannelValue> {
match channel {
0 => Ok(ChannelValue::default()),
c => {
let val = chan_lock
.get(c - 1)
.ok_or(Error::InvalidLength((c, MAX_CHANNELS)))?;
Ok(*val)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_configure_channels() -> Result<()> {
let exp_channels = [
ChannelValue::from(1),
ChannelValue::from(5),
ChannelValue::from(10),
ChannelValue::from(20),
ChannelValue::from(50),
ChannelValue::from(100),
];
let exp_len = exp_channels.len();
for c in 1..=MAX_CHANNELS {
assert_eq!(channel_value(c)?.as_inner(), 0);
}
{
let mut chan_lock = lock_channels()?;
assert!(channels(&chan_lock)?.is_empty());
assert!(channels_mut(&mut chan_lock)?.is_empty());
}
configure_channels(exp_channels.as_ref())?;
let mut chan_lock = lock_channels()?;
assert_eq!(chan_lock[..exp_len].as_ref(), exp_channels.as_ref());
assert_eq!(channel_value_with_lock(&chan_lock, 0)?.as_inner(), 0);
for c in 1..=exp_len {
assert_eq!(channel_value_with_lock(&chan_lock, c)?, exp_channels[c - 1]);
}
let channels = channels(&chan_lock)?;
assert_eq!(channels, exp_channels.as_ref());
let channels = channels_mut(&mut chan_lock)?;
assert_eq!(channels, exp_channels.as_ref());
configure_channels_with_lock(
&mut chan_lock,
[
ChannelValue::default(),
ChannelValue::default(),
ChannelValue::default(),
ChannelValue::default(),
ChannelValue::default(),
ChannelValue::default(),
]
.as_ref(),
)?;
for c in 0..MAX_CHANNELS {
assert_eq!(channel_value_with_lock(&chan_lock, c)?.as_inner(), 0);
}
Ok(())
}
}