1
0
forked from M-Labs/kirdy
kirdy-firmware/src/main.rs
linuswck a8787430b1 Add Temperature Monitor to Thermostat
- Issue an alarm when temperature goes out of user-defined operating range during Pid Controller startup
    or reading is outside of +-0.5 Degree from temperature set point after Pid Controller becomes stable
- If alarm is observed, power down laser and tec controller and disengage Pid Controller
- Add the corresponding cmd for configuring the temperature monitor
2024-02-21 17:32:11 +08:00

165 lines
5.6 KiB
Rust

#![cfg_attr(not(test), no_main)]
#![cfg_attr(not(test), no_std)]
use cortex_m_rt::entry;
use log::{info, debug};
use stm32f4xx_hal::pac::{CorePeripherals, Peripherals};
mod device;
mod laser_diode;
mod thermostat;
mod net;
use device::{boot::bootup, log_setup, sys_timer};
use uom::fmt::DisplayStyle::Abbreviation;
use uom::si::electric_potential::volt;
use uom::si::electric_current::{ampere, milliampere};
use uom::si::thermodynamic_temperature::degree_celsius;
use uom::si::power::milliwatt;
use uom::si::f64::{ElectricPotential, ElectricCurrent, Power, ThermodynamicTemperature};
use serde::{Serialize, Deserialize};
use stm32f4xx_hal::pac::SCB;
// If RTT is used, print panic info through RTT
#[cfg(all(feature = "RTT", not(test)))]
use {core::panic::PanicInfo, rtt_target::rprintln};
#[cfg(all(feature = "RTT", not(test)))]
#[panic_handler]
fn panic(info: &PanicInfo) -> ! {
rprintln!("{}", info);
loop {}
}
// Otherwise use panic halt
#[cfg(all(not(feature = "RTT"), not(test)))]
use panic_halt as _;
static mut ETH_DATA_BUFFER: [u8; 1024] = [0; 1024];
pub struct DeviceSettings{
report_readings: bool,
}
#[cfg(not(test))]
#[entry]
fn main() -> ! {
log_setup::init_log();
info!("Kirdy init");
let core_perif = CorePeripherals::take().unwrap();
let perif = Peripherals::take().unwrap();
let (mut wd, mut _flash_store, mut laser, mut thermostat,) = bootup(core_perif, perif);
// Demo Fns for reading and writing stm32 Internal Flash
/*
let key = "test";
info!("Read the Flash Content Stored");
match flash_store.read(key).unwrap() {
Some(val) => {info!("Flash Valued Read: {:?}", val)}
_ => {info!("Key does not match")}
}
info!("Erasing Flash");
flash_store.erase().unwrap();
match flash_store.read(key).unwrap() {
Some(val) => {info!("Flash Valued Read: {:?}", val)}
_ => {info!("Key does not match")}
}
info!("Writing Flash");
let buf = [1, 2, 3, 4];
flash_store.write(key, &buf).unwrap();
info!("Reading Flash");
match flash_store.read(key).unwrap() {
Some(val) => {info!("Val: {:?}", val)}
_ => {info!("Key does not match")}
};
*/
// https://github.com/iliekturtles/uom/blob/master/examples/si.rs
let volt_fmt = ElectricPotential::format_args(volt, Abbreviation);
let amp_fmt = ElectricCurrent::format_args(ampere, Abbreviation);
let milli_amp_fmt = ElectricCurrent::format_args(milliampere, Abbreviation);
let milli_watt_fmt = Power::format_args(milliwatt, Abbreviation);
let mut should_reset = false;
let mut device_settings = DeviceSettings {
report_readings: false,
};
loop {
wd.feed();
if !should_reset {
let mut eth_is_pending = false;
laser.poll_and_update_output_current();
if thermostat.poll_adc_and_update_pid() {
if thermostat.get_temp_mon_status().over_temp_alarm {
laser.power_down();
thermostat.set_pid_engaged(false);
thermostat.power_down();
}
info!("curr_dac_vfb: {:?}", volt_fmt.with(thermostat.get_dac_vfb()));
info!("curr_vref: {:?}", volt_fmt.with(thermostat.get_vref()));
info!("curr_tec_i: {:?}", amp_fmt.with(thermostat.get_tec_i()));
info!("curr_tec_v: {:?}", volt_fmt.with(thermostat.get_tec_v()));
info!("curr_ld_drive_cuurent: {:?}", milli_amp_fmt.with(laser.get_ld_drive_current()));
info!("pd_mon_v: {:?}", volt_fmt.with(laser.pd_mon_status().v));
info!("power_excursion: {:?}", laser.pd_mon_status().pwr_excursion);
info!("Termination Status: {:?}", laser.get_term_status());
if net::net::eth_is_socket_active() {
if device_settings.report_readings {
unsafe {
net::cmd_handler::send_ld_readings(&mut ETH_DATA_BUFFER, &mut laser);
net::cmd_handler::send_tec_readings(&mut ETH_DATA_BUFFER, &mut thermostat);
}
}
}
}
if net::net::eth_is_socket_active() {
cortex_m::interrupt::free(|cs|
{
eth_is_pending = net::net::is_pending(cs);
}
);
if eth_is_pending {
unsafe{
cortex_m::interrupt::free(|cs| {
net::net::clear_pending(cs);
});
let bytes = net::net::eth_recv(&mut ETH_DATA_BUFFER);
debug!("Number of bytes recv: {:?}", bytes);
(laser, thermostat, should_reset, device_settings) = net::cmd_handler::execute_cmd(&mut ETH_DATA_BUFFER, bytes, laser, thermostat, device_settings);
}
}
}
else {
device_settings.report_readings = false;
}
} else {
// Should reset, close all TCP sockets.
let mut any_socket_alive = false;
if net::net::eth_is_socket_active() {
net::net::eth_close_socket();
any_socket_alive = true;
}
// Must let loop run for one more cycle to poll server for RST to be sent,
// this makes sure system does not reset right after socket.abort() is called.
if !any_socket_alive {
SCB::sys_reset();
}
}
}
}