diff --git a/src/channels.rs b/src/channels.rs index 1849fef..4291724 100644 --- a/src/channels.rs +++ b/src/channels.rs @@ -1,4 +1,4 @@ -use serde::{Serialize, Deserialize}; +use serde::{Serialize, Serializer}; use smoltcp::time::Instant; use stm32f4xx_hal::hal; use uom::si::{ @@ -438,9 +438,22 @@ impl Channels { pid_output, } } + + pub fn pwm_summary(&mut self, channel: usize) -> PwmSummary { + PwmSummary { + channel, + center: CenterPointJson(self.channel_state(channel).center.clone()), + i_set: self.get_i(channel).into(), + max_v: self.get_max_v(channel).into(), + max_i_pos: self.get_max_i_pos(channel).into(), + max_i_neg: self.get_max_i_neg(channel).into(), + } + } } -#[derive(Serialize, Deserialize)] +type JsonBuffer = heapless::Vec; + +#[derive(Serialize)] pub struct Report { channel: usize, time: i64, @@ -457,14 +470,58 @@ pub struct Report { pid_output: Option, } -type JsonBuffer = heapless::Vec; - impl Report { pub fn to_json(&self) -> Result { serde_json_core::to_vec(self) } } +pub struct CenterPointJson(CenterPoint); + +// used in JSON encoding, not for config +impl Serialize for CenterPointJson { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match self.0 { + CenterPoint::Vref => + serializer.serialize_str("vref"), + CenterPoint::Override(vref) => + serializer.serialize_f32(vref), + } + } +} + +#[derive(Serialize)] +pub struct PwmSummaryField { + value: T, + max: T, +} + +impl From<(T, T)> for PwmSummaryField { + fn from((value, max): (T, T)) -> Self { + PwmSummaryField { value, max } + } +} + +#[derive(Serialize)] +pub struct PwmSummary { + channel: usize, + center: CenterPointJson, + i_set: PwmSummaryField, + max_v: PwmSummaryField, + max_i_pos: PwmSummaryField, + max_i_neg: PwmSummaryField, +} + +impl PwmSummary { + pub fn to_json(&self) -> Result { + serde_json_core::to_vec(self) + } +} + + #[cfg(test)] mod test { use super::*; @@ -491,4 +548,34 @@ mod test { assert_eq!(buf[0], b'{'); assert_eq!(buf[buf.len() - 1], b'}'); } + + #[test] + fn pwm_summary_to_json() { + let value = 1.0 / 1.1; + let max = 5.0 / 1.1; + + let pwm_summary = PwmSummary { + channel: 0, + center: CenterPoint::Vref, + i_set: PwmSummaryField { + value: ElectricCurrent::new::(value), + max: ElectricCurrent::new::(max), + }, + max_v: PwmSummaryField { + value: ElectricPotential::new::(value), + max: ElectricPotential::new::(max), + }, + max_i_pos: PwmSummaryField { + value: ElectricCurrent::new::(value), + max: ElectricCurrent::new::(max), + }, + max_i_neg: PwmSummaryField { + value: ElectricCurrent::new::(value), + max: ElectricCurrent::new::(max), + }, + }; + let buf = pwm_summary.to_json().unwrap(); + assert_eq!(buf[0], b'{'); + assert_eq!(buf[buf.len() - 1], b'}'); + } } diff --git a/src/main.rs b/src/main.rs index 3b1a08a..53f8b12 100644 --- a/src/main.rs +++ b/src/main.rs @@ -56,7 +56,7 @@ use server::Server; mod session; use session::{Session, SessionOutput}; mod command_parser; -use command_parser::{CenterPoint, Command, ShowCommand, PwmPin}; +use command_parser::{Command, ShowCommand, PwmPin}; mod timer; mod pid; mod steinhart_hart; @@ -80,36 +80,42 @@ pub const EEPROM_SIZE: usize = 128; const TCP_PORT: u16 = 23; -fn report_to(channel: usize, channels: &mut Channels, socket: &mut TcpSocket) -> bool { +fn send_line(socket: &mut TcpSocket, data: &[u8]) -> bool { let send_free = socket.send_capacity() - socket.send_queue(); - match channels.report(channel).to_json() { - Ok(buf) if buf.len() > send_free + 1 => { - // Not enough buffer space, skip report for now - warn!( - "TCP socket has only {}/{} needed {}", - send_free + 1, socket.send_capacity(), buf.len(), - ); - } - Ok(buf) => { - match socket.send_slice(&buf) { - Ok(sent) if sent == buf.len() => { - let _ = socket.send_slice(b"\n"); - // success - return true - } - Ok(sent) => - warn!("sent only {}/{} bytes of report", sent, buf.len()), - Err(e) => - error!("error sending report: {:?}", e), + if data.len() > send_free + 1 { + // Not enough buffer space, skip report for now + warn!( + "TCP socket has only {}/{} needed {}", + send_free + 1, socket.send_capacity(), data.len(), + ); + } else { + match socket.send_slice(&data) { + Ok(sent) if sent == data.len() => { + let _ = socket.send_slice(b"\n"); + // success + return true } + Ok(sent) => + warn!("sent only {}/{} bytes", sent, data.len()), + Err(e) => + error!("error sending line: {:?}", e), } - Err(e) => - error!("unable to serialize report: {:?}", e), } // not success false } +fn report_to(channel: usize, channels: &mut Channels, socket: &mut TcpSocket) -> bool { + match channels.report(channel).to_json() { + Ok(buf) => + send_line(socket, &buf[..]), + Err(e) => { + error!("unable to serialize report: {:?}", e); + false + } + } +} + /// Initialization and main loop #[cfg(not(test))] #[entry] @@ -207,26 +213,9 @@ fn main() -> ! { } Command::Show(ShowCommand::Pid) => { for channel in 0..CHANNELS { - let send_free = socket.send_capacity() - socket.send_queue(); match channels.channel_state(channel).pid.summary(channel).to_json() { - Ok(buf) if buf.len() > send_free + 1 => { - // Not enough buffer space, skip report for now - warn!( - "TCP socket has only {}/{} needed {}", - send_free + 1, socket.send_capacity(), buf.len(), - ); - } Ok(buf) => { - match socket.send_slice(&buf) { - Ok(sent) if sent == buf.len() => { - let _ = socket.send_slice(b"\n"); - // success - } - Ok(sent) => - warn!("sent only {}/{} bytes of summary", sent, buf.len()), - Err(e) => - error!("error sending summary: {:?}", e), - } + send_line(&mut socket, &buf); } Err(e) => error!("unable to serialize pid summary: {:?}", e), @@ -235,52 +224,14 @@ 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 _ = 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, - ); + match channels.pwm_summary(channel).to_json() { + Ok(buf) => { + send_line(&mut socket, &buf); } + Err(e) => + error!("unable to serialize pwm summary: {:?}", e), } - let max_v = channels.get_max_v(channel); - let _ = writeln!( - socket, "- max_v={:.3} / {:.3}", - max_v.0.into_format_args(volt, Abbreviation), - max_v.1.into_format_args(volt, Abbreviation), - ); - let max_i_pos = channels.get_max_i_pos(channel); - let _ = writeln!( - socket, "- max_i_pos={:.3} / {:.3}", - max_i_pos.0.into_format_args(ampere, Abbreviation), - max_i_pos.1.into_format_args(ampere, Abbreviation), - ); - let max_i_neg = channels.get_max_i_neg(channel); - let _ = writeln!( - socket, "- max_i_neg={:.3} / {:.3}", - max_i_neg.0.into_format_args(ampere, Abbreviation), - max_i_neg.1.into_format_args(ampere, Abbreviation), - ); } - let _ = writeln!(socket, ""); } Command::Show(ShowCommand::SteinhartHart) => { for channel in 0..CHANNELS { diff --git a/src/pid.rs b/src/pid.rs index 5ec8d56..543e6e7 100644 --- a/src/pid.rs +++ b/src/pid.rs @@ -96,7 +96,7 @@ impl Controller { } } -type JsonBuffer = heapless::Vec; +type JsonBuffer = heapless::Vec; #[derive(Clone, Serialize, Deserialize)] pub struct Summary {