2026-01-19 07:28:14 +00:00

122 lines
4.4 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;
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<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,
}
}
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<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),
}
}
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;
}
}