2020-08-11 00:07:07 +08:00
|
|
|
use embedded_hal::blocking::spi::Transfer;
|
2020-08-11 11:29:47 +08:00
|
|
|
use core::assert;
|
2020-08-11 00:07:07 +08:00
|
|
|
|
2020-09-24 17:32:53 +08:00
|
|
|
use crate::urukul::Error;
|
2020-08-11 00:07:07 +08:00
|
|
|
|
|
|
|
pub struct Attenuator<SPI> {
|
2020-09-25 14:24:33 +08:00
|
|
|
spi: SPI,
|
|
|
|
data: [u8; 4],
|
2020-08-11 00:07:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<SPI, E> Attenuator<SPI>
|
|
|
|
where
|
2020-09-25 14:24:33 +08:00
|
|
|
SPI: Transfer<u8, Error = E>
|
2020-08-11 00:07:07 +08:00
|
|
|
{
|
2020-09-25 14:24:33 +08:00
|
|
|
pub fn new(spi: SPI) -> Self {
|
|
|
|
Attenuator {
|
|
|
|
spi,
|
|
|
|
// data[y] refers to the yth byte for SPI communication
|
|
|
|
data: [0, 0, 0, 0],
|
|
|
|
}
|
|
|
|
}
|
2020-08-11 00:07:07 +08:00
|
|
|
|
2020-09-25 14:24:33 +08:00
|
|
|
/*
|
|
|
|
* Set attenuations of all attenuators
|
|
|
|
* att[x] refers to the attenuation for channel x
|
|
|
|
*/
|
|
|
|
pub fn set_attenuation(&mut self, att: [f32; 4]) -> Result<(), Error<E>> {
|
|
|
|
for i in 0..4 {
|
|
|
|
let mut atten = att[i];
|
|
|
|
if att[i] > 31.5 {
|
|
|
|
atten = 31.5;
|
|
|
|
}
|
|
|
|
if att[i] < 0.0 {
|
|
|
|
atten = 0.0;
|
|
|
|
}
|
|
|
|
// Set data as attenuation * 2
|
|
|
|
// Flip data using bitwise XOR, active low data
|
|
|
|
// Data is most signifant attenuator first
|
|
|
|
self.data[3-i] = (((atten * 2.0) as u8) ^ 0xFF) << 2
|
|
|
|
}
|
|
|
|
let mut clone = self.data.clone();
|
|
|
|
// Transmit SPI once to set attenuation
|
|
|
|
self.spi.transfer(&mut clone)
|
|
|
|
.map(|_| ())
|
|
|
|
.map_err(|_| Error::AttenuatorError)
|
|
|
|
}
|
2020-08-11 11:29:47 +08:00
|
|
|
|
2020-09-25 14:24:33 +08:00
|
|
|
pub fn set_channel_attenuation(&mut self, channel: u8, attenuation: f32) -> Result<(), Error<E>> {
|
|
|
|
assert!(channel < 4);
|
|
|
|
let mut arr: [f32; 4] = self.get_attenuation()?;
|
|
|
|
arr[channel as usize] = attenuation;
|
|
|
|
self.set_attenuation(arr).map(|_| ())
|
|
|
|
}
|
2020-08-11 11:29:47 +08:00
|
|
|
|
2020-09-25 14:24:33 +08:00
|
|
|
pub fn get_channel_attenuation(&mut self, channel: u8) -> Result<f32, Error<E>> {
|
|
|
|
assert!(channel < 4);
|
|
|
|
match self.get_attenuation() {
|
|
|
|
Ok(arr) => Ok(arr[channel as usize]),
|
|
|
|
Err(e) => Err(e),
|
|
|
|
}
|
|
|
|
}
|
2020-08-11 11:29:47 +08:00
|
|
|
|
2020-09-25 14:24:33 +08:00
|
|
|
pub fn get_attenuation(&mut self) -> Result<[f32; 4], Error<E>> {
|
|
|
|
let mut clone = self.data.clone();
|
|
|
|
match self.spi.transfer(&mut clone).map_err(Error::SPI) {
|
|
|
|
Ok(arr) => {
|
|
|
|
let mut ret :[f32; 4] = [0.0; 4];
|
|
|
|
for index in 0..4 {
|
|
|
|
ret[index] = ((arr[3 - index] ^ 0xFC) as f32) / 8.0;
|
|
|
|
}
|
|
|
|
Ok(ret)
|
|
|
|
},
|
|
|
|
Err(e) => Err(e),
|
|
|
|
}
|
|
|
|
}
|
2020-08-31 17:43:15 +08:00
|
|
|
|
2020-09-25 14:24:33 +08:00
|
|
|
/*
|
|
|
|
* Test method for Attenuators.
|
|
|
|
* Return the number of test failed.
|
|
|
|
*/
|
|
|
|
pub fn test(&mut self) -> Result<u32, Error<E>> {
|
|
|
|
// Test attenuators by getting back the attenuation
|
|
|
|
let mut error_count = 0;
|
|
|
|
// Convert cached SPI data into attenuation floats
|
|
|
|
let att_floats :[f32; 4] = [
|
|
|
|
((self.data[3] ^ 0xFC) as f32) / 8.0,
|
|
|
|
((self.data[2] ^ 0xFC) as f32) / 8.0,
|
|
|
|
((self.data[1] ^ 0xFC) as f32) / 8.0,
|
|
|
|
((self.data[0] ^ 0xFC) as f32) / 8.0,
|
|
|
|
];
|
|
|
|
// Set the attenuation to an arbitrary value, then read the attenuation
|
|
|
|
self.set_attenuation([
|
|
|
|
3.5, 9.5, 20.0, 28.5
|
|
|
|
])?;
|
|
|
|
match self.get_attenuation() {
|
|
|
|
Ok(arr) => {
|
|
|
|
if arr[0] != 3.5 {
|
|
|
|
error_count += 1;
|
|
|
|
}
|
|
|
|
if arr[1] != 9.5 {
|
|
|
|
error_count += 1;
|
|
|
|
}
|
|
|
|
if arr[2] != 20.0 {
|
|
|
|
error_count += 1;
|
|
|
|
}
|
|
|
|
if arr[3] != 28.5 {
|
|
|
|
error_count += 1;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
Err(_) => return Err(Error::AttenuatorError),
|
|
|
|
};
|
|
|
|
self.set_attenuation(att_floats)?;
|
|
|
|
Ok(error_count)
|
|
|
|
}
|
2020-08-11 00:07:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<SPI, E> Transfer<u8> for Attenuator<SPI>
|
|
|
|
where
|
2020-09-25 14:24:33 +08:00
|
|
|
SPI: Transfer<u8, Error = E>
|
2020-08-11 00:07:07 +08:00
|
|
|
{
|
2020-09-25 14:24:33 +08:00
|
|
|
type Error = Error<E>;
|
2020-08-11 00:07:07 +08:00
|
|
|
|
2020-09-25 14:24:33 +08:00
|
|
|
fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> {
|
|
|
|
self.spi.transfer(words).map_err(Error::SPI)
|
|
|
|
}
|
2020-08-11 00:07:07 +08:00
|
|
|
}
|