Compare commits

...

3 Commits

Author SHA1 Message Date
Astro 87287e83b3 update cargoSha256 2020-09-28 13:16:54 +02:00
Astro 407c0998af ad7172: set output data rate to 10 Hz 2020-09-28 01:24:32 +02:00
Astro 9e5a58cafd main: switch reports to json serialization 2020-09-27 23:58:03 +02:00
6 changed files with 107 additions and 37 deletions

13
Cargo.lock generated
View File

@ -353,6 +353,16 @@ dependencies = [
"serde_derive", "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]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.116" version = "1.0.116"
@ -457,6 +467,7 @@ dependencies = [
"cortex-m-log", "cortex-m-log",
"cortex-m-rt", "cortex-m-rt",
"eeprom24x", "eeprom24x",
"heapless",
"log", "log",
"nb 0.1.3", "nb 0.1.3",
"nom", "nom",
@ -465,6 +476,7 @@ dependencies = [
"panic-semihosting", "panic-semihosting",
"postcard", "postcard",
"serde", "serde",
"serde-json-core",
"smoltcp", "smoltcp",
"stm32-eth", "stm32-eth",
"stm32f4xx-hal", "stm32f4xx-hal",
@ -492,6 +504,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8bb593f5252356bfb829112f8fca2d0982d48588d2d6bb5a92553b0dfc4c9aba" checksum = "8bb593f5252356bfb829112f8fca2d0982d48588d2d6bb5a92553b0dfc4c9aba"
dependencies = [ dependencies = [
"num-traits", "num-traits",
"serde",
"typenum", "typenum",
] ]

View File

@ -31,10 +31,12 @@ num-traits = { version = "0.2", default-features = false, features = ["libm"] }
usb-device = "0.2" usb-device = "0.2"
usbd-serial = "0.1" usbd-serial = "0.1"
nb = "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" eeprom24x = "0.3"
serde = { version = "1.0", default-features = false, features = ["derive"] } serde = { version = "1.0", default-features = false, features = ["derive"] }
postcard = "0.5.1" postcard = "0.5.1"
heapless = "0.5"
serde-json-core = "0.1"
[patch.crates-io] [patch.crates-io]
stm32f4xx-hal = { git = "https://github.com/stm32-rs/stm32f4xx-hal.git" } stm32f4xx-hal = { git = "https://github.com/stm32-rs/stm32f4xx-hal.git" }

View File

@ -1 +1 @@
"05drvrap04amg5rdcniz8zj191pilwjjb5vkc66xhq16c8bj1xsj" "12mv48v1x4z8f089i0sxhnl4l8nhijp16y4j9v55cnqqgd41y84v"

View File

@ -90,6 +90,8 @@ impl<SPI: Transfer<u8, Error = E>, NSS: OutputPin, E: fmt::Debug> Adc<SPI, NSS>
data.set_enh_filt_en(true); data.set_enh_filt_en(true);
data.set_enh_filt(PostFilter::F16SPS); data.set_enh_filt(PostFilter::F16SPS);
data.set_order(DigitalFilterOrder::Sinc5Sinc1); data.set_order(DigitalFilterOrder::Sinc5Sinc1);
// output data rate: 10 Hz
data.set_odr(0b10011);
})?; })?;
self.update_reg(&regs::Channel { index }, |data| { self.update_reg(&regs::Channel { index }, |data| {
data.set_setup(index); data.set_setup(index);

View File

@ -1,11 +1,13 @@
use stm32f4xx_hal::hal; use serde::{Serialize, Deserialize};
use smoltcp::time::Instant; use smoltcp::time::Instant;
use stm32f4xx_hal::hal;
use uom::si::{ use uom::si::{
f64::{ElectricCurrent, ElectricPotential, ElectricalResistance}, f64::{ElectricCurrent, ElectricPotential, ElectricalResistance},
electric_potential::{millivolt, volt}, electric_potential::{millivolt, volt},
electric_current::ampere, electric_current::ampere,
electrical_resistance::ohm, electrical_resistance::ohm,
ratio::ratio, ratio::ratio,
thermodynamic_temperature::degree_celsius,
}; };
use crate::{ use crate::{
ad5680, ad5680,
@ -408,4 +410,51 @@ impl Channels {
let duty = self.set_pwm(channel, PwmPin::MaxINeg, duty); let duty = self.set_pwm(channel, PwmPin::MaxINeg, duty);
(duty * max, max) (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::<ohm>(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::<degree_celsius>()),
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<ElectricPotential>,
sens: Option<ElectricalResistance>,
temperature: Option<f64>,
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<u8, heapless::consts::U320>;
impl Report {
pub fn to_json(&self) -> Result<JsonBuffer, serde_json_core::ser::Error> {
serde_json_core::to_vec(self)
}
} }

View File

@ -9,7 +9,7 @@ use panic_abort as _;
#[cfg(all(feature = "semihosting", not(test)))] #[cfg(all(feature = "semihosting", not(test)))]
use panic_semihosting as _; use panic_semihosting as _;
use log::{info, warn}; use log::{error, info, warn};
use core::fmt::Write; use core::fmt::Write;
use cortex_m::asm::wfi; use cortex_m::asm::wfi;
@ -23,6 +23,7 @@ use stm32f4xx_hal::{
}; };
use smoltcp::{ use smoltcp::{
time::Instant, time::Instant,
socket::TcpSocket,
wire::EthernetAddress, wire::EthernetAddress,
}; };
use uom::{ use uom::{
@ -79,6 +80,37 @@ pub const EEPROM_SIZE: usize = 128;
const TCP_PORT: u16 = 23; 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 /// Initialization and main loop
#[cfg(not(test))] #[cfg(not(test))]
#[entry] #[entry]
@ -171,29 +203,7 @@ fn main() -> ! {
} }
Command::Show(ShowCommand::Input) => { Command::Show(ShowCommand::Input) => {
for channel in 0..CHANNELS { for channel in 0..CHANNELS {
if let Some(adc_input) = channels.channel_state(channel).get_adc() { report_to(channel, &mut channels, &mut socket);
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::<ohm>(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);
}
} }
} }
Command::Show(ShowCommand::Pid) => { Command::Show(ShowCommand::Pid) => {
@ -479,17 +489,11 @@ fn main() -> ! {
Err(_) => Err(_) =>
socket.close(), socket.close(),
} }
} else if socket.can_send() && socket.send_capacity() - socket.send_queue() > 256 { } else if socket.can_send() {
while let Some(channel) = session.is_report_pending() { if let Some(channel) = session.is_report_pending() {
let state = &mut channels.channel_state(usize::from(channel)); if report_to(channel, &mut channels, &mut socket) {
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(|_| {
session.mark_report_sent(channel); session.mark_report_sent(channel);
}); }
} }
} }
}); });