forked from M-Labs/ionpak-thermostat
add remote postfilter configuration
This commit is contained in:
parent
87de8b7859
commit
63aa2347b7
@ -66,3 +66,4 @@ The scope of this setting is per TCP session.
|
||||
| `pid <0/1> output_max <value>` | |
|
||||
| `pid <0/1> integral_min <value>` | |
|
||||
| `pid <0/1> integral_max <value>` | |
|
||||
| `postfilter <0/1> rate <rate>` | Set postfilter output data rate |
|
||||
|
@ -78,6 +78,29 @@ impl<SPI: Transfer<u8>, NSS: OutputPin> Adc<SPI, NSS> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_postfilter(&mut self, index: u8) -> Result<Option<PostFilter>, AdcError<SPI::Error>> {
|
||||
self.read_reg(®s::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(®s::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
|
||||
pub fn data_ready(&mut self) -> Result<Option<u8>, AdcError<SPI::Error>> {
|
||||
self.read_reg(®s::Status)
|
||||
|
@ -111,6 +111,7 @@ impl fmt::Display for RefSource {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
#[repr(u8)]
|
||||
pub enum PostFilter {
|
||||
/// 27 SPS, 47 dB rejection, 36.7 ms settling
|
||||
@ -124,6 +125,49 @@ pub enum PostFilter {
|
||||
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 {
|
||||
fn from(x: u8) -> Self {
|
||||
match x {
|
||||
|
@ -5,7 +5,7 @@ use nom::{
|
||||
bytes::complete::{is_a, tag, take_while1},
|
||||
character::{is_digit, complete::{char, one_of}},
|
||||
combinator::{complete, map, value},
|
||||
sequence::preceded,
|
||||
sequence::{preceded, separated_pair},
|
||||
multi::{fold_many0, fold_many1},
|
||||
error::ErrorKind,
|
||||
};
|
||||
@ -66,6 +66,7 @@ pub enum ShowCommand {
|
||||
Reporting,
|
||||
Pwm,
|
||||
Pid,
|
||||
PostFilter,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@ -103,6 +104,10 @@ pub enum Command {
|
||||
parameter: PidParameter,
|
||||
value: f32,
|
||||
},
|
||||
PostFilter {
|
||||
channel: usize,
|
||||
rate: f32,
|
||||
},
|
||||
}
|
||||
|
||||
fn end(input: &[u8]) -> IResult<&[u8], ()> {
|
||||
@ -244,11 +249,34 @@ fn pid(input: &[u8]) -> IResult<&[u8], Result<Command, Error>> {
|
||||
))(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>> {
|
||||
alt((value(Ok(Command::Quit), tag("quit")),
|
||||
map(report, Ok),
|
||||
pwm,
|
||||
pid,
|
||||
postfilter,
|
||||
))(input)
|
||||
}
|
||||
|
||||
|
@ -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 }} => {
|
||||
states[channel].pid_enabled = false;
|
||||
board::set_timer_pwm(width, total);
|
||||
@ -339,6 +357,21 @@ fn main() -> ! {
|
||||
}
|
||||
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)) => {
|
||||
let _ = writeln!(socket, "Command error: {:?}", e);
|
||||
|
Loading…
Reference in New Issue
Block a user