2026-01-22 10:36:55 +00:00

149 lines
6.0 KiB
Rust

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 system. It manages the high-level state machine,
/// transitioning between system states like booting, the Hub launcher, and
/// actual application execution.
pub struct Firmware {
/// The Virtual Machine instance.
pub vm: VirtualMachine,
/// The System Operating logic (syscalls, telemetry, logs).
pub os: PrometeuOS,
/// The System UI / Launcher environment.
pub hub: PrometeuHub,
/// Current high-level state of the system.
pub state: FirmwareState,
/// Desired execution target resolved at boot.
pub boot_target: BootTarget,
/// Tracking flag to ensure `on_enter` is called exactly once per state transition.
state_initialized: bool,
}
impl Firmware {
/// Initializes the firmware in the `Reset` state.
pub fn new(cap_config: Option<CertificationConfig>) -> 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<FirmwareState> {
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;
}
}