use crate::firmware::boot_target::BootTarget; use crate::firmware::firmware_state::{FirmwareState, LoadCartridgeStep, ResetStep}; use crate::firmware::prometeu_context::PrometeuContext; use crate::hardware::{HardwareBridge, InputSignals}; use crate::model::Cartridge; use crate::prometeu_hub::PrometeuHub; use crate::prometeu_os::PrometeuOS; use crate::virtual_machine::VirtualMachine; use crate::telemetry::CertificationConfig; pub struct Firmware { pub vm: VirtualMachine, pub os: PrometeuOS, pub hub: PrometeuHub, pub state: FirmwareState, pub boot_target: BootTarget, state_initialized: bool, } impl Firmware { pub fn new(cap_config: Option) -> Self { Self { vm: VirtualMachine::default(), os: PrometeuOS::new(cap_config), hub: PrometeuHub::new(), state: FirmwareState::Reset(ResetStep), boot_target: BootTarget::Hub, state_initialized: false, } } pub fn step_frame(&mut self, signals: &InputSignals, hw: &mut dyn HardwareBridge) { // Updates input once per host frame hw.pad_mut().begin_frame(signals); hw.touch_mut().begin_frame(signals); if !self.state_initialized { self.on_enter(signals, hw); self.state_initialized = true; } if let Some(next_state) = self.on_update(signals, hw) { self.change_state(next_state, signals, hw); } } pub fn change_state(&mut self, new_state: FirmwareState, signals: &InputSignals, hw: &mut dyn HardwareBridge) { self.on_exit(signals, hw); self.state = new_state; self.state_initialized = false; // Enters the new state immediately self.on_enter(signals, hw); self.state_initialized = true; } fn on_enter(&mut self, signals: &InputSignals, hw: &mut dyn HardwareBridge) { let mut req = PrometeuContext { vm: &mut self.vm, os: &mut self.os, hub: &mut self.hub, boot_target: &self.boot_target, signals, hw, }; match &mut self.state { FirmwareState::Reset(s) => s.on_enter(&mut req), FirmwareState::SplashScreen(s) => s.on_enter(&mut req), FirmwareState::LaunchHub(s) => s.on_enter(&mut req), FirmwareState::HubHome(s) => s.on_enter(&mut req), FirmwareState::LoadCartridge(s) => s.on_enter(&mut req), FirmwareState::GameRunning(s) => s.on_enter(&mut req), FirmwareState::AppCrashes(s) => s.on_enter(&mut req), } } fn on_update(&mut self, signals: &InputSignals, hw: &mut dyn HardwareBridge) -> Option { let mut req = PrometeuContext { vm: &mut self.vm, os: &mut self.os, hub: &mut self.hub, boot_target: &self.boot_target, signals, hw, }; match &mut self.state { FirmwareState::Reset(s) => s.on_update(&mut req), FirmwareState::SplashScreen(s) => s.on_update(&mut req), FirmwareState::LaunchHub(s) => s.on_update(&mut req), FirmwareState::HubHome(s) => s.on_update(&mut req), FirmwareState::LoadCartridge(s) => s.on_update(&mut req), FirmwareState::GameRunning(s) => s.on_update(&mut req), FirmwareState::AppCrashes(s) => s.on_update(&mut req), } } fn on_exit(&mut self, signals: &InputSignals, hw: &mut dyn HardwareBridge) { let mut req = PrometeuContext { vm: &mut self.vm, os: &mut self.os, hub: &mut self.hub, boot_target: &self.boot_target, signals, hw, }; match &mut self.state { FirmwareState::Reset(s) => s.on_exit(&mut req), FirmwareState::SplashScreen(s) => s.on_exit(&mut req), FirmwareState::LaunchHub(s) => s.on_exit(&mut req), FirmwareState::HubHome(s) => s.on_exit(&mut req), FirmwareState::LoadCartridge(s) => s.on_exit(&mut req), FirmwareState::GameRunning(s) => s.on_exit(&mut req), FirmwareState::AppCrashes(s) => s.on_exit(&mut req), } } pub fn load_cartridge(&mut self, cartridge: Cartridge) { self.state = FirmwareState::LoadCartridge(LoadCartridgeStep { cartridge }); self.state_initialized = false; } }