forked from M-Labs/kirdy
258 lines
9.2 KiB
Rust
258 lines
9.2 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 core::ptr::addr_of_mut;
|
|
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,
|
|
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();
|
|
|
|
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;
|
|
|
|
laser.poll_and_update_output_current();
|
|
|
|
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] {
|
|
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();
|
|
}
|
|
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){
|
|
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();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|