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; /// PROMETEU Firmware. /// /// The central orchestrator of the console. The firmware acts as the /// "Control Unit", managing the high-level state machine of the system. /// /// It is responsible for transitioning between different modes of operation, /// such as showing the splash screen, running the Hub (launcher), or /// executing a game/app. /// /// ### Execution Loop: /// The firmware is designed to be ticked once per frame (60Hz). During each /// tick, it: /// 1. Updates peripherals with the latest input signals. /// 2. Delegates the logic update to the current active state. /// 3. Handles state transitions (e.g., from Loading to Playing). pub struct Firmware { /// The execution engine (PVM) for user applications. pub vm: VirtualMachine, /// The underlying OS services (Syscalls, Filesystem, Telemetry). pub os: PrometeuOS, /// The internal state of the system launcher (Hub). pub hub: PrometeuHub, /// The current operational state (e.g., Reset, SplashScreen, GameRunning). pub state: FirmwareState, /// The desired application to run after boot (Hub or specific Cartridge). pub boot_target: BootTarget, /// State-machine lifecycle tracker. state_initialized: bool, } impl Firmware { /// Initializes the firmware in the `Reset` state. 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, } } /// The main entry point for the Host to advance the system logic. /// /// This method is called exactly once per Host frame (60Hz). /// It updates peripheral signals and delegates the logic to the current state. pub fn tick(&mut self, signals: &InputSignals, hw: &mut dyn HardwareBridge) { // 0. Process asset commits at the beginning of the frame boundary. hw.assets_mut().apply_commits(); // 1. Update the peripheral state using the latest signals from the Host. // This ensures input is consistent throughout the entire update. hw.pad_mut().begin_frame(signals); hw.touch_mut().begin_frame(signals); // 2. State machine lifecycle management. if !self.state_initialized { self.on_enter(signals, hw); self.state_initialized = true; } // 3. Update the current state and check for transitions. if let Some(next_state) = self.on_update(signals, hw) { self.change_state(next_state, signals, hw); } } /// Transitions the system to a new state, handling lifecycle hooks. 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; // Enter the new state immediately to avoid "empty" frames during transitions. self.on_enter(signals, hw); self.state_initialized = true; } /// Dispatches the `on_enter` event to the current state implementation. 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), } } /// Dispatches the `on_update` event to the current state implementation. /// Returns an optional `FirmwareState` if a transition is requested. 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), } } /// Dispatches the `on_exit` event to the current state implementation. 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; } }