Compare commits

...

4 Commits

Author SHA1 Message Date
1741acfc3b Account for swapped current limits 2024-09-23 16:31:13 +08:00
ce4fb6090a README: polarity_swapped 2024-09-23 14:48:54 +08:00
f3d5b1dc6b add swap status to the report
Signed-off-by: Egor Savkin <es@m-labs.hk>
2024-09-23 14:48:54 +08:00
ca096c119d Add command for flipping output polarity
Needed for IDC cable connections, since the IDC connector and front
panel connectors have flipped polarities.
2024-09-23 14:48:54 +08:00
5 changed files with 106 additions and 43 deletions

View File

@ -94,42 +94,43 @@ The scope of this setting is per TCP session.
Send commands as simple text string terminated by `\n`. Responses are Send commands as simple text string terminated by `\n`. Responses are
formatted as line-delimited JSON. formatted as line-delimited JSON.
| Syntax | Function | | Syntax | Function |
|----------------------------------|-------------------------------------------------------------------------------| |-------------------------------------------|-------------------------------------------------------------------------------|
| `report` | Show current input | | `report` | Show current input |
| `report mode` | Show current report mode | | `report mode` | Show current report mode |
| `report mode <off/on>` | Set report mode | | `report mode <off/on>` | Set report mode |
| `pwm` | Show current PWM settings | | `pwm` | Show current PWM settings |
| `pwm <0/1> max_i_pos <amp>` | Set maximum positive output current | | `pwm <0/1> max_i_pos <amp>` | Set maximum positive output current |
| `pwm <0/1> max_i_neg <amp>` | Set maximum negative output current | | `pwm <0/1> max_i_neg <amp>` | Set maximum negative output current |
| `pwm <0/1> max_v <volt>` | Set maximum output voltage | | `pwm <0/1> max_v <volt>` | Set maximum output voltage |
| `pwm <0/1> i_set <amp>` | Disengage PID, set fixed output current | | `pwm <0/1> i_set <amp>` | Disengage PID, set fixed output current |
| `pwm <0/1> pid` | Let output current to be controlled by the PID | | `pwm <0/1> polarity_swapped <false/true>` | Swap output current polarity on channel |
| `center <0/1> <volt>` | Set the MAX1968 0A-centerpoint to the specified fixed voltage | | `pwm <0/1> pid` | Let output current to be controlled by the PID |
| `center <0/1> vref` | Set the MAX1968 0A-centerpoint to measure from VREF | | `center <0/1> <volt>` | Set the MAX1968 0A-centerpoint to the specified fixed voltage |
| `pid` | Show PID configuration | | `center <0/1> vref` | Set the MAX1968 0A-centerpoint to measure from VREF |
| `pid <0/1> target <deg_celsius>` | Set the PID controller target temperature | | `pid` | Show PID configuration |
| `pid <0/1> kp <value>` | Set proportional gain | | `pid <0/1> target <deg_celsius>` | Set the PID controller target temperature |
| `pid <0/1> ki <value>` | Set integral gain | | `pid <0/1> kp <value>` | Set proportional gain |
| `pid <0/1> kd <value>` | Set differential gain | | `pid <0/1> ki <value>` | Set integral gain |
| `pid <0/1> output_min <amp>` | Set mininum output | | `pid <0/1> kd <value>` | Set differential gain |
| `pid <0/1> output_max <amp>` | Set maximum output | | `pid <0/1> output_min <amp>` | Set mininum output |
| `s-h` | Show Steinhart-Hart equation parameters | | `pid <0/1> output_max <amp>` | Set maximum output |
| `s-h <0/1> <t0/b/r0> <value>` | Set Steinhart-Hart parameter for a channel | | `s-h` | Show Steinhart-Hart equation parameters |
| `postfilter` | Show postfilter settings | | `s-h <0/1> <t0/b/r0> <value>` | Set Steinhart-Hart parameter for a channel |
| `postfilter <0/1> off` | Disable postfilter | | `postfilter` | Show postfilter settings |
| `postfilter <0/1> rate <rate>` | Set postfilter output data rate | | `postfilter <0/1> off` | Disable postfilter |
| `load [0/1]` | Restore configuration for channel all/0/1 from flash | | `postfilter <0/1> rate <rate>` | Set postfilter output data rate |
| `save [0/1]` | Save configuration for channel all/0/1 to flash | | `load [0/1]` | Restore configuration for channel all/0/1 from flash |
| `reset` | Reset the device | | `save [0/1]` | Save configuration for channel all/0/1 to flash |
| `dfu` | Reset device and enters USB device firmware update (DFU) mode | | `reset` | Reset the device |
| `ipv4 <X.X.X.X/L> [Y.Y.Y.Y]` | Configure IPv4 address, netmask length, and optional default gateway | | `dfu` | Reset device and enters USB device firmware update (DFU) mode |
| `fan` | Show current fan settings and sensors' measurements | | `ipv4 <X.X.X.X/L> [Y.Y.Y.Y]` | Configure IPv4 address, netmask length, and optional default gateway |
| `fan <value>` | Set fan power with values from 1 to 100 | | `fan` | Show current fan settings and sensors' measurements |
| `fan auto` | Enable automatic fan speed control | | `fan <value>` | Set fan power with values from 1 to 100 |
| `fcurve <a> <b> <c>` | Set fan controller curve coefficients (see *Fan control* section) | | `fan auto` | Enable automatic fan speed control |
| `fcurve default` | Set fan controller curve coefficients to defaults (see *Fan control* section) | | `fcurve <a> <b> <c>` | Set fan controller curve coefficients (see *Fan control* section) |
| `hwrev` | Show hardware revision, and settings related to it | | `fcurve default` | Set fan controller curve coefficients to defaults (see *Fan control* section) |
| `hwrev` | Show hardware revision, and settings related to it |
## USB ## USB

View File

@ -35,6 +35,7 @@ pub struct ChannelState {
pub pid_engaged: bool, pub pid_engaged: bool,
pub pid: pid::Controller, pub pid: pid::Controller,
pub sh: sh::Parameters, pub sh: sh::Parameters,
pub polarity_swapped: bool,
} }
impl ChannelState { impl ChannelState {
@ -51,6 +52,7 @@ impl ChannelState {
pid_engaged: false, pid_engaged: false,
pid: pid::Controller::new(pid::Parameters::default()), pid: pid::Controller::new(pid::Parameters::default()),
sh: sh::Parameters::default(), sh: sh::Parameters::default(),
polarity_swapped: false,
} }
} }

View File

@ -157,7 +157,11 @@ impl Channels {
} }
pub fn set_i(&mut self, channel: usize, i_set: ElectricCurrent) -> ElectricCurrent { pub fn set_i(&mut self, channel: usize, i_set: ElectricCurrent) -> ElectricCurrent {
let i_set = i_set.min(MAX_TEC_I).max(-MAX_TEC_I); let mut i_set = i_set.min(MAX_TEC_I).max(-MAX_TEC_I);
self.channel_state(channel).i_set = i_set;
if self.channel_state(channel).polarity_swapped {
i_set = -i_set;
}
let vref_meas = match channel.into() { let vref_meas = match channel.into() {
0 => self.channel0.vref_meas, 0 => self.channel0.vref_meas,
1 => self.channel1.vref_meas, 1 => self.channel1.vref_meas,
@ -168,7 +172,6 @@ impl Channels {
let voltage = i_set * 10.0 * r_sense + center_point; let voltage = i_set * 10.0 * r_sense + center_point;
let voltage = self.set_dac(channel, voltage); let voltage = self.set_dac(channel, voltage);
let i_set = (voltage - center_point) / (10.0 * r_sense); let i_set = (voltage - center_point) / (10.0 * r_sense);
self.channel_state(channel).i_set = i_set;
i_set i_set
} }
@ -386,18 +389,31 @@ impl Channels {
} }
pub fn get_max_i_pos(&mut self, channel: usize) -> (ElectricCurrent, ElectricCurrent) { pub fn get_max_i_pos(&mut self, channel: usize) -> (ElectricCurrent, ElectricCurrent) {
let duty = self.get_pwm(channel, PwmPin::MaxIPos); let duty = if self.channel_state(channel).polarity_swapped {
self.get_pwm(channel, PwmPin::MaxINeg)
} else {
self.get_pwm(channel, PwmPin::MaxIPos)
};
(duty * MAX_TEC_I_DUTY_TO_CURRENT_RATE, MAX_TEC_I) (duty * MAX_TEC_I_DUTY_TO_CURRENT_RATE, MAX_TEC_I)
} }
pub fn get_max_i_neg(&mut self, channel: usize) -> (ElectricCurrent, ElectricCurrent) { pub fn get_max_i_neg(&mut self, channel: usize) -> (ElectricCurrent, ElectricCurrent) {
let duty = self.get_pwm(channel, PwmPin::MaxINeg); let duty = if self.channel_state(channel).polarity_swapped {
self.get_pwm(channel, PwmPin::MaxIPos)
} else {
self.get_pwm(channel, PwmPin::MaxINeg)
};
(duty * MAX_TEC_I_DUTY_TO_CURRENT_RATE, MAX_TEC_I) (duty * MAX_TEC_I_DUTY_TO_CURRENT_RATE, MAX_TEC_I)
} }
// Get current passing through TEC // Get current passing through TEC
pub fn get_tec_i(&mut self, channel: usize) -> ElectricCurrent { pub fn get_tec_i(&mut self, channel: usize) -> ElectricCurrent {
(self.adc_read(channel, PinsAdcReadTarget::ITec, 16) - self.adc_read(channel, PinsAdcReadTarget::VREF, 16)) / ElectricalResistance::new::<ohm>(0.4) let tec_i = (self.adc_read(channel, PinsAdcReadTarget::ITec, 16) - self.adc_read(channel, PinsAdcReadTarget::VREF, 16)) / ElectricalResistance::new::<ohm>(0.4);
if self.channel_state(channel).polarity_swapped {
-tec_i
} else {
tec_i
}
} }
// Get voltage across TEC // Get voltage across TEC
@ -442,14 +458,22 @@ impl Channels {
pub fn set_max_i_pos(&mut self, channel: usize, max_i_pos: ElectricCurrent) -> (ElectricCurrent, ElectricCurrent) { pub fn set_max_i_pos(&mut self, channel: usize, max_i_pos: ElectricCurrent) -> (ElectricCurrent, ElectricCurrent) {
let max = ElectricCurrent::new::<ampere>(3.0); let max = ElectricCurrent::new::<ampere>(3.0);
let duty = (max_i_pos.min(MAX_TEC_I).max(ElectricCurrent::zero()) / MAX_TEC_I_DUTY_TO_CURRENT_RATE).get::<ratio>(); let duty = (max_i_pos.min(MAX_TEC_I).max(ElectricCurrent::zero()) / MAX_TEC_I_DUTY_TO_CURRENT_RATE).get::<ratio>();
let duty = self.set_pwm(channel, PwmPin::MaxIPos, duty); let duty = if self.channel_state(channel).polarity_swapped {
self.set_pwm(channel, PwmPin::MaxINeg, duty)
} else {
self.set_pwm(channel, PwmPin::MaxIPos, duty)
};
(duty * MAX_TEC_I_DUTY_TO_CURRENT_RATE, max) (duty * MAX_TEC_I_DUTY_TO_CURRENT_RATE, max)
} }
pub fn set_max_i_neg(&mut self, channel: usize, max_i_neg: ElectricCurrent) -> (ElectricCurrent, ElectricCurrent) { pub fn set_max_i_neg(&mut self, channel: usize, max_i_neg: ElectricCurrent) -> (ElectricCurrent, ElectricCurrent) {
let max = ElectricCurrent::new::<ampere>(3.0); let max = ElectricCurrent::new::<ampere>(3.0);
let duty = (max_i_neg.min(MAX_TEC_I).max(ElectricCurrent::zero()) / MAX_TEC_I_DUTY_TO_CURRENT_RATE).get::<ratio>(); let duty = (max_i_neg.min(MAX_TEC_I).max(ElectricCurrent::zero()) / MAX_TEC_I_DUTY_TO_CURRENT_RATE).get::<ratio>();
let duty = self.set_pwm(channel, PwmPin::MaxINeg, duty); let duty = if self.channel_state(channel).polarity_swapped {
self.set_pwm(channel, PwmPin::MaxIPos, duty)
} else {
self.set_pwm(channel, PwmPin::MaxINeg, duty)
};
(duty * MAX_TEC_I_DUTY_TO_CURRENT_RATE, max) (duty * MAX_TEC_I_DUTY_TO_CURRENT_RATE, max)
} }
@ -469,6 +493,7 @@ impl Channels {
temperature: state.get_temperature() temperature: state.get_temperature()
.map(|temperature| temperature.get::<degree_celsius>()), .map(|temperature| temperature.get::<degree_celsius>()),
pid_engaged: state.pid_engaged, pid_engaged: state.pid_engaged,
current_swapped: state.polarity_swapped,
i_set, i_set,
dac_value, dac_value,
dac_feedback: self.adc_read(channel, PinsAdcReadTarget::DacVfb, 1), dac_feedback: self.adc_read(channel, PinsAdcReadTarget::DacVfb, 1),
@ -567,6 +592,7 @@ pub struct Report {
sens: Option<ElectricalResistance>, sens: Option<ElectricalResistance>,
temperature: Option<f64>, temperature: Option<f64>,
pid_engaged: bool, pid_engaged: bool,
current_swapped: bool,
i_set: ElectricCurrent, i_set: ElectricCurrent,
dac_value: ElectricPotential, dac_value: ElectricPotential,
dac_feedback: ElectricPotential, dac_feedback: ElectricPotential,

View File

@ -181,6 +181,15 @@ impl Handler {
Ok(Handler::Handled) Ok(Handler::Handled)
} }
fn swap_polarity (socket: &mut TcpSocket, channels: &mut Channels, channel: usize, swapped: bool) -> Result<Handler, Error> {
channels.channel_state(channel).polarity_swapped = swapped;
let channel_state = channels.channel_state(channel);
let i_set = channel_state.i_set;
channels.set_i(channel, i_set);
send_line(socket, b"{}");
Ok(Handler::Handled)
}
fn set_pwm (socket: &mut TcpSocket, channels: &mut Channels, channel: usize, pin: PwmPin, value: f64) -> Result<Handler, Error> { fn set_pwm (socket: &mut TcpSocket, channels: &mut Channels, channel: usize, pin: PwmPin, value: f64) -> Result<Handler, Error> {
match pin { match pin {
PwmPin::ISet => { PwmPin::ISet => {
@ -424,6 +433,7 @@ impl Handler {
Command::Show(ShowCommand::PostFilter) => Handler::show_post_filter(socket, channels), Command::Show(ShowCommand::PostFilter) => Handler::show_post_filter(socket, channels),
Command::Show(ShowCommand::Ipv4) => Handler::show_ipv4(socket, ipv4_config), Command::Show(ShowCommand::Ipv4) => Handler::show_ipv4(socket, ipv4_config),
Command::PwmPid { channel } => Handler::engage_pid(socket, channels, channel), Command::PwmPid { channel } => Handler::engage_pid(socket, channels, channel),
Command::PwmPolaritySwapped { channel, swapped } => Handler::swap_polarity(socket, channels, channel, swapped),
Command::Pwm { channel, pin, value } => Handler::set_pwm(socket, channels, channel, pin, value), Command::Pwm { channel, pin, value } => Handler::set_pwm(socket, channels, channel, pin, value),
Command::CenterPoint { channel, center } => Handler::set_center_point(socket, channels, channel, center), Command::CenterPoint { channel, center } => Handler::set_center_point(socket, channels, channel, center),
Command::Pid { channel, parameter, value } => Handler::set_pid(socket, channels, channel, parameter, value), Command::Pid { channel, parameter, value } => Handler::set_pid(socket, channels, channel, parameter, value),

View File

@ -159,6 +159,10 @@ pub enum Command {
PwmPid { PwmPid {
channel: usize, channel: usize,
}, },
PwmPolaritySwapped {
channel: usize,
swapped: bool,
},
CenterPoint { CenterPoint {
channel: usize, channel: usize,
center: CenterPoint, center: CenterPoint,
@ -239,6 +243,12 @@ fn off_on(input: &[u8]) -> IResult<&[u8], bool> {
))(input) ))(input)
} }
fn boolean(input: &[u8]) -> IResult<&[u8], bool> {
alt((value(false, tag("false")),
value(true, tag("true"))
))(input)
}
fn channel(input: &[u8]) -> IResult<&[u8], usize> { fn channel(input: &[u8]) -> IResult<&[u8], usize> {
map(one_of("01"), |c| (c as usize) - ('0' as usize))(input) map(one_of("01"), |c| (c as usize) - ('0' as usize))(input)
} }
@ -321,6 +331,16 @@ fn pwm_pid(input: &[u8]) -> IResult<&[u8], ()> {
value((), tag("pid"))(input) value((), tag("pid"))(input)
} }
fn pwm_polarity_swapped(input: &[u8]) -> IResult<&[u8], bool> {
preceded(
tag("polarity_swapped"),
preceded(
whitespace,
boolean,
)
)(input)
}
fn pwm(input: &[u8]) -> IResult<&[u8], Result<Command, Error>> { fn pwm(input: &[u8]) -> IResult<&[u8], Result<Command, Error>> {
let (input, _) = tag("pwm")(input)?; let (input, _) = tag("pwm")(input)?;
alt(( alt((
@ -333,6 +353,10 @@ fn pwm(input: &[u8]) -> IResult<&[u8], Result<Command, Error>> {
let (input, ()) = pwm_pid(input)?; let (input, ()) = pwm_pid(input)?;
Ok((input, Ok(Command::PwmPid { channel }))) Ok((input, Ok(Command::PwmPid { channel })))
}, },
|input| {
let (input, swapped) = pwm_polarity_swapped(input)?;
Ok((input, Ok(Command::PwmPolaritySwapped { channel, swapped })))
},
|input| { |input| {
let (input, config) = pwm_setup(input)?; let (input, config) = pwm_setup(input)?;
match config { match config {