forked from M-Labs/thermostat
refactor into Channels::poll_adc()
This commit is contained in:
parent
9466961bd7
commit
3d1740b23b
@ -6,7 +6,7 @@ pub struct ChannelState {
|
||||
pub adc_data: Option<u32>,
|
||||
pub adc_time: Instant,
|
||||
pub dac_value: u32,
|
||||
pub pid_enabled: bool,
|
||||
pub pid_engaged: bool,
|
||||
pub pid: pid::Controller,
|
||||
pub sh: sh::Parameters,
|
||||
}
|
||||
@ -17,7 +17,7 @@ impl Default for ChannelState {
|
||||
adc_data: None,
|
||||
adc_time: Instant::from_secs(0),
|
||||
dac_value: 0,
|
||||
pid_enabled: false,
|
||||
pid_engaged: false,
|
||||
pid: pid::Controller::new(pid::Parameters::default()),
|
||||
sh: sh::Parameters::default(),
|
||||
}
|
||||
@ -26,7 +26,7 @@ impl Default for ChannelState {
|
||||
|
||||
impl ChannelState {
|
||||
/// Update PID state on ADC input, calculate new DAC output
|
||||
pub fn update_adc(&mut self, now: Instant, adc_data: u32) {
|
||||
pub fn update_pid(&mut self, now: Instant, adc_data: u32) {
|
||||
self.adc_data = Some(adc_data);
|
||||
self.adc_time = now;
|
||||
|
||||
|
@ -1,9 +1,14 @@
|
||||
use stm32f4xx_hal::hal::digital::v2::OutputPin;
|
||||
use smoltcp::time::Instant;
|
||||
use crate::{
|
||||
ad7172,
|
||||
channel::{Channel, Channel0, Channel1},
|
||||
channel_state::ChannelState,
|
||||
pins,
|
||||
};
|
||||
|
||||
pub const CHANNELS: usize = 2;
|
||||
|
||||
pub struct Channels {
|
||||
pub channel0: Channel<Channel0>,
|
||||
pub channel1: Channel<Channel1>,
|
||||
@ -27,4 +32,47 @@ impl Channels {
|
||||
|
||||
Channels { channel0, channel1, adc, pwm }
|
||||
}
|
||||
|
||||
pub fn channel_state<I: Into<usize>>(&mut self, channel: I) -> &mut ChannelState {
|
||||
match channel.into() {
|
||||
0 => &mut self.channel0.state,
|
||||
1 => &mut self.channel1.state,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
/// ADC input + PID processing
|
||||
pub fn poll_adc(&mut self, instant: Instant) -> Option<u8> {
|
||||
self.adc.data_ready().unwrap().map(|channel| {
|
||||
let data = self.adc.read_data().unwrap();
|
||||
|
||||
let dac_value = {
|
||||
let state = self.channel_state(channel);
|
||||
state.update_pid(instant, data);
|
||||
|
||||
if state.pid_engaged {
|
||||
Some(state.dac_value)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
};
|
||||
if let Some(dac_value) = dac_value {
|
||||
// Forward PID output to i_set DAC
|
||||
match channel {
|
||||
0 => {
|
||||
self.channel0.dac.set(dac_value).unwrap();
|
||||
self.channel0.shdn.set_high().unwrap();
|
||||
}
|
||||
1 => {
|
||||
self.channel1.dac.set(dac_value).unwrap();
|
||||
self.channel1.shdn.set_high().unwrap();
|
||||
}
|
||||
_ =>
|
||||
unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
channel
|
||||
})
|
||||
}
|
||||
}
|
||||
|
63
src/main.rs
63
src/main.rs
@ -39,17 +39,16 @@ mod net;
|
||||
mod server;
|
||||
use server::Server;
|
||||
mod session;
|
||||
use session::{CHANNELS, Session, SessionOutput};
|
||||
use session::{Session, SessionOutput};
|
||||
mod command_parser;
|
||||
use command_parser::{Command, ShowCommand, PwmPin};
|
||||
mod timer;
|
||||
mod pid;
|
||||
mod steinhart_hart;
|
||||
mod channels;
|
||||
use channels::Channels;
|
||||
use channels::{CHANNELS, Channels};
|
||||
mod channel;
|
||||
mod channel_state;
|
||||
use channel_state::ChannelState;
|
||||
|
||||
|
||||
const HSE: MegaHertz = MegaHertz(8);
|
||||
@ -96,9 +95,6 @@ fn main() -> ! {
|
||||
dp.ADC1, dp.ADC2,
|
||||
);
|
||||
let mut channels = Channels::new(pins);
|
||||
let mut channel_states: [ChannelState; CHANNELS] = [
|
||||
ChannelState::default(), ChannelState::default()
|
||||
];
|
||||
timer::setup(cp.SYST, clocks);
|
||||
|
||||
#[cfg(not(feature = "generate-hwaddr"))]
|
||||
@ -114,31 +110,10 @@ fn main() -> ! {
|
||||
Server::<Session>::run(iface, |server| {
|
||||
loop {
|
||||
let instant = Instant::from_millis(i64::from(timer::now()));
|
||||
// ADC input
|
||||
channels.adc.data_ready().unwrap().map(|channel| {
|
||||
let data = channels.adc.read_data().unwrap();
|
||||
|
||||
let state = &mut channel_states[usize::from(channel)];
|
||||
state.update_adc(instant, data);
|
||||
|
||||
if state.pid_enabled {
|
||||
// Forward PID output to i_set DAC
|
||||
match channel {
|
||||
0 => {
|
||||
channels.channel0.dac.set(state.dac_value).unwrap();
|
||||
channels.channel0.shdn.set_high().unwrap();
|
||||
}
|
||||
1 => {
|
||||
channels.channel1.dac.set(state.dac_value).unwrap();
|
||||
channels.channel1.shdn.set_high().unwrap();
|
||||
}
|
||||
_ =>
|
||||
unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
let updated_channel = channels.poll_adc(instant);
|
||||
if let Some(channel) = updated_channel {
|
||||
server.for_each(|_, session| session.set_report_pending(channel.into()));
|
||||
});
|
||||
}
|
||||
|
||||
let instant = Instant::from_millis(i64::from(timer::now()));
|
||||
cortex_m::interrupt::free(net::clear_pending);
|
||||
@ -165,7 +140,8 @@ fn main() -> ! {
|
||||
let _ = writeln!(socket, "report={}", if session.reporting() { "on" } else { "off" });
|
||||
}
|
||||
Command::Show(ShowCommand::Input) => {
|
||||
for (channel, state) in channel_states.iter().enumerate() {
|
||||
for channel in 0..CHANNELS {
|
||||
let state = channels.channel_state(channel);
|
||||
if let Some(adc_data) = state.adc_data {
|
||||
let _ = writeln!(
|
||||
socket, "t={} raw{}=0x{:06X}",
|
||||
@ -180,7 +156,8 @@ fn main() -> ! {
|
||||
let _ = writeln!(socket, "ref0={}", ref0);
|
||||
}
|
||||
Command::Show(ShowCommand::Pid) => {
|
||||
for (channel, state) in channel_states.iter().enumerate() {
|
||||
for channel in 0..CHANNELS {
|
||||
let state = channels.channel_state(channel);
|
||||
let _ = writeln!(socket, "PID settings for channel {}", channel);
|
||||
let pid = &state.pid;
|
||||
let _ = writeln!(socket, "- target={:.4}", pid.target);
|
||||
@ -206,11 +183,12 @@ fn main() -> ! {
|
||||
}
|
||||
}
|
||||
Command::Show(ShowCommand::Pwm) => {
|
||||
for (channel, state) in channel_states.iter().enumerate() {
|
||||
for channel in 0..CHANNELS {
|
||||
let state = channels.channel_state(channel);
|
||||
let _ = writeln!(
|
||||
socket, "channel {}: PID={}",
|
||||
channel,
|
||||
if state.pid_enabled { "engaged" } else { "disengaged" }
|
||||
if state.pid_engaged { "engaged" } else { "disengaged" }
|
||||
);
|
||||
let _ = writeln!(socket, "- i_set={}/{}", state.dac_value, ad5680::MAX_VALUE);
|
||||
fn show_pwm_channel<S, P>(mut socket: S, name: &str, pin: &P)
|
||||
@ -241,7 +219,8 @@ fn main() -> ! {
|
||||
}
|
||||
}
|
||||
Command::Show(ShowCommand::SteinhartHart) => {
|
||||
for (channel, state) in channel_states.iter().enumerate() {
|
||||
for channel in 0..CHANNELS {
|
||||
let state = channels.channel_state(channel);
|
||||
let _ = writeln!(
|
||||
socket, "channel {}: Steinhart-Hart equation parameters",
|
||||
channel,
|
||||
@ -253,7 +232,7 @@ fn main() -> ! {
|
||||
}
|
||||
}
|
||||
Command::Show(ShowCommand::PostFilter) => {
|
||||
for (channel, _) in channel_states.iter().enumerate() {
|
||||
for channel in 0..CHANNELS {
|
||||
match channels.adc.get_postfilter(channel as u8).unwrap() {
|
||||
Some(filter) => {
|
||||
let _ = writeln!(
|
||||
@ -271,12 +250,12 @@ fn main() -> ! {
|
||||
}
|
||||
}
|
||||
Command::PwmPid { channel } => {
|
||||
channel_states[channel].pid_enabled = true;
|
||||
channels.channel_state(channel).pid_engaged = true;
|
||||
let _ = writeln!(socket, "channel {}: PID enabled to control PWM", channel
|
||||
);
|
||||
}
|
||||
Command::Pwm { channel, pin: PwmPin::ISet, duty } if duty <= ad5680::MAX_VALUE => {
|
||||
channel_states[channel].pid_enabled = false;
|
||||
channels.channel_state(channel).pid_engaged = false;
|
||||
match channel {
|
||||
0 => {
|
||||
channels.channel0.dac.set(duty).unwrap();
|
||||
@ -288,7 +267,7 @@ fn main() -> ! {
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
channel_states[channel].dac_value = duty;
|
||||
channels.channel_state(channel).dac_value = duty;
|
||||
let _ = writeln!(
|
||||
socket, "channel {}: PWM duty cycle manually set to {}/{}",
|
||||
channel, duty, ad5680::MAX_VALUE
|
||||
@ -335,7 +314,7 @@ fn main() -> ! {
|
||||
let _ = writeln!(socket, "error: PWM duty range must fit 16 bits");
|
||||
}
|
||||
Command::Pid { channel, parameter, value } => {
|
||||
let pid = &mut channel_states[channel].pid;
|
||||
let pid = &mut channels.channel_state(channel).pid;
|
||||
use command_parser::PidParameter::*;
|
||||
match parameter {
|
||||
Target =>
|
||||
@ -361,7 +340,7 @@ fn main() -> ! {
|
||||
let _ = writeln!(socket, "PID parameter updated");
|
||||
}
|
||||
Command::SteinhartHart { channel, parameter, value } => {
|
||||
let sh = &mut channel_states[channel].sh;
|
||||
let sh = &mut channels.channel_state(channel).sh;
|
||||
use command_parser::ShParameter::*;
|
||||
match parameter {
|
||||
T0 => sh.t0 = value,
|
||||
@ -397,7 +376,7 @@ fn main() -> ! {
|
||||
}
|
||||
} else if socket.can_send() && socket.send_capacity() - socket.send_queue() > 256 {
|
||||
while let Some(channel) = session.is_report_pending() {
|
||||
let state = &mut channel_states[usize::from(channel)];
|
||||
let state = &mut channels.channel_state(usize::from(channel));
|
||||
let _ = writeln!(
|
||||
socket, "t={} raw{}=0x{:06X}",
|
||||
state.adc_time, channel, state.adc_data.unwrap_or(0)
|
||||
|
@ -1,4 +1,5 @@
|
||||
use super::command_parser::{Command, Error as ParserError};
|
||||
use super::channels::CHANNELS;
|
||||
|
||||
const MAX_LINE_LEN: usize = 64;
|
||||
|
||||
@ -50,8 +51,6 @@ impl From<Result<Command, ParserError>> for SessionOutput {
|
||||
}
|
||||
}
|
||||
|
||||
pub const CHANNELS: usize = 2;
|
||||
|
||||
pub struct Session {
|
||||
reader: LineReader,
|
||||
reporting: bool,
|
||||
|
Loading…
Reference in New Issue
Block a user