diff --git a/README.md b/README.md index 154c075..0d67e2e 100644 --- a/README.md +++ b/README.md @@ -46,26 +46,28 @@ The scope of this setting is per TCP session. ### Commands -| Syntax | Function | -| --- | --- | -| `report` | Show current input | -| `report mode` | Show current report mode | -| `report mode ` | Set report mode | -| `pwm` | Show current PWM settings | -| `pwm <0/1> max_i_pos ` | Set PWM duty cycle for **max_i_pos** to *ampere* | -| `pwm <0/1> max_i_neg ` | Set PWM duty cycle for **max_i_neg** to *ampere* | -| `pwm <0/1> max_v ` | Set PWM duty cycle for **max_v** to *volt* | -| `pwm <0/1> ` | Disengage PID, set **i_set** DAC to *ampere* | -| `pwm <0/1> pid` | Set PWM to be controlled by PID | -| `pid` | Show PID configuration | -| `pid <0/1> target ` | Set the PID controller target | -| `pid <0/1> kp ` | Set proportional gain | -| `pid <0/1> ki ` | Set integral gain | -| `pid <0/1> kd ` | Set differential gain | -| `pid <0/1> output_min ` | Set mininum output | -| `pid <0/1> output_max ` | Set maximum output | -| `pid <0/1> integral_min ` | Set integral lower bound | -| `pid <0/1> integral_max ` | Set integral upper bound | -| `s-h` | Show Steinhart-Hart equation parameters | -| `s-h <0/1> ` | Set Steinhart-Hart parameter for a channel | -| `postfilter <0/1> rate ` | Set postfilter output data rate | +| Syntax | Function | +| --- | --- | +| `report` | Show current input | +| `report mode` | Show current report mode | +| `report mode ` | Set report mode | +| `pwm` | Show current PWM settings | +| `pwm <0/1> max_i_pos ` | Set PWM duty cycle for **max_i_pos** to *ampere* | +| `pwm <0/1> max_i_neg ` | Set PWM duty cycle for **max_i_neg** to *ampere* | +| `pwm <0/1> max_v ` | Set PWM duty cycle for **max_v** to *volt* | +| `pwm <0/1> ` | Disengage PID, set **i_set** DAC to *ampere* | +| `pwm <0/1> pid` | Set PWM to be controlled by PID | +| `center <0/1> ` | Set the MAX1968 0A-centerpoint to *volts* | +| `center <0/1> vref` | Set the MAX1968 0A-centerpoint to measure from VREF | +| `pid` | Show PID configuration | +| `pid <0/1> target ` | Set the PID controller target | +| `pid <0/1> kp ` | Set proportional gain | +| `pid <0/1> ki ` | Set integral gain | +| `pid <0/1> kd ` | Set differential gain | +| `pid <0/1> output_min ` | Set mininum output | +| `pid <0/1> output_max ` | Set maximum output | +| `pid <0/1> integral_min ` | Set integral lower bound | +| `pid <0/1> integral_max ` | Set integral upper bound | +| `s-h` | Show Steinhart-Hart equation parameters | +| `s-h <0/1> ` | Set Steinhart-Hart parameter for a channel | +| `postfilter <0/1> rate ` | Set postfilter output data rate | diff --git a/src/channel_state.rs b/src/channel_state.rs index a25bd24..7719e09 100644 --- a/src/channel_state.rs +++ b/src/channel_state.rs @@ -13,6 +13,7 @@ use crate::{ ad7172, pid, steinhart_hart as sh, + command_parser::CenterPoint, }; const R_INNER: f64 = 2.0 * 5100.0; @@ -24,6 +25,8 @@ pub struct ChannelState { pub adc_time: Instant, /// VREF for the TEC (1.5V) pub vref: ElectricPotential, + /// i_set 0A center point + pub center: CenterPoint, pub dac_value: ElectricPotential, pub pid_engaged: bool, pub pid: pid::Controller, @@ -36,8 +39,9 @@ impl ChannelState { adc_data: None, adc_calibration, adc_time: Instant::from_secs(0), - // can be initialized later with Channels.read_vref() - vref: ElectricPotential::new::(3.3 / 2.0), + // updated later with Channels.read_vref() + vref: ElectricPotential::new::(1.5), + center: CenterPoint::Vref, dac_value: ElectricPotential::new::(0.0), pid_engaged: false, pid: pid::Controller::new(pid::Parameters::default()), diff --git a/src/channels.rs b/src/channels.rs index df53ac2..4f10975 100644 --- a/src/channels.rs +++ b/src/channels.rs @@ -13,7 +13,7 @@ use crate::{ ad7172, channel::{Channel, Channel0, Channel1}, channel_state::ChannelState, - command_parser::PwmPin, + command_parser::{CenterPoint, PwmPin}, pins, }; @@ -99,11 +99,17 @@ impl Channels { } pub fn get_i(&mut self, channel: usize) -> (ElectricCurrent, ElectricCurrent) { - let vref = self.channel_state(channel).vref; + let state = self.channel_state(channel); + let center_point = match state.center { + CenterPoint::Vref => + state.vref, + CenterPoint::Override(center_point) => + ElectricPotential::new::(center_point), + }; let r_sense = ElectricalResistance::new::(R_SENSE); let (voltage, max) = self.get_dac(channel); - let i_tec = (voltage - vref) / (10.0 * r_sense); - let max = (max - vref) / (10.0 * r_sense); + let i_tec = (voltage - center_point) / (10.0 * r_sense); + let max = (max - center_point) / (10.0 * r_sense); (i_tec, max) } @@ -127,12 +133,18 @@ impl Channels { } pub fn set_i(&mut self, channel: usize, i_tec: ElectricCurrent) -> (ElectricCurrent, ElectricCurrent) { - let vref = self.channel_state(channel).vref; + let state = self.channel_state(channel); + let center_point = match state.center { + CenterPoint::Vref => + state.vref, + CenterPoint::Override(center_point) => + ElectricPotential::new::(center_point), + }; let r_sense = ElectricalResistance::new::(R_SENSE); - let voltage = i_tec * 10.0 * r_sense + vref; + let voltage = i_tec * 10.0 * r_sense + center_point; let (voltage, max) = self.set_dac(channel, voltage); - let i_tec = (voltage - vref) / (10.0 * r_sense); - let max = (max - vref) / (10.0 * r_sense); + let i_tec = (voltage - center_point) / (10.0 * r_sense); + let max = (max - center_point) / (10.0 * r_sense); (i_tec, max) } diff --git a/src/command_parser.rs b/src/command_parser.rs index 2fa99a4..db9d3a9 100644 --- a/src/command_parser.rs +++ b/src/command_parser.rs @@ -122,6 +122,12 @@ pub enum PwmPin { MaxV, } +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum CenterPoint { + Vref, + Override(f64), +} + #[derive(Debug, Clone, PartialEq)] pub enum Command { Quit, @@ -137,6 +143,10 @@ pub enum Command { PwmPid { channel: usize, }, + CenterPoint { + channel: usize, + center: CenterPoint, + }, /// PID parameter setting Pid { channel: usize, @@ -290,6 +300,25 @@ fn pwm(input: &[u8]) -> IResult<&[u8], Result> { ))(input) } +fn center_point(input: &[u8]) -> IResult<&[u8], Result> { + let (input, _) = tag("center")(input)?; + let (input, _) = whitespace(input)?; + let (input, channel) = channel(input)?; + let (input, _) = whitespace(input)?; + let (input, center) = alt(( + value(Ok(CenterPoint::Vref), tag("vref")), + |input| { + let (input, value) = float(input)?; + Ok((input, value.map(CenterPoint::Override))) + } + ))(input)?; + end(input)?; + Ok((input, center.map(|center| Command::CenterPoint { + channel, + center, + }))) +} + /// `pid <0-1> ` fn pid_parameter(input: &[u8]) -> IResult<&[u8], Result> { let (input, channel) = channel(input)?; @@ -378,6 +407,7 @@ fn command(input: &[u8]) -> IResult<&[u8], Result> { alt((value(Ok(Command::Quit), tag("quit")), map(report, Ok), pwm, + center_point, pid, steinhart_hart, postfilter, @@ -529,4 +559,22 @@ mod test { rate: 21.0, })); } + + #[test] + fn parse_center_point() { + let command = Command::parse(b"center 0 1.5"); + assert_eq!(command, Ok(Command::CenterPoint { + channel: 0, + center: CenterPoint::Override(1.5), + })); + } + + #[test] + fn parse_center_point_vref() { + let command = Command::parse(b"center 1 vref"); + assert_eq!(command, Ok(Command::CenterPoint { + channel: 1, + center: CenterPoint::Vref, + })); + } } diff --git a/src/main.rs b/src/main.rs index d8eeb21..c36cc9a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -55,7 +55,7 @@ use server::Server; mod session; use session::{Session, SessionOutput}; mod command_parser; -use command_parser::{Command, ShowCommand, PwmPin}; +use command_parser::{CenterPoint, Command, ShowCommand, PwmPin}; mod timer; mod pid; mod steinhart_hart; @@ -221,18 +221,32 @@ fn main() -> ! { } Command::Show(ShowCommand::Pwm) => { for channel in 0..CHANNELS { + let i_set = channels.get_i(channel); let state = channels.channel_state(channel); let _ = writeln!( socket, "channel {}: PID={}", channel, if state.pid_engaged { "engaged" } else { "disengaged" } ); - let i_set = channels.get_i(channel); - let _ = writeln!( - socket, "- i_set={:.3} / {:.3}", + let _ = write!( + socket, "- i_set={:.3} / {:.3} ", i_set.0.into_format_args(ampere, Abbreviation), i_set.1.into_format_args(ampere, Abbreviation), ); + match state.center { + CenterPoint::Vref => { + let _ = writeln!( + socket, "center=vref vref={:.3}", + state.vref.into_format_args(volt, Abbreviation), + ); + } + CenterPoint::Override(volts) => { + let _ = writeln!( + socket, "center={:.3} V", + volts, + ); + } + } let max_v = channels.get_max_v(channel); let _ = writeln!( socket, "- max_v={:.3} / {:.3}", @@ -321,7 +335,7 @@ fn main() -> ! { let voltage = ElectricPotential::new::(value); let (voltage, max) = channels.set_max_v(channel, voltage); let _ = writeln!( - socket, "channel {:.3}: max_v set to {:.3} / {:.3}", + socket, "channel {}: max_v set to {:.3} / {:.3}", channel, voltage.into_format_args(volt, Abbreviation), max.into_format_args(volt, Abbreviation), @@ -331,7 +345,7 @@ fn main() -> ! { let current = ElectricCurrent::new::(value); let (current, max) = channels.set_max_i_pos(channel, current); let _ = writeln!( - socket, "channel {:.3}: max_i_pos set to {:.3} / {:.3}", + socket, "channel {}: max_i_pos set to {:.3} / {:.3}", channel, current.into_format_args(ampere, Abbreviation), max.into_format_args(ampere, Abbreviation), @@ -341,7 +355,7 @@ fn main() -> ! { let current = ElectricCurrent::new::(value); let (current, max) = channels.set_max_i_neg(channel, current); let _ = writeln!( - socket, "channel {:.3}: max_i_neg set to {:.3} / {:.3}", + socket, "channel {}: max_i_neg set to {:.3} / {:.3}", channel, current.into_format_args(ampere, Abbreviation), max.into_format_args(ampere, Abbreviation), @@ -349,6 +363,23 @@ fn main() -> ! { } } } + Command::CenterPoint { channel, center } => { + let (i_tec, _) = channels.get_i(channel); + let state = channels.channel_state(channel); + state.center = center; + if !state.pid_engaged { + channels.set_i(channel, i_tec); + let _ = writeln!( + socket, "channel {}: center point updated, output readjusted for {:.3}", + channel, i_tec.into_format_args(ampere, Abbreviation), + ); + } else { + let _ = writeln!( + socket, "channel {}: center point updated", + channel, + ); + } + } Command::Pid { channel, parameter, value } => { let pid = &mut channels.channel_state(channel).pid; use command_parser::PidParameter::*;