kirdy/src/main.rs

277 lines
9.8 KiB
Rust

#![cfg_attr(not(test), no_main)]
#![cfg_attr(not(test), no_std)]
use cortex_m_rt::entry;
use log::{debug, info};
use stm32f4xx_hal::pac::{CorePeripherals, Peripherals};
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,
}
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(),
};
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;
debug!("Found Device Settings");
}
Ok(None) => {
debug!("Flash does not have Device Settings");
continue;
}
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();
device_settings = device_settings_flash;
thermostat.load_settings_from_summary(thermostat_settings);
laser.load_settings_from_summary(laser_settings);
}
State::MainLoop => {
laser.poll_and_update_output_current();
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.set_pid_engaged(false);
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();
}
}
}
}
}