diff --git a/Cargo.lock b/Cargo.lock index 72a077b..43583fe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -353,6 +353,16 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde-json-core" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf406405ada9ef326ca78677324ac66994ff348fc48a16030be08caeed29825" +dependencies = [ + "heapless", + "serde", +] + [[package]] name = "serde_derive" version = "1.0.116" @@ -457,6 +467,7 @@ dependencies = [ "cortex-m-log", "cortex-m-rt", "eeprom24x", + "heapless", "log", "nb 0.1.3", "nom", @@ -465,6 +476,7 @@ dependencies = [ "panic-semihosting", "postcard", "serde", + "serde-json-core", "smoltcp", "stm32-eth", "stm32f4xx-hal", @@ -492,6 +504,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8bb593f5252356bfb829112f8fca2d0982d48588d2d6bb5a92553b0dfc4c9aba" dependencies = [ "num-traits", + "serde", "typenum", ] diff --git a/Cargo.toml b/Cargo.toml index ff16d02..a818298 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,10 +31,12 @@ num-traits = { version = "0.2", default-features = false, features = ["libm"] } usb-device = "0.2" usbd-serial = "0.1" nb = "0.1" -uom = { version = "0.29", default-features = false, features = ["autoconvert", "si", "f64"] } +uom = { version = "0.29", default-features = false, features = ["autoconvert", "si", "f64", "use_serde"] } eeprom24x = "0.3" serde = { version = "1.0", default-features = false, features = ["derive"] } postcard = "0.5.1" +heapless = "0.5" +serde-json-core = "0.1" [patch.crates-io] stm32f4xx-hal = { git = "https://github.com/stm32-rs/stm32f4xx-hal.git" } diff --git a/src/channels.rs b/src/channels.rs index 9e38170..f7bda93 100644 --- a/src/channels.rs +++ b/src/channels.rs @@ -1,11 +1,13 @@ -use stm32f4xx_hal::hal; +use serde::{Serialize, Deserialize}; use smoltcp::time::Instant; +use stm32f4xx_hal::hal; use uom::si::{ f64::{ElectricCurrent, ElectricPotential, ElectricalResistance}, electric_potential::{millivolt, volt}, electric_current::ampere, electrical_resistance::ohm, ratio::ratio, + thermodynamic_temperature::degree_celsius, }; use crate::{ ad5680, @@ -408,4 +410,51 @@ impl Channels { let duty = self.set_pwm(channel, PwmPin::MaxINeg, duty); (duty * max, max) } + + pub fn report(&mut self, channel: usize) -> Report { + let vref = self.channel_state(channel).vref; + let (i_set, _) = self.get_i(channel); + let i_tec = self.read_itec(channel); + let tec_i = (i_tec - vref) / ElectricalResistance::new::(0.4); + let state = self.channel_state(channel); + Report { + channel, + time: state.adc_time.total_millis(), + adc: state.get_adc(), + sens: state.get_sens(), + temperature: state.get_temperature() + .map(|temperature| temperature.get::()), + pid_engaged: state.pid_engaged, + i_set, + vref, + dac_feedback: self.read_dac_feedback(channel), + i_tec, + tec_i, + tec_u_meas: self.read_tec_u_meas(channel), + } + } +} + +#[derive(Serialize, Deserialize)] +pub struct Report { + channel: usize, + time: i64, + adc: Option, + sens: Option, + temperature: Option, + pid_engaged: bool, + i_set: ElectricCurrent, + vref: ElectricPotential, + dac_feedback: ElectricPotential, + i_tec: ElectricPotential, + tec_i: ElectricCurrent, + tec_u_meas: ElectricPotential, +} + +type JsonBuffer = heapless::Vec; + +impl Report { + pub fn to_json(&self) -> Result { + serde_json_core::to_vec(self) + } } diff --git a/src/main.rs b/src/main.rs index 641b2e4..643576e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,7 +9,7 @@ use panic_abort as _; #[cfg(all(feature = "semihosting", not(test)))] use panic_semihosting as _; -use log::{info, warn}; +use log::{error, info, warn}; use core::fmt::Write; use cortex_m::asm::wfi; @@ -23,6 +23,7 @@ use stm32f4xx_hal::{ }; use smoltcp::{ time::Instant, + socket::TcpSocket, wire::EthernetAddress, }; use uom::{ @@ -79,6 +80,37 @@ pub const EEPROM_SIZE: usize = 128; const TCP_PORT: u16 = 23; +fn report_to(channel: usize, channels: &mut Channels, socket: &mut TcpSocket) -> 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 + // TODO: session.mark_report_sent(channel); + } + Ok(sent) => + warn!("sent only {}/{} bytes of report", sent, buf.len()), + Err(e) => + error!("error sending report: {:?}", e), + } + } + Err(e) => + error!("unable to serialize report: {:?}", e), + } + // not success + false +} + /// Initialization and main loop #[cfg(not(test))] #[entry] @@ -171,29 +203,7 @@ fn main() -> ! { } Command::Show(ShowCommand::Input) => { for channel in 0..CHANNELS { - if let Some(adc_input) = channels.channel_state(channel).get_adc() { - let vref = channels.channel_state(channel).vref; - let dac_feedback = channels.read_dac_feedback(channel); - - let itec = channels.read_itec(channel); - let tec_i = (itec - vref) / ElectricalResistance::new::(0.4); - - let tec_u_meas = channels.read_tec_u_meas(channel); - - let state = channels.channel_state(channel); - let _ = writeln!( - socket, "channel {}: t={:.0} adc{}={:.3} adc_r={:?} vref={:.3} dac_feedback={:.3} itec={:.3} tec={:.3} tec_u_meas={:.3} r={:.3}", - channel, state.adc_time, - channel, adc_input.into_format_args(volt, Abbreviation), - state.get_sens().map(|sens| sens.into_format_args(ohm, Abbreviation)), - vref.into_format_args(volt, Abbreviation), dac_feedback.into_format_args(volt, Abbreviation), - itec.into_format_args(volt, Abbreviation), tec_i.into_format_args(ampere, Abbreviation), - tec_u_meas.into_format_args(volt, Abbreviation), - ((tec_u_meas - vref) / tec_i).into_format_args(ohm, Abbreviation), - ); - } else { - let _ = writeln!(socket, "channel {}: no adc input", channel); - } + report_to(channel, &mut channels, &mut socket); } } Command::Show(ShowCommand::Pid) => { @@ -479,17 +489,11 @@ fn main() -> ! { Err(_) => socket.close(), } - } else if socket.can_send() && socket.send_capacity() - socket.send_queue() > 256 { - while let Some(channel) = session.is_report_pending() { - let state = &mut channels.channel_state(usize::from(channel)); - let adc_data = state.adc_data.unwrap_or(0); - let _ = writeln!( - socket, "t={} raw{}=0x{:06X} value={}", - state.adc_time, channel, adc_data, - state.get_adc().unwrap().into_format_args(volt, Abbreviation), - ).map(|_| { + } else if socket.can_send() { + if let Some(channel) = session.is_report_pending() { + if report_to(channel, &mut channels, &mut socket) { session.mark_report_sent(channel); - }); + } } } });