From 6473b27539c33866a36a96680bbea414c1a61216 Mon Sep 17 00:00:00 2001 From: topquark12 Date: Wed, 2 Jun 2021 15:35:50 +0800 Subject: [PATCH] main refactor: initial working prototype --- src/command_handler.rs | 312 +++++++++++++++++++++++++++++++++++++++++ src/main.rs | 248 ++------------------------------ 2 files changed, 327 insertions(+), 233 deletions(-) create mode 100644 src/command_handler.rs diff --git a/src/command_handler.rs b/src/command_handler.rs new file mode 100644 index 0000000..66e1cf9 --- /dev/null +++ b/src/command_handler.rs @@ -0,0 +1,312 @@ +use crate::{CHANNEL_CONFIG_KEY, ad7172, channels::{self, CHANNELS}, command_parser::PwmPin, config::ChannelConfig, dfu, flash_store::{FlashStore}, session::Session}; +use channels::Channels; +use smoltcp::socket::TcpSocket; +use log::{error, warn}; +use core::fmt::Write; +use crate::net; +use crate::command_parser; +use command_parser::Ipv4Config; +use command_parser::Command; +use command_parser::ShowCommand; +use crate::leds::Leds; +use uom::{ + si::{ + f64::{ + ElectricCurrent, + ElectricPotential, + ElectricalResistance, + ThermodynamicTemperature, + }, + electric_current::ampere, + electric_potential::volt, + electrical_resistance::ohm, + thermodynamic_temperature::degree_celsius, + }, +}; + +#[derive(Debug, Clone, PartialEq)] +pub enum Handler { + Handled, + CloseSocket, + NewIPV4(Ipv4Config), + Reset, +} + +#[derive(Clone, Debug, PartialEq)] +pub enum Error { + ParseFloat, +} + +fn send_line(socket: &mut TcpSocket, data: &[u8]) -> bool { + let send_free = socket.send_capacity() - socket.send_queue(); + if data.len() > send_free + 1 { + // Not enough buffer space, skip report for now, + // instead of sending incomplete line + 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), + } + } + // not success + false +} + +impl Handler { + + pub fn handle_command (command: Command, socket: &mut TcpSocket, channels: &mut Channels, session: &Session, leds: &mut Leds, store: &mut FlashStore, ipv4_config: &mut Ipv4Config) -> Result { + match command { + Command::Quit => + // socket.close(), + Ok(Handler::CloseSocket), + + Command::Reporting(_reporting) => { + // handled by session + send_line(socket, b"{}"); + Ok(Handler::Handled) + } + Command::Show(ShowCommand::Reporting) => { + let _ = writeln!(socket, "{{ \"report\": {:?} }}", session.reporting()); + Ok(Handler::Handled) + } + Command::Show(ShowCommand::Input) => { + match channels.reports_json() { + Ok(buf) => { + send_line(socket, &buf[..]); + } + Err(e) => { + error!("unable to serialize report: {:?}", e); + let _ = writeln!(socket, "{{\"error\":\"{:?}\"}}", e); + + } + } + Ok(Handler::Handled) + } + Command::Show(ShowCommand::Pid) => { + match channels.pid_summaries_json() { + Ok(buf) => { + send_line(socket, &buf); + } + Err(e) => { + error!("unable to serialize pid summary: {:?}", e); + let _ = writeln!(socket, "{{\"error\":\"{:?}\"}}", e); + } + } + Ok(Handler::Handled) + } + Command::Show(ShowCommand::Pwm) => { + match channels.pwm_summaries_json() { + Ok(buf) => { + send_line(socket, &buf); + } + Err(e) => { + error!("unable to serialize pwm summary: {:?}", e); + let _ = writeln!(socket, "{{\"error\":\"{:?}\"}}", e); + } + } + Ok(Handler::Handled) + } + Command::Show(ShowCommand::SteinhartHart) => { + match channels.steinhart_hart_summaries_json() { + Ok(buf) => { + send_line(socket, &buf); + } + Err(e) => { + error!("unable to serialize steinhart-hart summaries: {:?}", e); + let _ = writeln!(socket, "{{\"error\":\"{:?}\"}}", e); + } + } + Ok(Handler::Handled) + } + Command::Show(ShowCommand::PostFilter) => { + match channels.postfilter_summaries_json() { + Ok(buf) => { + send_line(socket, &buf); + } + Err(e) => { + error!("unable to serialize postfilter summary: {:?}", e); + let _ = writeln!(socket, "{{\"error\":\"{:?}\"}}", e); + } + } + Ok(Handler::Handled) + } + Command::Show(ShowCommand::Ipv4) => { + let (cidr, gateway) = net::split_ipv4_config(ipv4_config.clone()); + let _ = write!(socket, "{{\"addr\":\"{}\"", cidr); + gateway.map(|gateway| write!(socket, ",\"gateway\":\"{}\"", gateway)); + let _ = writeln!(socket, "}}"); + Ok(Handler::Handled) + } + Command::PwmPid { channel } => { + channels.channel_state(channel).pid_engaged = true; + leds.g3.on(); + send_line(socket, b"{}"); + Ok(Handler::Handled) + } + Command::Pwm { channel, pin, value } => { + match pin { + PwmPin::ISet => { + channels.channel_state(channel).pid_engaged = false; + leds.g3.off(); + let current = ElectricCurrent::new::(value); + channels.set_i(channel, current); + channels.power_up(channel); + } + PwmPin::MaxV => { + let voltage = ElectricPotential::new::(value); + channels.set_max_v(channel, voltage); + } + PwmPin::MaxIPos => { + let current = ElectricCurrent::new::(value); + channels.set_max_i_pos(channel, current); + } + PwmPin::MaxINeg => { + let current = ElectricCurrent::new::(value); + channels.set_max_i_neg(channel, current); + } + } + send_line(socket, b"{}"); + Ok(Handler::Handled) + } + 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); + } + send_line(socket, b"{}"); + Ok(Handler::Handled) + } + Command::Pid { channel, parameter, value } => { + let pid = &mut channels.channel_state(channel).pid; + use command_parser::PidParameter::*; + match parameter { + Target => + pid.target = value, + KP => + pid.parameters.kp = value as f32, + KI => + pid.update_ki(value as f32), + KD => + pid.parameters.kd = value as f32, + OutputMin => + pid.parameters.output_min = value as f32, + OutputMax => + pid.parameters.output_max = value as f32, + IntegralMin => + pid.parameters.integral_min = value as f32, + IntegralMax => + pid.parameters.integral_max = value as f32, + } + send_line(socket, b"{}"); + Ok(Handler::Handled) + } + Command::SteinhartHart { channel, parameter, value } => { + let sh = &mut channels.channel_state(channel).sh; + use command_parser::ShParameter::*; + match parameter { + T0 => sh.t0 = ThermodynamicTemperature::new::(value), + B => sh.b = value, + R0 => sh.r0 = ElectricalResistance::new::(value), + } + send_line(socket, b"{}"); + Ok(Handler::Handled) + } + Command::PostFilter { channel, rate: None } => { + channels.adc.set_postfilter(channel as u8, None).unwrap(); + send_line(socket, b"{}"); + Ok(Handler::Handled) + } + Command::PostFilter { channel, rate: Some(rate) } => { + let filter = ad7172::PostFilter::closest(rate); + match filter { + Some(filter) => { + channels.adc.set_postfilter(channel as u8, Some(filter)).unwrap(); + send_line(socket, b"{}"); + } + None => { + error!("unable to choose postfilter for rate {:.3}", rate); + send_line(socket, b"{{\"error\": \"unable to choose postfilter rate\"}}"); + } + } + Ok(Handler::Handled) + } + Command::Load { channel } => { + for c in 0..CHANNELS { + if channel.is_none() || channel == Some(c) { + match store.read_value::(CHANNEL_CONFIG_KEY[c]) { + Ok(Some(config)) => { + config.apply(channels, c); + send_line(socket, b"{}"); + } + Ok(None) => { + error!("flash config not found"); + send_line(socket, b"{{\"error\": \"flash config not found\"}}"); + } + Err(e) => { + error!("unable to load config from flash: {:?}", e); + let _ = writeln!(socket, "{{\"error\":\"{:?}\"}}", e); + } + } + } + } + Ok(Handler::Handled) + } + Command::Save { channel } => { + for c in 0..CHANNELS { + let mut store_value_buf = [0u8; 256]; + if channel.is_none() || channel == Some(c) { + let config = ChannelConfig::new(channels, c); + match store.write_value(CHANNEL_CONFIG_KEY[c], &config, &mut store_value_buf) { + Ok(()) => { + send_line(socket, b"{}"); + } + Err(e) => { + error!("unable to save channel {} config to flash: {:?}", c, e); + let _ = writeln!(socket, "{{\"error\":\"{:?}\"}}", e); + } + } + } + } + Ok(Handler::Handled) + } + Command::Ipv4(config) => { + let _ = store + .write_value("ipv4", &config, [0; 16]) + .map_err(|e| error!("unable to save ipv4 config to flash: {:?}", e)); + let new_ipv4_config = Some(config); + send_line(socket, b"{}"); + Ok(Handler::NewIPV4(new_ipv4_config.unwrap())) + } + Command::Reset => { + for i in 0..CHANNELS { + channels.power_down(i); + } + // should_reset = true; + Ok(Handler::Reset) + } + Command::Dfu => { + for i in 0..CHANNELS { + channels.power_down(i); + } + unsafe { + dfu::set_dfu_trigger(); + } + // should_reset = true; + Ok(Handler::Reset) + } + } + } +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 9a11b7d..b724ed3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,7 @@ #![cfg_attr(test, allow(unused))] // TODO: #![deny(warnings, unused)] +// use Handler::NewIPV4; #[cfg(not(any(feature = "semihosting", test)))] use panic_abort as _; #[cfg(all(feature = "semihosting", not(test)))] @@ -11,7 +12,7 @@ use panic_semihosting as _; use log::{error, info, warn}; -use core::fmt::Write; +// use core::fmt::Write; use cortex_m::asm::wfi; use cortex_m_rt::entry; use stm32f4xx_hal::{ @@ -26,20 +27,6 @@ use smoltcp::{ socket::TcpSocket, wire::EthernetAddress, }; -use uom::{ - si::{ - f64::{ - ElectricCurrent, - ElectricPotential, - ElectricalResistance, - ThermodynamicTemperature, - }, - electric_current::ampere, - electric_potential::volt, - electrical_resistance::ohm, - thermodynamic_temperature::degree_celsius, - }, -}; mod init_log; use init_log::init_log; @@ -55,7 +42,7 @@ use server::Server; mod session; use session::{Session, SessionInput}; mod command_parser; -use command_parser::{Command, Ipv4Config, PwmPin, ShowCommand}; +use command_parser::Ipv4Config; mod timer; mod pid; mod steinhart_hart; @@ -67,6 +54,8 @@ mod config; use config::ChannelConfig; mod flash_store; mod dfu; +mod command_handler; +use command_handler::Handler; const HSE: MegaHertz = MegaHertz(8); #[cfg(not(feature = "semihosting"))] @@ -149,7 +138,7 @@ fn main() -> ! { usb::State::setup(usb); let mut store = flash_store::store(dp.FLASH); - let mut store_value_buf = [0u8; 256]; + let mut channels = Channels::new(pins); for c in 0..CHANNELS { @@ -218,223 +207,16 @@ fn main() -> ! { // socket RX ring buffer wraps around, or when the command is sent as seperate TCP packets etc. // Do nothing and feed more data to the line reader in the next loop cycle. Ok(SessionInput::Nothing) => {} - Ok(SessionInput::Command(command)) => match command { - Command::Quit => - socket.close(), - Command::Reporting(_reporting) => { - // handled by session - send_line(&mut socket, b"{}"); - } - Command::Show(ShowCommand::Reporting) => { - let _ = writeln!(socket, "{{ \"report\": {:?} }}", session.reporting()); - } - Command::Show(ShowCommand::Input) => { - match channels.reports_json() { - Ok(buf) => { - send_line(&mut socket, &buf[..]); - } - Err(e) => { - error!("unable to serialize report: {:?}", e); - let _ = writeln!(socket, "{{\"error\":\"{:?}\"}}", e); - - } + Ok(SessionInput::Command(command)) => { + // let handler = Handler::handle_command(command, &mut socket, &mut channels, session, &mut leds, store, ipv4_config); + match Handler::handle_command(command, &mut socket, &mut channels, session, &mut leds, &mut store, &mut ipv4_config) { + Ok(Handler::NewIPV4(ip)) => { + new_ipv4_config = Some(ip); } - } - Command::Show(ShowCommand::Pid) => { - match channels.pid_summaries_json() { - Ok(buf) => { - send_line(&mut socket, &buf); - } - Err(e) => { - error!("unable to serialize pid summary: {:?}", e); - let _ = writeln!(socket, "{{\"error\":\"{:?}\"}}", e); - } - } - } - Command::Show(ShowCommand::Pwm) => { - match channels.pwm_summaries_json() { - Ok(buf) => { - send_line(&mut socket, &buf); - } - Err(e) => { - error!("unable to serialize pwm summary: {:?}", e); - let _ = writeln!(socket, "{{\"error\":\"{:?}\"}}", e); - } - } - } - Command::Show(ShowCommand::SteinhartHart) => { - match channels.steinhart_hart_summaries_json() { - Ok(buf) => { - send_line(&mut socket, &buf); - } - Err(e) => { - error!("unable to serialize steinhart-hart summaries: {:?}", e); - let _ = writeln!(socket, "{{\"error\":\"{:?}\"}}", e); - } - } - } - Command::Show(ShowCommand::PostFilter) => { - match channels.postfilter_summaries_json() { - Ok(buf) => { - send_line(&mut socket, &buf); - } - Err(e) => { - error!("unable to serialize postfilter summary: {:?}", e); - let _ = writeln!(socket, "{{\"error\":\"{:?}\"}}", e); - } - } - } - Command::Show(ShowCommand::Ipv4) => { - let (cidr, gateway) = net::split_ipv4_config(ipv4_config.clone()); - let _ = write!(socket, "{{\"addr\":\"{}\"", cidr); - gateway.map(|gateway| write!(socket, ",\"gateway\":\"{}\"", gateway)); - let _ = writeln!(socket, "}}"); - } - Command::PwmPid { channel } => { - channels.channel_state(channel).pid_engaged = true; - leds.g3.on(); - send_line(&mut socket, b"{}"); - } - Command::Pwm { channel, pin, value } => { - match pin { - PwmPin::ISet => { - channels.channel_state(channel).pid_engaged = false; - leds.g3.off(); - let current = ElectricCurrent::new::(value); - channels.set_i(channel, current); - channels.power_up(channel); - } - PwmPin::MaxV => { - let voltage = ElectricPotential::new::(value); - channels.set_max_v(channel, voltage); - } - PwmPin::MaxIPos => { - let current = ElectricCurrent::new::(value); - channels.set_max_i_pos(channel, current); - } - PwmPin::MaxINeg => { - let current = ElectricCurrent::new::(value); - channels.set_max_i_neg(channel, current); - } - } - send_line(&mut socket, b"{}"); - } - 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); - } - send_line(&mut socket, b"{}"); - } - Command::Pid { channel, parameter, value } => { - let pid = &mut channels.channel_state(channel).pid; - use command_parser::PidParameter::*; - match parameter { - Target => - pid.target = value, - KP => - pid.parameters.kp = value as f32, - KI => - pid.update_ki(value as f32), - KD => - pid.parameters.kd = value as f32, - OutputMin => - pid.parameters.output_min = value as f32, - OutputMax => - pid.parameters.output_max = value as f32, - IntegralMin => - pid.parameters.integral_min = value as f32, - IntegralMax => - pid.parameters.integral_max = value as f32, - } - send_line(&mut socket, b"{}"); - } - Command::SteinhartHart { channel, parameter, value } => { - let sh = &mut channels.channel_state(channel).sh; - use command_parser::ShParameter::*; - match parameter { - T0 => sh.t0 = ThermodynamicTemperature::new::(value), - B => sh.b = value, - R0 => sh.r0 = ElectricalResistance::new::(value), - } - send_line(&mut socket, b"{}"); - } - Command::PostFilter { channel, rate: None } => { - channels.adc.set_postfilter(channel as u8, None).unwrap(); - send_line(&mut socket, b"{}"); - } - Command::PostFilter { channel, rate: Some(rate) } => { - let filter = ad7172::PostFilter::closest(rate); - match filter { - Some(filter) => { - channels.adc.set_postfilter(channel as u8, Some(filter)).unwrap(); - send_line(&mut socket, b"{}"); - } - None => { - error!("unable to choose postfilter for rate {:.3}", rate); - send_line(&mut socket, b"{{\"error\": \"unable to choose postfilter rate\"}}"); - } - } - } - Command::Load { channel } => { - for c in 0..CHANNELS { - if channel.is_none() || channel == Some(c) { - match store.read_value::(CHANNEL_CONFIG_KEY[c]) { - Ok(Some(config)) => { - config.apply(&mut channels, c); - send_line(&mut socket, b"{}"); - } - Ok(None) => { - error!("flash config not found"); - send_line(&mut socket, b"{{\"error\": \"flash config not found\"}}"); - } - Err(e) => { - error!("unable to load config from flash: {:?}", e); - let _ = writeln!(socket, "{{\"error\":\"{:?}\"}}", e); - } - } - } - } - } - Command::Save { channel } => { - for c in 0..CHANNELS { - if channel.is_none() || channel == Some(c) { - let config = ChannelConfig::new(&mut channels, c); - match store.write_value(CHANNEL_CONFIG_KEY[c], &config, &mut store_value_buf) { - Ok(()) => { - send_line(&mut socket, b"{}"); - } - Err(e) => { - error!("unable to save channel {} config to flash: {:?}", c, e); - let _ = writeln!(socket, "{{\"error\":\"{:?}\"}}", e); - } - } - } - } - } - Command::Ipv4(config) => { - let _ = store - .write_value("ipv4", &config, [0; 16]) - .map_err(|e| error!("unable to save ipv4 config to flash: {:?}", e)); - new_ipv4_config = Some(config); - send_line(&mut socket, b"{}"); - } - Command::Reset => { - for i in 0..CHANNELS { - channels.power_down(i); - } - should_reset = true; - } - Command::Dfu => { - for i in 0..CHANNELS { - channels.power_down(i); - } - unsafe { - dfu::set_dfu_trigger(); - } - should_reset = true; + Ok(Handler::Handled) => {} + Ok(Handler::CloseSocket) => socket.close(), + Ok(Handler::Reset) => should_reset = true, + Err(_) => {}, } } Ok(SessionInput::Error(e)) => {