#![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(); } } } } }