implements PLN-0105
This commit is contained in:
parent
d0a2682366
commit
1d6b799960
@ -3,7 +3,7 @@ use crate::firmware::firmware_state::{FirmwareState, LoadCartridgeStep, ResetSte
|
||||
use crate::firmware::prometeu_context::PrometeuContext;
|
||||
use prometeu_hal::cartridge::Cartridge;
|
||||
use prometeu_hal::telemetry::CertificationConfig;
|
||||
use prometeu_hal::{HardwareBridge, InputSignals};
|
||||
use prometeu_hal::{InputSignals, RuntimePlatform};
|
||||
use prometeu_system::{PrometeuHub, SystemOS};
|
||||
use prometeu_vm::VirtualMachine;
|
||||
|
||||
@ -54,24 +54,24 @@ impl Firmware {
|
||||
///
|
||||
/// 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) {
|
||||
pub fn tick(&mut self, signals: &InputSignals, platform: &mut dyn RuntimePlatform) {
|
||||
// 0. Process asset commits at the beginning of the frame boundary.
|
||||
hw.assets_mut().apply_commits();
|
||||
platform.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);
|
||||
platform.input_mut().pad_mut().begin_frame(signals);
|
||||
platform.input_mut().touch_mut().begin_frame(signals);
|
||||
|
||||
// 2. State machine lifecycle management.
|
||||
if !self.state_initialized {
|
||||
self.on_enter(signals, hw);
|
||||
self.on_enter(signals, platform);
|
||||
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);
|
||||
if let Some(next_state) = self.on_update(signals, platform) {
|
||||
self.change_state(next_state, signals, platform);
|
||||
}
|
||||
}
|
||||
|
||||
@ -80,26 +80,26 @@ impl Firmware {
|
||||
&mut self,
|
||||
new_state: FirmwareState,
|
||||
signals: &InputSignals,
|
||||
hw: &mut dyn HardwareBridge,
|
||||
platform: &mut dyn RuntimePlatform,
|
||||
) {
|
||||
self.on_exit(signals, hw);
|
||||
self.on_exit(signals, platform);
|
||||
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.on_enter(signals, platform);
|
||||
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) {
|
||||
fn on_enter(&mut self, signals: &InputSignals, platform: &mut dyn RuntimePlatform) {
|
||||
let mut req = PrometeuContext {
|
||||
vm: &mut self.vm,
|
||||
os: &mut self.os,
|
||||
hub: &mut self.hub,
|
||||
boot_target: &self.boot_target,
|
||||
signals,
|
||||
hw,
|
||||
platform,
|
||||
};
|
||||
match &mut self.state {
|
||||
FirmwareState::Reset(s) => s.on_enter(&mut req),
|
||||
@ -118,7 +118,7 @@ impl Firmware {
|
||||
fn on_update(
|
||||
&mut self,
|
||||
signals: &InputSignals,
|
||||
hw: &mut dyn HardwareBridge,
|
||||
platform: &mut dyn RuntimePlatform,
|
||||
) -> Option<FirmwareState> {
|
||||
let mut req = PrometeuContext {
|
||||
vm: &mut self.vm,
|
||||
@ -126,7 +126,7 @@ impl Firmware {
|
||||
hub: &mut self.hub,
|
||||
boot_target: &self.boot_target,
|
||||
signals,
|
||||
hw,
|
||||
platform,
|
||||
};
|
||||
match &mut self.state {
|
||||
FirmwareState::Reset(s) => s.on_update(&mut req),
|
||||
@ -141,14 +141,14 @@ impl Firmware {
|
||||
}
|
||||
|
||||
/// Dispatches the `on_exit` event to the current state implementation.
|
||||
fn on_exit(&mut self, signals: &InputSignals, hw: &mut dyn HardwareBridge) {
|
||||
fn on_exit(&mut self, signals: &InputSignals, platform: &mut dyn RuntimePlatform) {
|
||||
let mut req = PrometeuContext {
|
||||
vm: &mut self.vm,
|
||||
os: &mut self.os,
|
||||
hub: &mut self.hub,
|
||||
boot_target: &self.boot_target,
|
||||
signals,
|
||||
hw,
|
||||
platform,
|
||||
};
|
||||
match &mut self.state {
|
||||
FirmwareState::Reset(s) => s.on_exit(&mut req),
|
||||
|
||||
@ -2,10 +2,7 @@ use crate::firmware::firmware_state::{FirmwareState, LaunchHubStep};
|
||||
use crate::firmware::prometeu_context::PrometeuContext;
|
||||
use prometeu_hal::color::Color;
|
||||
use prometeu_hal::log::{LogLevel, LogSource};
|
||||
use prometeu_hal::{
|
||||
FrameId, GfxUiCommand, LegacyHardwareRenderSubmissionSink, RenderSubmission,
|
||||
RenderSubmissionSink, ShellUiFramePacket,
|
||||
};
|
||||
use prometeu_hal::{FrameId, GfxUiCommand, RenderSubmission, ShellUiFramePacket};
|
||||
use prometeu_system::CrashReport;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@ -24,15 +21,16 @@ impl AppCrashesStep {
|
||||
|
||||
pub fn on_update(&mut self, ctx: &mut PrometeuContext) -> Option<FirmwareState> {
|
||||
// Update peripherals for input on the crash screen
|
||||
ctx.hw.pad_mut().begin_frame(ctx.signals);
|
||||
ctx.platform.input_mut().pad_mut().begin_frame(ctx.signals);
|
||||
|
||||
let packet = ShellUiFramePacket::new(vec![GfxUiCommand::Clear { color: Color::RED }]);
|
||||
LegacyHardwareRenderSubmissionSink::new(ctx.hw)
|
||||
ctx.platform
|
||||
.render_submission_sink()
|
||||
.submit_render_submission(RenderSubmission::shell_ui(FrameId::ZERO, packet))
|
||||
.expect("firmware crash render submission should publish");
|
||||
|
||||
// If START is pressed, return to the Hub
|
||||
if ctx.hw.pad().start().down {
|
||||
if ctx.platform.input().pad().start().down {
|
||||
return Some(FirmwareState::LaunchHub(LaunchHubStep));
|
||||
}
|
||||
|
||||
|
||||
@ -36,7 +36,7 @@ impl GameRunningStep {
|
||||
return Some(FirmwareState::AppCrashes(AppCrashesStep { report }));
|
||||
}
|
||||
|
||||
let result = ctx.os.vm().tick(ctx.vm, ctx.signals, ctx.hw);
|
||||
let result = ctx.os.vm().tick(ctx.vm, ctx.signals, ctx.platform);
|
||||
|
||||
if let Some(report) = result {
|
||||
let _ = ctx.os.lifecycle().crash_task(self.task_id, Some(&report));
|
||||
|
||||
@ -16,7 +16,7 @@ impl HubHomeStep {
|
||||
}
|
||||
|
||||
pub fn on_update(&mut self, ctx: &mut PrometeuContext) -> Option<FirmwareState> {
|
||||
let outcome = ctx.hub.update_shell_profile(ctx.os, ctx.vm, ctx.signals, ctx.hw);
|
||||
let outcome = ctx.hub.update_shell_profile(ctx.os, ctx.vm, ctx.signals, ctx.platform);
|
||||
if let Some(report) = outcome.crash {
|
||||
return Some(FirmwareState::AppCrashes(AppCrashesStep { report }));
|
||||
}
|
||||
|
||||
@ -30,7 +30,7 @@ impl LoadCartridgeStep {
|
||||
);
|
||||
|
||||
// Initialize Asset Manager
|
||||
ctx.hw.assets_mut().initialize_for_cartridge(
|
||||
ctx.platform.assets_mut().initialize_for_cartridge(
|
||||
self.cartridge.asset_table.clone(),
|
||||
self.cartridge.preload.clone(),
|
||||
self.cartridge.assets.clone(),
|
||||
|
||||
@ -59,7 +59,7 @@ impl ShellRunningStep {
|
||||
}
|
||||
}
|
||||
|
||||
let outcome = ctx.hub.update_shell_profile(ctx.os, ctx.vm, ctx.signals, ctx.hw);
|
||||
let outcome = ctx.hub.update_shell_profile(ctx.os, ctx.vm, ctx.signals, ctx.platform);
|
||||
|
||||
if let Some(report) = outcome.crash {
|
||||
let _ = ctx.os.lifecycle().crash_task(self.task_id, Some(&report));
|
||||
|
||||
@ -3,10 +3,7 @@ use crate::firmware::prometeu_context::PrometeuContext;
|
||||
use prometeu_hal::color::Color;
|
||||
use prometeu_hal::log::{LogLevel, LogSource};
|
||||
use prometeu_hal::primitives::Rect;
|
||||
use prometeu_hal::{
|
||||
FrameId, GfxUiCommand, LegacyHardwareRenderSubmissionSink, RenderSubmission,
|
||||
RenderSubmissionSink, ShellUiFramePacket,
|
||||
};
|
||||
use prometeu_hal::{FrameId, GfxUiCommand, RenderSubmission, ShellUiFramePacket};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct SplashScreenStep {
|
||||
@ -17,7 +14,7 @@ impl SplashScreenStep {
|
||||
pub fn on_enter(&mut self, ctx: &mut PrometeuContext) {
|
||||
ctx.os.log(LogLevel::Info, LogSource::Pos, 0, "Showing SplashScreen".to_string());
|
||||
// Play sound on enter
|
||||
// ctx.hw.audio_mut().play(0, 0, 0, 255, 127, 1.0, 0, LoopMode::Off);
|
||||
// ctx.platform.audio_mut().play(0, 0, 0, 255, 127, 1.0, 0, LoopMode::Off);
|
||||
}
|
||||
|
||||
pub fn on_update(&mut self, ctx: &mut PrometeuContext) -> Option<FirmwareState> {
|
||||
@ -25,10 +22,10 @@ impl SplashScreenStep {
|
||||
const TOTAL_DURATION: u32 = 240; // 4 seconds total (updated from 2s based on total_duration logic)
|
||||
|
||||
// Update peripherals for input
|
||||
ctx.hw.pad_mut().begin_frame(ctx.signals);
|
||||
ctx.platform.input_mut().pad_mut().begin_frame(ctx.signals);
|
||||
|
||||
// Draw expanding square
|
||||
let (sw, sh) = ctx.hw.gfx().size();
|
||||
let (sw, sh) = ctx.platform.display_size();
|
||||
let max_size = (sw.min(sh) as i32 / 2).max(1);
|
||||
|
||||
let current_size = if self.frame < ANIMATION_DURATION {
|
||||
@ -47,13 +44,14 @@ impl SplashScreenStep {
|
||||
color: Color::WHITE,
|
||||
},
|
||||
]);
|
||||
LegacyHardwareRenderSubmissionSink::new(ctx.hw)
|
||||
ctx.platform
|
||||
.render_submission_sink()
|
||||
.submit_render_submission(RenderSubmission::shell_ui(FrameId::ZERO, packet))
|
||||
.expect("firmware splash render submission should publish");
|
||||
|
||||
// Transition logic
|
||||
// If any button is pressed at any time after the animation ends
|
||||
if self.frame >= ANIMATION_DURATION && ctx.hw.pad().any() {
|
||||
if self.frame >= ANIMATION_DURATION && ctx.platform.input().pad().any() {
|
||||
return Some(FirmwareState::LaunchHub(LaunchHubStep));
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
use crate::firmware::boot_target::BootTarget;
|
||||
use prometeu_hal::{HardwareBridge, InputSignals};
|
||||
use prometeu_hal::{InputSignals, RuntimePlatform};
|
||||
use prometeu_system::{PrometeuHub, SystemOS};
|
||||
use prometeu_vm::VirtualMachine;
|
||||
|
||||
@ -9,5 +9,5 @@ pub struct PrometeuContext<'a> {
|
||||
pub hub: &'a mut PrometeuHub,
|
||||
pub boot_target: &'a BootTarget,
|
||||
pub signals: &'a InputSignals,
|
||||
pub hw: &'a mut dyn HardwareBridge,
|
||||
pub platform: &'a mut dyn RuntimePlatform,
|
||||
}
|
||||
|
||||
@ -215,6 +215,10 @@ impl TelemetryPlatform for NoopTelemetryPlatform {}
|
||||
static LEGACY_NOOP_TELEMETRY: NoopTelemetryPlatform = NoopTelemetryPlatform;
|
||||
|
||||
pub trait RuntimePlatform {
|
||||
fn display_size(&self) -> (usize, usize) {
|
||||
(480, 270)
|
||||
}
|
||||
|
||||
fn render_submission_sink(&mut self) -> &mut dyn RenderSubmissionSink;
|
||||
fn render_backend(&mut self) -> &mut dyn RenderBackend;
|
||||
fn game2d_frame_composer(&mut self) -> &mut dyn Game2DFrameComposer;
|
||||
|
||||
@ -3,7 +3,7 @@ use crate::os::SystemOS;
|
||||
use prometeu_hal::app_mode::AppMode;
|
||||
use prometeu_hal::cartridge::Cartridge;
|
||||
use prometeu_hal::telemetry::{CertificationConfig, TelemetryFrame};
|
||||
use prometeu_hal::{HardwareBridge, InputSignals};
|
||||
use prometeu_hal::{HardwareBridge, InputSignals, RuntimePlatform};
|
||||
use prometeu_vm::VirtualMachine;
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
@ -25,7 +25,7 @@ impl<'a> VmFacade<'a> {
|
||||
&mut self,
|
||||
vm: &mut VirtualMachine,
|
||||
signals: &InputSignals,
|
||||
hw: &mut dyn HardwareBridge,
|
||||
platform: &mut dyn RuntimePlatform,
|
||||
) -> Option<CrashReport> {
|
||||
self.os.vm_runtime.tick(
|
||||
&mut self.os.log_service,
|
||||
@ -36,7 +36,7 @@ impl<'a> VmFacade<'a> {
|
||||
&mut self.os.next_handle,
|
||||
vm,
|
||||
signals,
|
||||
hw,
|
||||
platform,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@ -2,8 +2,8 @@ use crate::{CrashReport, SystemOS};
|
||||
use prometeu_hal::color::Color;
|
||||
use prometeu_hal::primitives::Rect;
|
||||
use prometeu_hal::{
|
||||
FrameId, GfxUiCommand, HardwareBridge, InputSignals, LegacyHardwareRenderSubmissionSink,
|
||||
RenderSubmission, RenderSubmissionSink, ShellUiFramePacket,
|
||||
FrameId, GfxUiCommand, InputPlatform, InputSignals, RenderSubmission, RuntimePlatform,
|
||||
ShellUiFramePacket,
|
||||
};
|
||||
use prometeu_vm::VirtualMachine;
|
||||
|
||||
@ -101,31 +101,35 @@ impl PrometeuHub {
|
||||
pub fn gui_update(
|
||||
&mut self,
|
||||
os: &mut SystemOS,
|
||||
hw: &mut dyn HardwareBridge,
|
||||
platform: &mut dyn RuntimePlatform,
|
||||
) -> Option<SystemProfileAction> {
|
||||
let in_shell = os.windows().focused_window().is_some();
|
||||
|
||||
if !in_shell {
|
||||
if !self.home_input_armed {
|
||||
self.home_input_armed = !activation_input_down(hw);
|
||||
self.home_input_armed = !activation_input_down(platform.input());
|
||||
return None;
|
||||
}
|
||||
} else {
|
||||
self.home_input_armed = false;
|
||||
}
|
||||
|
||||
if let Some(action) =
|
||||
action_for_click(in_shell, hw.touch().x(), hw.touch().y(), hw.touch().f().pressed)
|
||||
{
|
||||
let input = platform.input();
|
||||
if let Some(action) = action_for_click(
|
||||
in_shell,
|
||||
input.touch().x(),
|
||||
input.touch().y(),
|
||||
input.touch().f().pressed,
|
||||
) {
|
||||
return Some(action);
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub fn render(&mut self, os: &mut SystemOS, hw: &mut dyn HardwareBridge) {
|
||||
let pointer_x = hw.touch().x();
|
||||
let pointer_y = hw.touch().y();
|
||||
pub fn render(&mut self, os: &mut SystemOS, platform: &mut dyn RuntimePlatform) {
|
||||
let pointer_x = platform.input().touch().x();
|
||||
let pointer_y = platform.input().touch().y();
|
||||
|
||||
let packet = if os.windows().window_count() == 0 {
|
||||
render_home_packet(pointer_x, pointer_y)
|
||||
@ -143,7 +147,8 @@ impl PrometeuHub {
|
||||
}
|
||||
ShellUiFramePacket::new(commands)
|
||||
};
|
||||
LegacyHardwareRenderSubmissionSink::new(hw)
|
||||
platform
|
||||
.render_submission_sink()
|
||||
.submit_render_submission(RenderSubmission::shell_ui(FrameId::ZERO, packet))
|
||||
.expect("hub render submission should publish");
|
||||
}
|
||||
@ -153,20 +158,20 @@ impl PrometeuHub {
|
||||
os: &mut SystemOS,
|
||||
vm: &mut VirtualMachine,
|
||||
signals: &InputSignals,
|
||||
hw: &mut dyn HardwareBridge,
|
||||
platform: &mut dyn RuntimePlatform,
|
||||
) -> SystemProfileUpdate {
|
||||
let mut crash = None;
|
||||
let mut action = self.gui_update(os, hw);
|
||||
let mut action = self.gui_update(os, platform);
|
||||
|
||||
if os.windows().focused_window().is_some() {
|
||||
if hw.pad().start().down {
|
||||
if platform.input().pad().start().down {
|
||||
action = Some(SystemProfileAction::CloseShell);
|
||||
} else if action != Some(SystemProfileAction::CloseShell) {
|
||||
crash = os.vm().tick(vm, signals, hw);
|
||||
crash = os.vm().tick(vm, signals, platform);
|
||||
}
|
||||
}
|
||||
|
||||
self.render(os, hw);
|
||||
self.render(os, platform);
|
||||
|
||||
SystemProfileUpdate { crash, action }
|
||||
}
|
||||
@ -191,8 +196,11 @@ fn rect_contains(rect: Rect, x: i32, y: i32) -> bool {
|
||||
x >= rect.x && x < rect.x + rect.w && y >= rect.y && y < rect.y + rect.h
|
||||
}
|
||||
|
||||
fn activation_input_down(hw: &dyn HardwareBridge) -> bool {
|
||||
hw.touch().f().down || hw.pad().a().down || hw.pad().b().down || hw.pad().start().down
|
||||
fn activation_input_down(input: &dyn InputPlatform) -> bool {
|
||||
input.touch().f().down
|
||||
|| input.pad().a().down
|
||||
|| input.pad().b().down
|
||||
|| input.pad().start().down
|
||||
}
|
||||
|
||||
fn render_home_packet(pointer_x: i32, pointer_y: i32) -> ShellUiFramePacket {
|
||||
|
||||
@ -135,7 +135,7 @@ impl VirtualMachineRuntime {
|
||||
next_handle: &mut u32,
|
||||
vm: &mut VirtualMachine,
|
||||
signals: &InputSignals,
|
||||
hw: &mut dyn HardwareBridge,
|
||||
platform: &mut dyn RuntimePlatform,
|
||||
) -> Option<CrashReport> {
|
||||
let start = Instant::now();
|
||||
self.tick_index += 1;
|
||||
@ -145,8 +145,6 @@ impl VirtualMachineRuntime {
|
||||
}
|
||||
|
||||
self.update_fs(log_service, fs, fs_state);
|
||||
let mut platform = LegacyHardwareRuntimePlatform::new(hw);
|
||||
|
||||
if !self.logical_frame_active {
|
||||
if RenderManager::policy_for_app_mode(self.current_cartridge_app_mode)
|
||||
.uses_frame_scheduler()
|
||||
@ -157,7 +155,7 @@ impl VirtualMachineRuntime {
|
||||
}
|
||||
self.logical_frame_active = true;
|
||||
self.logical_frame_remaining_cycles = Self::CYCLES_PER_LOGICAL_FRAME;
|
||||
self.begin_logical_frame(signals, &mut platform);
|
||||
self.begin_logical_frame(signals, platform);
|
||||
|
||||
if self.needs_prepare_entry_call || vm.call_stack_is_empty() {
|
||||
vm.prepare_boot_call();
|
||||
@ -185,7 +183,7 @@ impl VirtualMachineRuntime {
|
||||
|
||||
if budget > 0 {
|
||||
let run_result = {
|
||||
let mut ctx = HostContext::new_platform(Some(&mut platform));
|
||||
let mut ctx = HostContext::new_platform(Some(platform));
|
||||
let mut host = VmRuntimeHost {
|
||||
runtime: self,
|
||||
log_service,
|
||||
@ -311,7 +309,7 @@ impl VirtualMachineRuntime {
|
||||
|
||||
// 1. Snapshot full telemetry at logical frame end
|
||||
let (glyph_bank, sound_bank, scene_bank) =
|
||||
Self::bank_telemetry_summary(&platform);
|
||||
Self::bank_telemetry_summary(platform);
|
||||
self.atomic_telemetry
|
||||
.glyph_slots_used
|
||||
.store(glyph_bank.used_slots as u32, Ordering::Relaxed);
|
||||
@ -402,7 +400,7 @@ impl VirtualMachineRuntime {
|
||||
|
||||
// 2. High-frequency telemetry update (only if inspection is active)
|
||||
if self.inspection_active {
|
||||
let (glyph_bank, sound_bank, scene_bank) = Self::bank_telemetry_summary(&platform);
|
||||
let (glyph_bank, sound_bank, scene_bank) = Self::bank_telemetry_summary(platform);
|
||||
self.atomic_telemetry
|
||||
.glyph_slots_used
|
||||
.store(glyph_bank.used_slots as u32, Ordering::Relaxed);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user