Use FSM to manage device state in main loop

This commit is contained in:
linuswck 2024-03-04 11:08:26 +08:00
parent 3aca712e1d
commit df939eb9a3
1 changed files with 86 additions and 65 deletions

View File

@ -35,6 +35,15 @@ pub struct DeviceSettings{
report_readings: bool, report_readings: bool,
} }
#[derive(Default)]
enum State {
#[default]
LoadFlashSettings,
MainLoop,
SaveFlashSettings,
HardReset,
}
#[cfg(not(test))] #[cfg(not(test))]
#[entry] #[entry]
fn main() -> ! { fn main() -> ! {
@ -84,84 +93,96 @@ fn main() -> ! {
report_readings: false, report_readings: false,
}; };
let mut state = State::default();
loop { loop {
wd.feed(); wd.feed();
if !should_reset { match state {
let mut eth_is_pending = false; State::LoadFlashSettings => {
let mut has_temp_reading = false; wd.feed();
// Todo
// State Transition
state = State::MainLoop;
}
State::MainLoop => {
let mut eth_is_pending = false;
let mut has_temp_reading = false;
laser.poll_and_update_output_current(); laser.poll_and_update_output_current();
if thermostat.poll_adc() { if thermostat.poll_adc() {
has_temp_reading = true; has_temp_reading = true;
thermostat.update_pid(); thermostat.update_pid();
if thermostat.get_temp_mon_status().over_temp_alarm { if thermostat.get_temp_mon_status().over_temp_alarm {
laser.power_down(); laser.power_down();
thermostat.set_pid_engaged(false); thermostat.set_pid_engaged(false);
thermostat.power_down(); thermostat.power_down();
}
if net::net::eth_is_socket_active() {
if device_settings.report_readings {
unsafe {
net::cmd_handler::send_status_report(&mut ETH_DATA_BUFFER, &mut laser, &mut thermostat);
}
}
}
} }
// info!("curr_dac_vfb: {:?}", volt_fmt.with(thermostat.get_dac_vfb()));
// info!("curr_vref: {:?}", volt_fmt.with(thermostat.get_vref()));
// info!("curr_tec_i: {:?}", amp_fmt.with(thermostat.get_tec_i()));
// info!("curr_tec_v: {:?}", volt_fmt.with(thermostat.get_tec_v()));
// info!("curr_ld_drive_cuurent: {:?}", milli_amp_fmt.with(laser.get_ld_drive_current()));
// info!("pd_mon_v: {:?}", volt_fmt.with(laser.pd_mon_status().v));
// info!("power_excursion: {:?}", laser.pd_mon_status().pwr_excursion);
// info!("Termination Status: {:?}", laser.get_term_status());
if net::net::eth_is_socket_active() { if net::net::eth_is_socket_active() {
if device_settings.report_readings { cortex_m::interrupt::free(|cs|
unsafe { {
net::cmd_handler::send_status_report(&mut ETH_DATA_BUFFER, &mut laser, &mut thermostat); eth_is_pending = net::net::is_pending(cs);
}
);
if eth_is_pending {
unsafe{
cortex_m::interrupt::free(|cs| {
net::net::clear_pending(cs);
});
let bytes = net::net::eth_recv(&mut ETH_DATA_BUFFER);
if bytes != 0 {
info!("Ts: {:?}", sys_timer::now());
debug!("Number of bytes recv: {:?}", bytes);
(laser, thermostat, should_reset, device_settings) = net::cmd_handler::execute_cmd(&mut ETH_DATA_BUFFER, bytes, laser, thermostat, device_settings);
}
} }
} }
} if has_temp_reading {
} thermostat.start_tec_readings_conversion();
if net::net::eth_is_socket_active() {
cortex_m::interrupt::free(|cs|
{
eth_is_pending = net::net::is_pending(cs);
}
);
if eth_is_pending {
unsafe{
cortex_m::interrupt::free(|cs| {
net::net::clear_pending(cs);
});
let bytes = net::net::eth_recv(&mut ETH_DATA_BUFFER);
if bytes != 0 {
info!("Ts: {:?}", sys_timer::now());
debug!("Number of bytes recv: {:?}", bytes);
(laser, thermostat, should_reset, device_settings) = net::cmd_handler::execute_cmd(&mut ETH_DATA_BUFFER, bytes, laser, thermostat, device_settings);
}
} }
} }
if has_temp_reading { else {
thermostat.start_tec_readings_conversion(); device_settings.report_readings = false;
}
// State Transition
if should_reset {
state = State::HardReset;
} }
} }
else { State::SaveFlashSettings => {
device_settings.report_readings = false; wd.feed();
} // Todo
} else { // State Transition
// Should reset, close all TCP sockets. state = State::MainLoop;
let mut any_socket_alive = false;
if net::net::eth_is_socket_active() {
net::net::eth_close_socket();
any_socket_alive = true;
} }
State::HardReset => {
wd.feed();
laser.power_down();
thermostat.power_down();
let mut any_socket_alive = false;
if net::net::eth_is_socket_active() {
net::net::eth_close_socket();
any_socket_alive = true;
}
// Must let loop run for one more cycle to poll server for RST to be sent, // 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. // this makes sure system does not reset right after socket.abort() is called.
if !any_socket_alive { if !any_socket_alive {
SCB::sys_reset(); SCB::sys_reset();
}
} }
} }
} }