288 lines
10 KiB
Rust
288 lines
10 KiB
Rust
#![cfg_attr(not(test), no_main)]
|
|
#![cfg_attr(not(test), no_std)]
|
|
|
|
use core::marker::PhantomData;
|
|
|
|
use cortex_m_rt::entry;
|
|
use log::{debug, info};
|
|
use stm32f4xx_hal::pac::{CorePeripherals, Peripherals};
|
|
use uom::si::f32::ElectricalConductance;
|
|
mod device;
|
|
mod laser_diode;
|
|
mod net;
|
|
mod thermostat;
|
|
|
|
use core::ptr::addr_of_mut;
|
|
|
|
use device::{boot::bootup, log_setup, sys_timer};
|
|
use serde::{Deserialize, Serialize};
|
|
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};
|
|
|
|
use crate::net::net::IpSettings;
|
|
|
|
#[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];
|
|
|
|
#[derive(Deserialize, Serialize, Clone, Copy, Debug)]
|
|
pub struct DeviceSettings {
|
|
ip_settings: IpSettings,
|
|
pd_mon_fin_gain: f32,
|
|
pd_mon_transconductance: ElectricalConductance,
|
|
}
|
|
|
|
const CONFIG_KEY: [&str; 3] = ["Device", "Laser_0", "Thermostat_0"];
|
|
|
|
#[derive(Default)]
|
|
pub enum State {
|
|
#[default]
|
|
LoadFlashSettings,
|
|
MainLoop,
|
|
SaveLdThermostatSettings,
|
|
SaveDeviceSettings,
|
|
PrepareForHardReset,
|
|
HardReset,
|
|
}
|
|
|
|
#[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);
|
|
|
|
let mut device_settings = DeviceSettings {
|
|
ip_settings: IpSettings::default(),
|
|
pd_mon_fin_gain: 1.0,
|
|
pd_mon_transconductance: ElectricalConductance {
|
|
dimension: PhantomData,
|
|
units: PhantomData,
|
|
value: 1.0 / 1000.0,
|
|
},
|
|
};
|
|
|
|
let mut active_report: [bool; net::net::NUM_OF_SOCKETS] = [false; net::net::NUM_OF_SOCKETS];
|
|
|
|
let mut state = State::default();
|
|
|
|
let eth_data_buffer = unsafe { addr_of_mut!(ETH_DATA_BUFFER).as_mut().unwrap() };
|
|
|
|
loop {
|
|
wd.feed();
|
|
|
|
if net::net::eth_poll_link_status_and_update_link_speed() {
|
|
active_report = [false; net::net::NUM_OF_SOCKETS];
|
|
}
|
|
|
|
match state {
|
|
State::LoadFlashSettings => {
|
|
// State Transition
|
|
state = State::MainLoop;
|
|
|
|
wd.feed();
|
|
let device_settings_flash: DeviceSettings;
|
|
match flash_store.read_value(CONFIG_KEY[0]) {
|
|
Ok(Some(config)) => {
|
|
device_settings_flash = config;
|
|
laser.set_pd_transconductance(config.pd_mon_fin_gain * config.pd_mon_transconductance);
|
|
debug!("Found Device Settings");
|
|
device_settings = device_settings_flash;
|
|
}
|
|
Ok(None) => {
|
|
info!("Flash does not have Device Settings");
|
|
}
|
|
Err(e) => {
|
|
debug!("Cannot Store Flash: {:?}", e);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
wd.feed();
|
|
let laser_settings: laser_diode::laser_diode::LdSettingsSummary;
|
|
match flash_store.read_value(CONFIG_KEY[1]) {
|
|
Ok(Some(config)) => {
|
|
laser_settings = config;
|
|
debug!("Found Laser Diode Settings");
|
|
}
|
|
Ok(None) => {
|
|
debug!("Does not have laser diode Settings");
|
|
continue;
|
|
}
|
|
Err(e) => {
|
|
debug!("Cannot Store Flash: {:?}", e);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
wd.feed();
|
|
let thermostat_settings: thermostat::thermostat::ThermostatSettingsSummary;
|
|
match flash_store.read_value(CONFIG_KEY[2]) {
|
|
Ok(Some(config)) => {
|
|
thermostat_settings = config;
|
|
debug!("Found Thermostat Settings");
|
|
}
|
|
Ok(None) => {
|
|
debug!("Does not have thermostat Settings");
|
|
continue;
|
|
}
|
|
Err(e) => {
|
|
debug!("Cannot Store Flash: {:?}", e);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
wd.feed();
|
|
thermostat.load_settings_from_summary(thermostat_settings);
|
|
laser.load_settings_from_summary(laser_settings);
|
|
}
|
|
State::MainLoop => {
|
|
laser.poll_and_update_output_current();
|
|
laser.poll_pd_mon_v();
|
|
|
|
net::net::eth_update_iface_poll_timer();
|
|
|
|
if thermostat.poll_adc() {
|
|
thermostat.update_pid();
|
|
if thermostat.get_temp_mon_status().over_temp_alarm {
|
|
laser.power_down();
|
|
thermostat.power_down();
|
|
}
|
|
|
|
net::net::for_each(|mut socket, id| {
|
|
if net::net::eth_is_socket_active(socket) && net::net::eth_is_socket_connected(socket) {
|
|
if active_report[id] {
|
|
if net::net::eth_can_sock_send(socket) {
|
|
net::cmd_handler::send_status_report(
|
|
eth_data_buffer,
|
|
&mut laser,
|
|
&mut thermostat,
|
|
&mut socket,
|
|
);
|
|
}
|
|
}
|
|
} else {
|
|
active_report[id] = false;
|
|
}
|
|
});
|
|
|
|
thermostat.start_tec_readings_conversion();
|
|
}
|
|
|
|
net::net::for_each(|mut socket, id| {
|
|
if net::net::eth_is_socket_active(socket) && net::net::eth_is_socket_connected(socket) {
|
|
if net::net::eth_can_sock_recv(socket) && net::net::eth_can_sock_send(socket) {
|
|
let bytes = net::net::eth_recv(eth_data_buffer, socket);
|
|
if bytes != 0 {
|
|
info!("Ts: {:?}", sys_timer::now());
|
|
debug!("Number of bytes recv: {:?}", bytes);
|
|
// State Transition
|
|
net::cmd_handler::execute_cmd(
|
|
eth_data_buffer,
|
|
bytes,
|
|
&mut socket,
|
|
&mut laser,
|
|
&mut thermostat,
|
|
&mut state,
|
|
&mut device_settings,
|
|
&mut active_report[id],
|
|
);
|
|
}
|
|
}
|
|
}
|
|
})
|
|
}
|
|
State::SaveLdThermostatSettings => {
|
|
// State Transition
|
|
state = State::MainLoop;
|
|
|
|
wd.feed();
|
|
let mut store_value_buf = [0u8; 1024];
|
|
match flash_store.write_value(CONFIG_KEY[1], &laser.get_settings_summary(), &mut store_value_buf) {
|
|
Ok(()) => {
|
|
debug!("Laser Diode Settings is stored in flash");
|
|
}
|
|
Err(e) => {
|
|
debug!("Cannot Store Flash: {:?}", e);
|
|
}
|
|
}
|
|
|
|
wd.feed();
|
|
match flash_store.write_value(CONFIG_KEY[2], &thermostat.get_settings_summary(), &mut store_value_buf) {
|
|
Ok(()) => {
|
|
debug!("Thermostat Settings is stored in flash");
|
|
}
|
|
Err(e) => {
|
|
debug!("Cannot Store Flash: {:?}", e);
|
|
}
|
|
}
|
|
}
|
|
State::SaveDeviceSettings => {
|
|
// State Transition
|
|
state = State::MainLoop;
|
|
|
|
wd.feed();
|
|
let mut store_value_buf = [0u8; 1024];
|
|
match flash_store.write_value(CONFIG_KEY[0], &device_settings, &mut store_value_buf) {
|
|
Ok(()) => {
|
|
debug!("Device Settings is stored in flash");
|
|
}
|
|
Err(e) => {
|
|
debug!("Cannot Store Flash: {:?}", e);
|
|
}
|
|
}
|
|
}
|
|
State::PrepareForHardReset => {
|
|
// State Transition
|
|
state = State::HardReset;
|
|
|
|
wd.feed();
|
|
laser.power_down();
|
|
thermostat.power_down();
|
|
net::net::for_each(|mut socket, _| {
|
|
if net::net::eth_is_socket_active(socket) {
|
|
net::cmd_handler::send_response(
|
|
eth_data_buffer,
|
|
net::cmd_handler::ResponseEnum::HardReset,
|
|
None,
|
|
&mut socket,
|
|
);
|
|
}
|
|
});
|
|
}
|
|
State::HardReset => {
|
|
wd.feed();
|
|
laser.power_down();
|
|
thermostat.power_down();
|
|
let mut any_socket_alive = false;
|
|
net::net::for_each(|socket, _| {
|
|
if net::net::eth_is_socket_active(socket) {
|
|
net::net::eth_close_socket(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();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|