#![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 crate::net::net::IpSettings; 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}; #[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, SaveFlashSettings, 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(); loop { wd.feed(); net::net::eth_poll_and_update_link_speed(); 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 => { let mut eth_is_pending = false; let mut has_temp_reading = false; laser.poll_and_update_output_current(); if thermostat.poll_adc() { has_temp_reading = true; 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] { unsafe { net::cmd_handler::send_status_report(&mut ETH_DATA_BUFFER, &mut laser, &mut thermostat, &mut socket); } } } else { active_report[id] = false; } }); } cortex_m::interrupt::free(|cs| { eth_is_pending = net::net::is_pending(cs); net::net::clear_pending(cs); } ); if eth_is_pending { net::net::for_each(|mut socket, id| { if net::net::eth_is_socket_active(socket) && net::net::eth_is_socket_connected(socket){ unsafe{ let bytes = net::net::eth_recv(&mut 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(&mut ETH_DATA_BUFFER, bytes, &mut socket, &mut laser, &mut thermostat, &mut state, &mut device_settings, &mut active_report[id]); } } } if has_temp_reading { thermostat.start_tec_readings_conversion(); } }) }; } State::SaveFlashSettings => { // 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); } } wd.feed(); 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::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) { unsafe { net::cmd_handler::send_response(&mut 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(); } } } } }