2019-03-07 23:27:33 +08:00
|
|
|
#![no_std]
|
|
|
|
#![no_main]
|
2020-09-11 05:17:31 +08:00
|
|
|
#![feature(maybe_uninit_extra, maybe_uninit_ref)]
|
2020-03-12 06:17:17 +08:00
|
|
|
// TODO: #![deny(warnings, unused)]
|
2019-03-07 23:27:33 +08:00
|
|
|
|
2019-03-15 02:58:41 +08:00
|
|
|
#[cfg(not(feature = "semihosting"))]
|
2019-04-27 21:23:50 +08:00
|
|
|
use panic_abort as _;
|
2019-03-15 02:58:41 +08:00
|
|
|
#[cfg(feature = "semihosting")]
|
2019-04-27 21:23:50 +08:00
|
|
|
use panic_semihosting as _;
|
2019-03-07 23:27:33 +08:00
|
|
|
|
2019-04-27 21:23:50 +08:00
|
|
|
use log::{info, warn};
|
2019-03-15 02:58:41 +08:00
|
|
|
|
2020-03-20 01:34:57 +08:00
|
|
|
use core::ops::DerefMut;
|
2019-03-15 02:58:41 +08:00
|
|
|
use core::fmt::Write;
|
2019-03-12 01:23:52 +08:00
|
|
|
use cortex_m::asm::wfi;
|
2019-03-07 23:27:33 +08:00
|
|
|
use cortex_m_rt::entry;
|
2019-03-12 01:23:52 +08:00
|
|
|
use stm32f4xx_hal::{
|
2020-03-20 01:34:57 +08:00
|
|
|
hal::{
|
|
|
|
self,
|
|
|
|
watchdog::{WatchdogEnable, Watchdog},
|
|
|
|
},
|
2019-03-12 01:23:52 +08:00
|
|
|
rcc::RccExt,
|
|
|
|
watchdog::IndependentWatchdog,
|
2020-03-13 01:31:43 +08:00
|
|
|
time::{U32Ext, MegaHertz},
|
2019-03-12 01:23:52 +08:00
|
|
|
stm32::{CorePeripherals, Peripherals},
|
|
|
|
};
|
2019-03-22 00:41:33 +08:00
|
|
|
use smoltcp::{
|
|
|
|
time::Instant,
|
|
|
|
wire::EthernetAddress,
|
|
|
|
};
|
2019-03-12 01:23:52 +08:00
|
|
|
|
2020-03-12 07:50:24 +08:00
|
|
|
mod init_log;
|
|
|
|
use init_log::init_log;
|
2020-09-11 05:17:31 +08:00
|
|
|
mod usb;
|
2020-09-07 03:10:10 +08:00
|
|
|
mod leds;
|
2020-03-09 07:27:35 +08:00
|
|
|
mod pins;
|
2020-03-12 06:16:48 +08:00
|
|
|
use pins::Pins;
|
|
|
|
mod ad7172;
|
2020-03-13 04:27:03 +08:00
|
|
|
mod ad5680;
|
2019-03-13 05:52:39 +08:00
|
|
|
mod net;
|
|
|
|
mod server;
|
|
|
|
use server::Server;
|
2020-03-14 06:39:22 +08:00
|
|
|
mod session;
|
2020-05-13 06:04:55 +08:00
|
|
|
use session::{Session, SessionOutput};
|
2020-03-14 06:39:22 +08:00
|
|
|
mod command_parser;
|
2020-03-20 01:34:57 +08:00
|
|
|
use command_parser::{Command, ShowCommand, PwmPin};
|
2019-03-15 01:13:25 +08:00
|
|
|
mod timer;
|
2020-05-17 06:13:52 +08:00
|
|
|
mod units;
|
2020-05-19 04:43:44 +08:00
|
|
|
use units::{Ohms, Volts};
|
2020-03-19 04:51:30 +08:00
|
|
|
mod pid;
|
|
|
|
mod steinhart_hart;
|
2020-05-13 05:16:57 +08:00
|
|
|
mod channels;
|
2020-05-13 06:04:55 +08:00
|
|
|
use channels::{CHANNELS, Channels};
|
2020-05-13 05:16:57 +08:00
|
|
|
mod channel;
|
2020-03-20 05:09:16 +08:00
|
|
|
mod channel_state;
|
2020-03-14 06:39:22 +08:00
|
|
|
|
2019-03-07 23:27:33 +08:00
|
|
|
|
2020-03-20 01:34:57 +08:00
|
|
|
const HSE: MegaHertz = MegaHertz(8);
|
2020-03-12 06:17:34 +08:00
|
|
|
#[cfg(not(feature = "semihosting"))]
|
|
|
|
const WATCHDOG_INTERVAL: u32 = 100;
|
|
|
|
#[cfg(feature = "semihosting")]
|
2020-05-21 05:07:31 +08:00
|
|
|
const WATCHDOG_INTERVAL: u32 = 30_000;
|
2020-03-12 06:17:34 +08:00
|
|
|
|
2019-03-22 00:41:33 +08:00
|
|
|
#[cfg(not(feature = "generate-hwaddr"))]
|
|
|
|
const NET_HWADDR: [u8; 6] = [0x02, 0x00, 0xDE, 0xAD, 0xBE, 0xEF];
|
2020-03-14 06:39:22 +08:00
|
|
|
const TCP_PORT: u16 = 23;
|
2019-03-15 02:58:41 +08:00
|
|
|
|
2020-03-13 01:31:43 +08:00
|
|
|
|
2019-03-19 04:41:51 +08:00
|
|
|
/// Initialization and main loop
|
2019-03-07 23:27:33 +08:00
|
|
|
#[entry]
|
|
|
|
fn main() -> ! {
|
2019-03-15 02:58:41 +08:00
|
|
|
init_log();
|
2020-03-14 06:39:22 +08:00
|
|
|
info!("tecpak");
|
2019-03-12 01:23:52 +08:00
|
|
|
|
|
|
|
let mut cp = CorePeripherals::take().unwrap();
|
2019-03-13 05:52:39 +08:00
|
|
|
cp.SCB.enable_icache();
|
|
|
|
cp.SCB.enable_dcache(&mut cp.CPUID);
|
|
|
|
|
2019-03-12 01:23:52 +08:00
|
|
|
let dp = Peripherals::take().unwrap();
|
2019-03-15 01:13:25 +08:00
|
|
|
let clocks = dp.RCC.constrain()
|
2019-03-12 01:23:52 +08:00
|
|
|
.cfgr
|
2020-03-13 01:31:43 +08:00
|
|
|
.use_hse(HSE)
|
2019-03-19 05:04:34 +08:00
|
|
|
.sysclk(168.mhz())
|
|
|
|
.hclk(168.mhz())
|
|
|
|
.pclk1(32.mhz())
|
|
|
|
.pclk2(64.mhz())
|
2019-03-12 01:23:52 +08:00
|
|
|
.freeze();
|
|
|
|
|
|
|
|
let mut wd = IndependentWatchdog::new(dp.IWDG);
|
2020-03-12 06:17:34 +08:00
|
|
|
wd.start(WATCHDOG_INTERVAL.ms());
|
2019-03-12 01:23:52 +08:00
|
|
|
wd.feed();
|
|
|
|
|
2020-05-29 02:45:42 +08:00
|
|
|
timer::setup(cp.SYST, clocks);
|
|
|
|
|
2020-09-11 05:17:31 +08:00
|
|
|
let (pins, mut leds, eth_pins, usb) = Pins::setup(
|
2020-03-13 00:26:14 +08:00
|
|
|
clocks, dp.TIM1, dp.TIM3,
|
2020-09-07 03:10:10 +08:00
|
|
|
dp.GPIOA, dp.GPIOB, dp.GPIOC, dp.GPIOD, dp.GPIOE, dp.GPIOF, dp.GPIOG,
|
2020-04-11 03:05:05 +08:00
|
|
|
dp.SPI2, dp.SPI4, dp.SPI5,
|
2020-05-29 02:43:34 +08:00
|
|
|
dp.ADC1,
|
2020-09-11 05:17:31 +08:00
|
|
|
dp.OTG_FS_GLOBAL,
|
|
|
|
dp.OTG_FS_DEVICE,
|
|
|
|
dp.OTG_FS_PWRCLK,
|
2020-03-13 00:26:14 +08:00
|
|
|
);
|
2020-09-07 03:10:10 +08:00
|
|
|
|
|
|
|
leds.r1.on();
|
|
|
|
leds.g3.off();
|
|
|
|
leds.g4.off();
|
|
|
|
|
2020-09-11 05:17:31 +08:00
|
|
|
usb::State::setup(usb);
|
|
|
|
|
2020-05-13 05:16:57 +08:00
|
|
|
let mut channels = Channels::new(pins);
|
2020-09-10 05:10:33 +08:00
|
|
|
let adc_calibration = [
|
|
|
|
channels.adc.get_calibration(0).unwrap(),
|
|
|
|
channels.adc.get_calibration(1).unwrap(),
|
|
|
|
];
|
2019-03-15 01:13:25 +08:00
|
|
|
|
2019-03-22 00:41:33 +08:00
|
|
|
#[cfg(not(feature = "generate-hwaddr"))]
|
|
|
|
let hwaddr = EthernetAddress(NET_HWADDR);
|
|
|
|
#[cfg(feature = "generate-hwaddr")]
|
|
|
|
let hwaddr = {
|
|
|
|
let uid = stm32f4xx_hal::signature::Uid::get();
|
|
|
|
EthernetAddress(hash2hwaddr::generate_hwaddr(uid))
|
|
|
|
};
|
|
|
|
info!("Net hwaddr: {}", hwaddr);
|
|
|
|
|
2020-09-04 03:38:56 +08:00
|
|
|
net::run(clocks, dp.ETHERNET_MAC, dp.ETHERNET_DMA, eth_pins, hwaddr, |iface| {
|
2020-03-14 06:39:22 +08:00
|
|
|
Server::<Session>::run(iface, |server| {
|
2020-09-07 03:10:10 +08:00
|
|
|
leds.r1.off();
|
|
|
|
|
2019-03-19 03:02:57 +08:00
|
|
|
loop {
|
2020-03-21 07:07:18 +08:00
|
|
|
let instant = Instant::from_millis(i64::from(timer::now()));
|
2020-05-13 06:04:55 +08:00
|
|
|
let updated_channel = channels.poll_adc(instant);
|
|
|
|
if let Some(channel) = updated_channel {
|
2020-03-14 06:39:22 +08:00
|
|
|
server.for_each(|_, session| session.set_report_pending(channel.into()));
|
2020-05-13 06:04:55 +08:00
|
|
|
}
|
2020-03-14 06:39:22 +08:00
|
|
|
|
2020-03-21 07:46:24 +08:00
|
|
|
let instant = Instant::from_millis(i64::from(timer::now()));
|
|
|
|
cortex_m::interrupt::free(net::clear_pending);
|
|
|
|
server.poll(instant)
|
|
|
|
.unwrap_or_else(|e| {
|
|
|
|
warn!("poll: {:?}", e);
|
|
|
|
});
|
|
|
|
|
2020-03-14 06:39:22 +08:00
|
|
|
// TCP protocol handling
|
|
|
|
server.for_each(|mut socket, session| {
|
2020-03-21 07:37:24 +08:00
|
|
|
if ! socket.is_active() {
|
2020-03-14 06:39:22 +08:00
|
|
|
let _ = socket.listen(TCP_PORT);
|
2020-03-21 06:20:38 +08:00
|
|
|
session.reset();
|
2020-03-21 07:11:23 +08:00
|
|
|
} else if socket.can_send() && socket.can_recv() && socket.send_capacity() - socket.send_queue() > 1024 {
|
2020-03-14 06:39:22 +08:00
|
|
|
match socket.recv(|buf| session.feed(buf)) {
|
|
|
|
Ok(SessionOutput::Nothing) => {}
|
|
|
|
Ok(SessionOutput::Command(command)) => match command {
|
|
|
|
Command::Quit =>
|
|
|
|
socket.close(),
|
|
|
|
Command::Reporting(reporting) => {
|
|
|
|
let _ = writeln!(socket, "report={}", if reporting { "on" } else { "off" });
|
|
|
|
}
|
|
|
|
Command::Show(ShowCommand::Reporting) => {
|
|
|
|
let _ = writeln!(socket, "report={}", if session.reporting() { "on" } else { "off" });
|
|
|
|
}
|
|
|
|
Command::Show(ShowCommand::Input) => {
|
2020-05-13 06:04:55 +08:00
|
|
|
for channel in 0..CHANNELS {
|
2020-05-13 06:15:29 +08:00
|
|
|
if let Some(adc_data) = channels.channel_state(channel).adc_data {
|
2020-05-19 04:43:44 +08:00
|
|
|
let vref = channels.read_vref(channel);
|
2020-05-17 08:18:25 +08:00
|
|
|
let dac_feedback = channels.read_dac_feedback(channel);
|
2020-05-17 06:54:37 +08:00
|
|
|
|
2020-05-17 05:59:31 +08:00
|
|
|
let itec = channels.read_itec(channel);
|
2020-05-19 04:43:44 +08:00
|
|
|
let tec_i = -(itec - Volts(1.5)) / Ohms(0.4);
|
2020-05-17 06:54:37 +08:00
|
|
|
|
2020-05-19 03:38:13 +08:00
|
|
|
let tec_u_meas = channels.read_tec_u_meas(channel);
|
|
|
|
|
2020-05-13 06:15:29 +08:00
|
|
|
let state = channels.channel_state(channel);
|
2020-03-14 06:39:22 +08:00
|
|
|
let _ = writeln!(
|
2020-09-10 05:10:33 +08:00
|
|
|
socket, "channel {}: t={} adc_raw{}=0x{:06X} adc{}={:.3}V vref={} dac_feedback={} itec={} tec={} tec_u_meas={}",
|
|
|
|
channel,
|
2020-05-13 06:15:29 +08:00
|
|
|
state.adc_time, channel, adc_data,
|
2020-09-10 05:10:33 +08:00
|
|
|
channel, adc_calibration[channel].convert_data(adc_data),
|
2020-05-19 04:43:44 +08:00
|
|
|
vref, dac_feedback,
|
2020-05-17 06:54:37 +08:00
|
|
|
itec, tec_i,
|
2020-05-19 03:38:13 +08:00
|
|
|
tec_u_meas,
|
2020-03-14 06:39:22 +08:00
|
|
|
);
|
2020-09-10 05:10:33 +08:00
|
|
|
} else {
|
|
|
|
let _ = writeln!(socket, "channel {}: no adc input", channel);
|
2020-03-14 06:39:22 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Command::Show(ShowCommand::Pid) => {
|
2020-05-13 06:04:55 +08:00
|
|
|
for channel in 0..CHANNELS {
|
|
|
|
let state = channels.channel_state(channel);
|
2020-03-20 01:34:57 +08:00
|
|
|
let _ = writeln!(socket, "PID settings for channel {}", channel);
|
|
|
|
let pid = &state.pid;
|
2020-03-20 05:00:22 +08:00
|
|
|
let _ = writeln!(socket, "- target={:.4}", pid.target);
|
|
|
|
macro_rules! show_pid_parameter {
|
2020-03-20 01:34:57 +08:00
|
|
|
($p: tt) => {
|
2020-03-20 05:00:22 +08:00
|
|
|
let _ = writeln!(
|
|
|
|
socket, "- {}={:.4}",
|
|
|
|
stringify!($p), pid.parameters.$p
|
|
|
|
);
|
2020-03-20 01:34:57 +08:00
|
|
|
};
|
|
|
|
}
|
2020-03-20 05:00:22 +08:00
|
|
|
show_pid_parameter!(kp);
|
|
|
|
show_pid_parameter!(ki);
|
|
|
|
show_pid_parameter!(kd);
|
|
|
|
show_pid_parameter!(integral_min);
|
|
|
|
show_pid_parameter!(integral_max);
|
2020-03-24 06:02:50 +08:00
|
|
|
show_pid_parameter!(output_min);
|
|
|
|
show_pid_parameter!(output_max);
|
2020-03-20 05:00:22 +08:00
|
|
|
if let Some(last_output) = pid.last_output {
|
2020-03-24 06:02:50 +08:00
|
|
|
let _ = writeln!(socket, "- last_output={:.4}", last_output);
|
2020-03-20 05:00:22 +08:00
|
|
|
}
|
2020-03-20 01:34:57 +08:00
|
|
|
let _ = writeln!(socket, "");
|
|
|
|
}
|
2020-03-14 06:39:22 +08:00
|
|
|
}
|
|
|
|
Command::Show(ShowCommand::Pwm) => {
|
2020-05-13 06:04:55 +08:00
|
|
|
for channel in 0..CHANNELS {
|
|
|
|
let state = channels.channel_state(channel);
|
2020-03-20 01:34:57 +08:00
|
|
|
let _ = writeln!(
|
|
|
|
socket, "channel {}: PID={}",
|
|
|
|
channel,
|
2020-05-13 06:04:55 +08:00
|
|
|
if state.pid_engaged { "engaged" } else { "disengaged" }
|
2020-03-20 01:34:57 +08:00
|
|
|
);
|
2020-05-17 07:23:35 +08:00
|
|
|
let _ = writeln!(socket, "- i_set={}", state.dac_value);
|
2020-03-20 01:34:57 +08:00
|
|
|
fn show_pwm_channel<S, P>(mut socket: S, name: &str, pin: &P)
|
|
|
|
where
|
|
|
|
S: core::fmt::Write,
|
|
|
|
P: hal::PwmPin<Duty=u16>,
|
|
|
|
{
|
|
|
|
let _ = writeln!(
|
|
|
|
socket,
|
|
|
|
"- {}={}/{}",
|
|
|
|
name, pin.get_duty(), pin.get_max_duty()
|
|
|
|
);
|
|
|
|
}
|
|
|
|
match channel {
|
|
|
|
0 => {
|
2020-05-13 05:16:57 +08:00
|
|
|
show_pwm_channel(socket.deref_mut(), "max_v", &channels.pwm.max_v0);
|
|
|
|
show_pwm_channel(socket.deref_mut(), "max_i_pos", &channels.pwm.max_i_pos0);
|
|
|
|
show_pwm_channel(socket.deref_mut(), "max_i_neg", &channels.pwm.max_i_neg0);
|
2020-03-20 01:34:57 +08:00
|
|
|
}
|
|
|
|
1 => {
|
2020-05-13 05:16:57 +08:00
|
|
|
show_pwm_channel(socket.deref_mut(), "max_v", &channels.pwm.max_v1);
|
|
|
|
show_pwm_channel(socket.deref_mut(), "max_i_pos", &channels.pwm.max_i_pos1);
|
|
|
|
show_pwm_channel(socket.deref_mut(), "max_i_neg", &channels.pwm.max_i_neg1);
|
2020-03-20 01:34:57 +08:00
|
|
|
}
|
|
|
|
_ => unreachable!(),
|
|
|
|
}
|
|
|
|
let _ = writeln!(socket, "");
|
|
|
|
}
|
2020-03-14 06:39:22 +08:00
|
|
|
}
|
|
|
|
Command::Show(ShowCommand::SteinhartHart) => {
|
2020-05-13 06:04:55 +08:00
|
|
|
for channel in 0..CHANNELS {
|
|
|
|
let state = channels.channel_state(channel);
|
2020-03-20 01:34:57 +08:00
|
|
|
let _ = writeln!(
|
|
|
|
socket, "channel {}: Steinhart-Hart equation parameters",
|
|
|
|
channel,
|
|
|
|
);
|
|
|
|
let _ = writeln!(socket, "- t0={}", state.sh.t0);
|
2020-03-20 05:56:14 +08:00
|
|
|
let _ = writeln!(socket, "- b={}", state.sh.b);
|
2020-03-20 01:34:57 +08:00
|
|
|
let _ = writeln!(socket, "- r0={}", state.sh.r0);
|
|
|
|
let _ = writeln!(socket, "");
|
|
|
|
}
|
2020-03-14 06:39:22 +08:00
|
|
|
}
|
|
|
|
Command::Show(ShowCommand::PostFilter) => {
|
2020-05-13 06:04:55 +08:00
|
|
|
for channel in 0..CHANNELS {
|
2020-05-13 05:16:57 +08:00
|
|
|
match channels.adc.get_postfilter(channel as u8).unwrap() {
|
2020-03-20 01:34:57 +08:00
|
|
|
Some(filter) => {
|
|
|
|
let _ = writeln!(
|
|
|
|
socket, "channel {}: postfilter={:.2} SPS",
|
|
|
|
channel, filter.output_rate().unwrap()
|
|
|
|
);
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
let _ = writeln!(
|
|
|
|
socket, "channel {}: no postfilter",
|
|
|
|
channel
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Command::PwmPid { channel } => {
|
2020-05-13 06:04:55 +08:00
|
|
|
channels.channel_state(channel).pid_engaged = true;
|
2020-09-07 03:10:10 +08:00
|
|
|
leds.g3.on();
|
2020-03-20 01:34:57 +08:00
|
|
|
let _ = writeln!(socket, "channel {}: PID enabled to control PWM", channel
|
|
|
|
);
|
|
|
|
}
|
2020-05-17 07:23:35 +08:00
|
|
|
Command::Pwm { channel, pin: PwmPin::ISet, duty } => {
|
2020-05-13 06:04:55 +08:00
|
|
|
channels.channel_state(channel).pid_engaged = false;
|
2020-09-07 03:10:10 +08:00
|
|
|
leds.g3.off();
|
2020-05-17 07:23:35 +08:00
|
|
|
let voltage = Volts(duty);
|
|
|
|
channels.set_dac(channel, voltage);
|
2020-03-20 01:34:57 +08:00
|
|
|
let _ = writeln!(
|
2020-05-17 07:23:35 +08:00
|
|
|
socket, "channel {}: PWM duty cycle manually set to {}",
|
|
|
|
channel, voltage
|
2020-03-20 01:34:57 +08:00
|
|
|
);
|
2020-03-14 06:39:22 +08:00
|
|
|
}
|
2020-05-17 07:23:35 +08:00
|
|
|
Command::Pwm { channel, pin, duty } => {
|
2020-05-28 02:38:57 +08:00
|
|
|
fn set_pwm_channel<P: hal::PwmPin<Duty=u16>>(pin: &mut P, duty: f64) -> (u16, u16) {
|
|
|
|
let max = pin.get_max_duty();
|
|
|
|
let value = (duty * (max as f64)) as u16;
|
|
|
|
pin.set_duty(value);
|
|
|
|
(value, max)
|
2020-03-20 01:34:57 +08:00
|
|
|
}
|
2020-05-28 02:38:57 +08:00
|
|
|
let (value, max) = match (channel, pin) {
|
2020-03-20 01:34:57 +08:00
|
|
|
(_, PwmPin::ISet) =>
|
|
|
|
// Handled above
|
|
|
|
unreachable!(),
|
|
|
|
(0, PwmPin::MaxIPos) =>
|
2020-05-13 05:16:57 +08:00
|
|
|
set_pwm_channel(&mut channels.pwm.max_i_pos0, duty),
|
2020-03-20 01:34:57 +08:00
|
|
|
(0, PwmPin::MaxINeg) =>
|
2020-05-13 05:16:57 +08:00
|
|
|
set_pwm_channel(&mut channels.pwm.max_i_neg0, duty),
|
2020-03-20 01:34:57 +08:00
|
|
|
(0, PwmPin::MaxV) =>
|
2020-05-13 05:16:57 +08:00
|
|
|
set_pwm_channel(&mut channels.pwm.max_v0, duty),
|
2020-03-20 01:34:57 +08:00
|
|
|
(1, PwmPin::MaxIPos) =>
|
2020-05-13 05:16:57 +08:00
|
|
|
set_pwm_channel(&mut channels.pwm.max_i_pos1, duty),
|
2020-03-20 01:34:57 +08:00
|
|
|
(1, PwmPin::MaxINeg) =>
|
2020-05-13 05:16:57 +08:00
|
|
|
set_pwm_channel(&mut channels.pwm.max_i_neg1, duty),
|
2020-03-20 01:34:57 +08:00
|
|
|
(1, PwmPin::MaxV) =>
|
2020-05-13 05:16:57 +08:00
|
|
|
set_pwm_channel(&mut channels.pwm.max_v1, duty),
|
2020-03-20 01:34:57 +08:00
|
|
|
_ =>
|
|
|
|
unreachable!(),
|
|
|
|
};
|
|
|
|
let _ = writeln!(
|
|
|
|
socket, "channel {}: PWM {} reconfigured to {}/{}",
|
2020-05-28 02:38:57 +08:00
|
|
|
channel, pin.name(), value, max
|
2020-03-20 01:34:57 +08:00
|
|
|
);
|
2020-03-14 06:39:22 +08:00
|
|
|
}
|
|
|
|
Command::Pid { channel, parameter, value } => {
|
2020-05-13 06:04:55 +08:00
|
|
|
let pid = &mut channels.channel_state(channel).pid;
|
2020-03-20 01:34:57 +08:00
|
|
|
use command_parser::PidParameter::*;
|
|
|
|
match parameter {
|
|
|
|
Target =>
|
2020-03-20 05:01:16 +08:00
|
|
|
pid.target = value,
|
2020-03-20 01:34:57 +08:00
|
|
|
KP =>
|
2020-03-20 05:01:16 +08:00
|
|
|
pid.parameters.kp = value,
|
2020-03-20 01:34:57 +08:00
|
|
|
KI =>
|
2020-03-20 05:01:16 +08:00
|
|
|
pid.parameters.ki = value,
|
2020-03-20 01:34:57 +08:00
|
|
|
KD =>
|
2020-03-20 05:01:16 +08:00
|
|
|
pid.parameters.kd = value,
|
2020-03-20 01:34:57 +08:00
|
|
|
OutputMin =>
|
2020-03-20 05:01:16 +08:00
|
|
|
pid.parameters.output_min = value,
|
2020-03-20 01:34:57 +08:00
|
|
|
OutputMax =>
|
2020-03-20 05:01:16 +08:00
|
|
|
pid.parameters.output_max = value,
|
2020-03-20 01:34:57 +08:00
|
|
|
IntegralMin =>
|
2020-03-20 05:01:16 +08:00
|
|
|
pid.parameters.integral_min = value,
|
2020-03-20 01:34:57 +08:00
|
|
|
IntegralMax =>
|
2020-03-20 05:01:16 +08:00
|
|
|
pid.parameters.integral_max = value,
|
2020-03-20 01:34:57 +08:00
|
|
|
}
|
2020-03-20 05:01:16 +08:00
|
|
|
// TODO: really reset PID state
|
|
|
|
// after each parameter change?
|
2020-03-20 01:34:57 +08:00
|
|
|
pid.reset();
|
|
|
|
let _ = writeln!(socket, "PID parameter updated");
|
2020-03-14 06:39:22 +08:00
|
|
|
}
|
|
|
|
Command::SteinhartHart { channel, parameter, value } => {
|
2020-05-13 06:04:55 +08:00
|
|
|
let sh = &mut channels.channel_state(channel).sh;
|
2020-03-20 01:34:57 +08:00
|
|
|
use command_parser::ShParameter::*;
|
|
|
|
match parameter {
|
|
|
|
T0 => sh.t0 = value,
|
2020-03-20 05:56:14 +08:00
|
|
|
B => sh.b = value,
|
2020-03-20 01:34:57 +08:00
|
|
|
R0 => sh.r0 = value,
|
|
|
|
}
|
|
|
|
let _ = writeln!(socket, "Steinhart-Hart equation parameter updated");
|
2020-03-14 06:39:22 +08:00
|
|
|
}
|
|
|
|
Command::PostFilter { channel, rate } => {
|
2020-03-20 01:34:57 +08:00
|
|
|
let filter = ad7172::PostFilter::closest(rate);
|
|
|
|
match filter {
|
|
|
|
Some(filter) => {
|
2020-05-13 05:16:57 +08:00
|
|
|
channels.adc.set_postfilter(channel as u8, Some(filter)).unwrap();
|
2020-03-20 01:34:57 +08:00
|
|
|
let _ = writeln!(
|
|
|
|
socket, "channel {}: postfilter set to {:.2} SPS",
|
|
|
|
channel, filter.output_rate().unwrap()
|
|
|
|
);
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
let _ = writeln!(socket, "Unable to choose postfilter");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-03-14 06:39:22 +08:00
|
|
|
}
|
|
|
|
Ok(SessionOutput::Error(e)) => {
|
|
|
|
let _ = writeln!(socket, "Command error: {:?}", e);
|
|
|
|
}
|
|
|
|
Err(_) =>
|
|
|
|
socket.close(),
|
|
|
|
}
|
|
|
|
} else if socket.can_send() && socket.send_capacity() - socket.send_queue() > 256 {
|
|
|
|
while let Some(channel) = session.is_report_pending() {
|
2020-05-13 06:04:55 +08:00
|
|
|
let state = &mut channels.channel_state(usize::from(channel));
|
2020-09-10 05:10:33 +08:00
|
|
|
let adc_data = state.adc_data.unwrap_or(0);
|
2020-03-14 06:39:22 +08:00
|
|
|
let _ = writeln!(
|
2020-09-10 05:10:33 +08:00
|
|
|
socket, "t={} raw{}=0x{:06X} value={:.3}V",
|
|
|
|
state.adc_time, channel, adc_data,
|
|
|
|
adc_calibration[channel].convert_data(adc_data),
|
2020-03-14 06:39:22 +08:00
|
|
|
).map(|_| {
|
|
|
|
session.mark_report_sent(channel);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
2020-03-12 07:44:15 +08:00
|
|
|
|
2019-03-19 03:02:57 +08:00
|
|
|
// Update watchdog
|
|
|
|
wd.feed();
|
|
|
|
|
2020-09-07 03:10:10 +08:00
|
|
|
leds.g4.off();
|
2020-03-21 07:46:24 +08:00
|
|
|
cortex_m::interrupt::free(|cs| {
|
|
|
|
if !net::is_pending(cs) {
|
|
|
|
// Wait for interrupts
|
2020-09-11 05:17:31 +08:00
|
|
|
// (Ethernet, SysTick, or USB)
|
2020-03-21 07:46:24 +08:00
|
|
|
wfi();
|
|
|
|
}
|
|
|
|
});
|
2020-09-07 03:10:10 +08:00
|
|
|
leds.g4.on();
|
2019-03-15 01:13:25 +08:00
|
|
|
}
|
2019-03-19 03:02:57 +08:00
|
|
|
});
|
|
|
|
});
|
2019-03-15 03:43:35 +08:00
|
|
|
|
2019-03-19 04:17:27 +08:00
|
|
|
unreachable!()
|
2019-03-07 23:27:33 +08:00
|
|
|
}
|