add remote postfilter configuration

master
Astro 2019-09-19 03:28:10 +02:00
parent 87de8b7859
commit 63aa2347b7
5 changed files with 130 additions and 1 deletions

View File

@ -66,3 +66,4 @@ The scope of this setting is per TCP session.
| `pid <0/1> output_max <value>` | | | `pid <0/1> output_max <value>` | |
| `pid <0/1> integral_min <value>` | | | `pid <0/1> integral_min <value>` | |
| `pid <0/1> integral_max <value>` | | | `pid <0/1> integral_max <value>` | |
| `postfilter <0/1> rate <rate>` | Set postfilter output data rate |

View File

@ -78,6 +78,29 @@ impl<SPI: Transfer<u8>, NSS: OutputPin> Adc<SPI, NSS> {
Ok(()) Ok(())
} }
pub fn get_postfilter(&mut self, index: u8) -> Result<Option<PostFilter>, AdcError<SPI::Error>> {
self.read_reg(&regs::FiltCon { index })
.map(|data| {
if data.enh_filt_en() {
Some(data.enh_filt())
} else {
None
}
})
}
pub fn set_postfilter(&mut self, index: u8, filter: Option<PostFilter>) -> Result<(), AdcError<SPI::Error>> {
self.update_reg(&regs::FiltCon { index }, |data| {
match filter {
None => data.set_enh_filt_en(false),
Some(filter) => {
data.set_enh_filt_en(true);
data.set_enh_filt(filter);
}
}
})
}
/// Returns the channel the data is from /// Returns the channel the data is from
pub fn data_ready(&mut self) -> Result<Option<u8>, AdcError<SPI::Error>> { pub fn data_ready(&mut self) -> Result<Option<u8>, AdcError<SPI::Error>> {
self.read_reg(&regs::Status) self.read_reg(&regs::Status)

View File

@ -111,6 +111,7 @@ impl fmt::Display for RefSource {
} }
} }
#[derive(Clone, Copy)]
#[repr(u8)] #[repr(u8)]
pub enum PostFilter { pub enum PostFilter {
/// 27 SPS, 47 dB rejection, 36.7 ms settling /// 27 SPS, 47 dB rejection, 36.7 ms settling
@ -124,6 +125,49 @@ pub enum PostFilter {
Invalid = 0b111, Invalid = 0b111,
} }
impl PostFilter {
pub const VALID_VALUES: &'static [Self] = &[
PostFilter::F27SPS,
PostFilter::F21SPS,
PostFilter::F20SPS,
PostFilter::F16SPS,
];
pub fn closest(rate: f32) -> Option<Self> {
/// (x - y).abs()
fn d(x: f32, y: f32) -> f32 {
if x >= y {
x - y
} else {
y - x
}
}
let mut best: Option<(f32, Self)> = None;
for value in Self::VALID_VALUES {
let error = d(rate, value.output_rate().unwrap());
let better = best
.map(|(best_error, _)| error < best_error)
.unwrap_or(true);
if better {
best = Some((error, *value));
}
}
best.map(|(_, best)| best)
}
/// Samples per Second
pub fn output_rate(&self) -> Option<f32> {
match self {
PostFilter::F27SPS => Some(27.0),
PostFilter::F21SPS => Some(21.25),
PostFilter::F20SPS => Some(20.0),
PostFilter::F16SPS => Some(16.67),
PostFilter::Invalid => None,
}
}
}
impl From<u8> for PostFilter { impl From<u8> for PostFilter {
fn from(x: u8) -> Self { fn from(x: u8) -> Self {
match x { match x {

View File

@ -5,7 +5,7 @@ use nom::{
bytes::complete::{is_a, tag, take_while1}, bytes::complete::{is_a, tag, take_while1},
character::{is_digit, complete::{char, one_of}}, character::{is_digit, complete::{char, one_of}},
combinator::{complete, map, value}, combinator::{complete, map, value},
sequence::preceded, sequence::{preceded, separated_pair},
multi::{fold_many0, fold_many1}, multi::{fold_many0, fold_many1},
error::ErrorKind, error::ErrorKind,
}; };
@ -66,6 +66,7 @@ pub enum ShowCommand {
Reporting, Reporting,
Pwm, Pwm,
Pid, Pid,
PostFilter,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -103,6 +104,10 @@ pub enum Command {
parameter: PidParameter, parameter: PidParameter,
value: f32, value: f32,
}, },
PostFilter {
channel: usize,
rate: f32,
},
} }
fn end(input: &[u8]) -> IResult<&[u8], ()> { fn end(input: &[u8]) -> IResult<&[u8], ()> {
@ -244,11 +249,34 @@ fn pid(input: &[u8]) -> IResult<&[u8], Result<Command, Error>> {
))(input) ))(input)
} }
fn postfilter(input: &[u8]) -> IResult<&[u8], Result<Command, Error>> {
let (input, _) = tag("postfilter")(input)?;
alt((
preceded(
whitespace,
|input| {
let (input, channel) = channel(input)?;
let (input, _) = whitespace(input)?;
let (input, _) = tag("rate")(input)?;
let (input, _) = whitespace(input)?;
let (input, rate) = float(input)?;
let result = rate
.map(|rate| Command::PostFilter {
channel, rate,
});
Ok((input, result))
}
),
value(Ok(Command::Show(ShowCommand::PostFilter)), end)
))(input)
}
fn command(input: &[u8]) -> IResult<&[u8], Result<Command, Error>> { fn command(input: &[u8]) -> IResult<&[u8], Result<Command, Error>> {
alt((value(Ok(Command::Quit), tag("quit")), alt((value(Ok(Command::Quit), tag("quit")),
map(report, Ok), map(report, Ok),
pwm, pwm,
pid, pid,
postfilter,
))(input) ))(input)
} }

View File

@ -305,6 +305,24 @@ fn main() -> ! {
); );
} }
} }
Command::Show(ShowCommand::PostFilter) => {
for (channel, _) in states.iter().enumerate() {
match adc.get_postfilter(channel as u8).unwrap() {
Some(filter) => {
let _ = writeln!(
socket, "channel {}: postfilter={:.2} SPS",
channel, filter.output_rate().unwrap()
);
}
None => {
let _ = writeln!(
socket, "channel {}: no postfilter",
channel
);
}
}
}
}
Command::Pwm { channel, mode: PwmMode::Manual { width, total }} => { Command::Pwm { channel, mode: PwmMode::Manual { width, total }} => {
states[channel].pid_enabled = false; states[channel].pid_enabled = false;
board::set_timer_pwm(width, total); board::set_timer_pwm(width, total);
@ -339,6 +357,21 @@ fn main() -> ! {
} }
let _ = writeln!(socket, "PID parameter updated"); let _ = writeln!(socket, "PID parameter updated");
} }
Command::PostFilter { channel, rate } => {
let filter = ad7172::PostFilter::closest(rate);
match filter {
Some(filter) => {
adc.set_postfilter(channel as u8, Some(filter)).unwrap();
let _ = writeln!(
socket, "channel {}: postfilter set to {:.2} SPS",
channel, filter.output_rate().unwrap()
);
}
None => {
let _ = writeln!(socket, "Unable to choose postfilter");
}
}
}
} }
Ok(SessionOutput::Error(e)) => { Ok(SessionOutput::Error(e)) => {
let _ = writeln!(socket, "Command error: {:?}", e); let _ = writeln!(socket, "Command error: {:?}", e);