implements PLN-0048 minimal system hub pipeline
This commit is contained in:
parent
bea3f76aa7
commit
20e8439416
@ -343,6 +343,22 @@ mod tests {
|
|||||||
assert_eq!(firmware.hub.window_manager.windows.len(), 1);
|
assert_eq!(firmware.hub.window_manager.windows.len(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn system_running_ticks_focused_system_app_through_hub_pipeline() {
|
||||||
|
let mut firmware = Firmware::new(None);
|
||||||
|
let mut hardware = Hardware::new();
|
||||||
|
let signals = InputSignals::default();
|
||||||
|
|
||||||
|
firmware.load_cartridge(valid_cartridge(AppMode::System));
|
||||||
|
firmware.tick(&signals, &mut hardware);
|
||||||
|
|
||||||
|
let tick_index_before_system_update = firmware.os.tick_index;
|
||||||
|
firmware.tick(&signals, &mut hardware);
|
||||||
|
|
||||||
|
assert!(matches!(firmware.state, FirmwareState::SystemRunning(_)));
|
||||||
|
assert_eq!(firmware.os.tick_index, tick_index_before_system_update + 1);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn load_cartridge_routes_game_apps_to_game_running() {
|
fn load_cartridge_routes_game_apps_to_game_running() {
|
||||||
let mut firmware = Firmware::new(None);
|
let mut firmware = Firmware::new(None);
|
||||||
|
|||||||
@ -11,26 +11,8 @@ impl HubHomeStep {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_update(&mut self, ctx: &mut PrometeuContext) -> Option<FirmwareState> {
|
pub fn on_update(&mut self, ctx: &mut PrometeuContext) -> Option<FirmwareState> {
|
||||||
let mut error = None;
|
let outcome = ctx.hub.update_system_profile(ctx.os, ctx.vm, ctx.signals, ctx.hw);
|
||||||
|
if let Some(report) = outcome.crash {
|
||||||
// Always updates the Hub GUI (clears screen and processes input if no focus)
|
|
||||||
ctx.hub.gui_update(ctx.os, ctx.hw);
|
|
||||||
|
|
||||||
if let Some(focused_id) = ctx.hub.window_manager.focused {
|
|
||||||
if ctx.hw.pad().start().down {
|
|
||||||
ctx.hub.window_manager.remove_window(focused_id);
|
|
||||||
} else {
|
|
||||||
// System App runs here, drawing over the Hub background
|
|
||||||
error = ctx.os.tick(ctx.vm, ctx.signals, ctx.hw);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Renders the System App window borders
|
|
||||||
ctx.hub.render(ctx.os, ctx.hw);
|
|
||||||
|
|
||||||
ctx.hw.gfx_mut().present();
|
|
||||||
|
|
||||||
if let Some(report) = error {
|
|
||||||
return Some(FirmwareState::AppCrashes(AppCrashesStep { report }));
|
return Some(FirmwareState::AppCrashes(AppCrashesStep { report }));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -11,23 +11,16 @@ impl SystemRunningStep {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_update(&mut self, ctx: &mut PrometeuContext) -> Option<FirmwareState> {
|
pub fn on_update(&mut self, ctx: &mut PrometeuContext) -> Option<FirmwareState> {
|
||||||
let mut error = None;
|
let outcome = ctx.hub.update_system_profile(ctx.os, ctx.vm, ctx.signals, ctx.hw);
|
||||||
|
if let Some(report) = outcome.crash {
|
||||||
|
return Some(FirmwareState::AppCrashes(AppCrashesStep { report }));
|
||||||
|
}
|
||||||
|
|
||||||
ctx.hub.gui_update(ctx.os, ctx.hw);
|
if !outcome.focused_window_active {
|
||||||
|
|
||||||
if let Some(focused_id) = ctx.hub.window_manager.focused {
|
|
||||||
if ctx.hw.pad().start().down {
|
|
||||||
ctx.hub.window_manager.remove_window(focused_id);
|
|
||||||
return Some(FirmwareState::HubHome(HubHomeStep));
|
return Some(FirmwareState::HubHome(HubHomeStep));
|
||||||
}
|
}
|
||||||
|
|
||||||
error = ctx.os.tick(ctx.vm, ctx.signals, ctx.hw);
|
None
|
||||||
}
|
|
||||||
|
|
||||||
ctx.hub.render(ctx.os, ctx.hw);
|
|
||||||
ctx.hw.gfx_mut().present();
|
|
||||||
|
|
||||||
error.map(|report| FirmwareState::AppCrashes(AppCrashesStep { report }))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_exit(&mut self, _ctx: &mut PrometeuContext) {}
|
pub fn on_exit(&mut self, _ctx: &mut PrometeuContext) {}
|
||||||
|
|||||||
@ -1,15 +1,21 @@
|
|||||||
use crate::VirtualMachineRuntime;
|
|
||||||
use crate::programs::prometeu_hub::window_manager::WindowManager;
|
use crate::programs::prometeu_hub::window_manager::WindowManager;
|
||||||
use prometeu_hal::HardwareBridge;
|
use crate::{CrashReport, VirtualMachineRuntime};
|
||||||
use prometeu_hal::color::Color;
|
use prometeu_hal::color::Color;
|
||||||
use prometeu_hal::log::{LogLevel, LogSource};
|
use prometeu_hal::log::{LogLevel, LogSource};
|
||||||
use prometeu_hal::window::Rect;
|
use prometeu_hal::window::Rect;
|
||||||
|
use prometeu_hal::{HardwareBridge, InputSignals};
|
||||||
|
use prometeu_vm::VirtualMachine;
|
||||||
|
|
||||||
/// PrometeuHub: Launcher and system UI environment.
|
/// PrometeuHub: Launcher and system UI environment.
|
||||||
pub struct PrometeuHub {
|
pub struct PrometeuHub {
|
||||||
pub window_manager: WindowManager,
|
pub window_manager: WindowManager,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct SystemProfileUpdate {
|
||||||
|
pub crash: Option<CrashReport>,
|
||||||
|
pub focused_window_active: bool,
|
||||||
|
}
|
||||||
|
|
||||||
impl Default for PrometeuHub {
|
impl Default for PrometeuHub {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::new()
|
Self::new()
|
||||||
@ -75,4 +81,29 @@ impl PrometeuHub {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn update_system_profile(
|
||||||
|
&mut self,
|
||||||
|
os: &mut VirtualMachineRuntime,
|
||||||
|
vm: &mut VirtualMachine,
|
||||||
|
signals: &InputSignals,
|
||||||
|
hw: &mut dyn HardwareBridge,
|
||||||
|
) -> SystemProfileUpdate {
|
||||||
|
let mut crash = None;
|
||||||
|
|
||||||
|
self.gui_update(os, hw);
|
||||||
|
|
||||||
|
if let Some(focused_id) = self.window_manager.focused {
|
||||||
|
if hw.pad().start().down {
|
||||||
|
self.window_manager.remove_window(focused_id);
|
||||||
|
} else {
|
||||||
|
crash = os.tick(vm, signals, hw);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.render(os, hw);
|
||||||
|
hw.gfx_mut().present();
|
||||||
|
|
||||||
|
SystemProfileUpdate { crash, focused_window_active: self.window_manager.focused.is_some() }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -29,4 +29,4 @@
|
|||||||
{"type":"discussion","id":"DSC-0018","status":"done","ticket":"asset-load-asset-id-int-contract","title":"Asset Load Asset ID Int Contract","created_at":"2026-03-27","updated_at":"2026-03-27","tags":["asset","runtime","abi"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0019","file":"discussion/lessons/DSC-0018-asset-load-asset-id-int-contract/LSN-0019-asset-load-id-abi-convergence.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"}]}
|
{"type":"discussion","id":"DSC-0018","status":"done","ticket":"asset-load-asset-id-int-contract","title":"Asset Load Asset ID Int Contract","created_at":"2026-03-27","updated_at":"2026-03-27","tags":["asset","runtime","abi"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0019","file":"discussion/lessons/DSC-0018-asset-load-asset-id-int-contract/LSN-0019-asset-load-id-abi-convergence.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"}]}
|
||||||
{"type":"discussion","id":"DSC-0019","status":"done","ticket":"jenkinsfile-correction","title":"Jenkinsfile Correction and Relocation","created_at":"2026-04-07","updated_at":"2026-04-07","tags":["ci","jenkins"],"agendas":[{"id":"AGD-0017","file":"AGD-0017-jenkinsfile-correction.md","status":"done","created_at":"2026-04-07","updated_at":"2026-04-07"}],"decisions":[{"id":"DEC-0002","file":"DEC-0002-jenkinsfile-strategy.md","status":"accepted","created_at":"2026-04-07","updated_at":"2026-04-07"}],"plans":[{"id":"PLN-0002","file":"PLN-0002-jenkinsfile-execution.md","status":"done","created_at":"2026-04-07","updated_at":"2026-04-07"}],"lessons":[{"id":"LSN-0020","file":"discussion/lessons/DSC-0019-jenkins-ci-standardization/LSN-0020-jenkins-standard-relocation.md","status":"done","created_at":"2026-04-07","updated_at":"2026-04-07"}]}
|
{"type":"discussion","id":"DSC-0019","status":"done","ticket":"jenkinsfile-correction","title":"Jenkinsfile Correction and Relocation","created_at":"2026-04-07","updated_at":"2026-04-07","tags":["ci","jenkins"],"agendas":[{"id":"AGD-0017","file":"AGD-0017-jenkinsfile-correction.md","status":"done","created_at":"2026-04-07","updated_at":"2026-04-07"}],"decisions":[{"id":"DEC-0002","file":"DEC-0002-jenkinsfile-strategy.md","status":"accepted","created_at":"2026-04-07","updated_at":"2026-04-07"}],"plans":[{"id":"PLN-0002","file":"PLN-0002-jenkinsfile-execution.md","status":"done","created_at":"2026-04-07","updated_at":"2026-04-07"}],"lessons":[{"id":"LSN-0020","file":"discussion/lessons/DSC-0019-jenkins-ci-standardization/LSN-0020-jenkins-standard-relocation.md","status":"done","created_at":"2026-04-07","updated_at":"2026-04-07"}]}
|
||||||
{"type":"discussion","id":"DSC-0030","status":"done","ticket":"internal-viewport-270p","title":"Agenda - Internal Viewport 270p (480x270)","created_at":"2026-04-27","updated_at":"2026-04-28","tags":["gfx","runtime","viewport","resolution","frame-composer","host"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0039","file":"discussion/lessons/DSC-0030-internal-viewport-270p/LSN-0039-resolution-baseline-changes-are-runtime-wide-contracts.md","status":"done","created_at":"2026-04-28","updated_at":"2026-04-28"}]}
|
{"type":"discussion","id":"DSC-0030","status":"done","ticket":"internal-viewport-270p","title":"Agenda - Internal Viewport 270p (480x270)","created_at":"2026-04-27","updated_at":"2026-04-28","tags":["gfx","runtime","viewport","resolution","frame-composer","host"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0039","file":"discussion/lessons/DSC-0030-internal-viewport-270p/LSN-0039-resolution-baseline-changes-are-runtime-wide-contracts.md","status":"done","created_at":"2026-04-28","updated_at":"2026-04-28"}]}
|
||||||
{"type":"discussion","id":"DSC-0031","status":"in_progress","ticket":"runtime-mode-separation-game-system","title":"Agenda - Runtime Mode Separation: Game and System","created_at":"2026-05-11","updated_at":"2026-05-14","tags":["runtime","firmware","hub","system-apps","game-mode","scheduler"],"agendas":[{"id":"AGD-0031","file":"AGD-0031-runtime-mode-separation-game-system.md","status":"accepted","created_at":"2026-05-11","updated_at":"2026-05-14"}],"decisions":[{"id":"DEC-0023","file":"DEC-0023-system-pipeline-separation.md","status":"accepted","created_at":"2026-05-14","updated_at":"2026-05-14"}],"plans":[{"id":"PLN-0046","file":"PLN-0046-profile-separation-specification.md","status":"done","created_at":"2026-05-14","updated_at":"2026-05-14","ref_decisions":["DEC-0023"]},{"id":"PLN-0047","file":"PLN-0047-firmware-runtime-profile-dispatch.md","status":"done","created_at":"2026-05-14","updated_at":"2026-05-14","ref_decisions":["DEC-0023"]},{"id":"PLN-0048","file":"PLN-0048-minimal-system-hub-pipeline.md","status":"open","created_at":"2026-05-14","updated_at":"2026-05-14","ref_decisions":["DEC-0023"]},{"id":"PLN-0049","file":"PLN-0049-system-profile-abi-gates.md","status":"open","created_at":"2026-05-14","updated_at":"2026-05-14","ref_decisions":["DEC-0023"]},{"id":"PLN-0050","file":"PLN-0050-system-pipeline-evidence-and-learning.md","status":"open","created_at":"2026-05-14","updated_at":"2026-05-14","ref_decisions":["DEC-0023"]}],"lessons":[]}
|
{"type":"discussion","id":"DSC-0031","status":"in_progress","ticket":"runtime-mode-separation-game-system","title":"Agenda - Runtime Mode Separation: Game and System","created_at":"2026-05-11","updated_at":"2026-05-14","tags":["runtime","firmware","hub","system-apps","game-mode","scheduler"],"agendas":[{"id":"AGD-0031","file":"AGD-0031-runtime-mode-separation-game-system.md","status":"accepted","created_at":"2026-05-11","updated_at":"2026-05-14"}],"decisions":[{"id":"DEC-0023","file":"DEC-0023-system-pipeline-separation.md","status":"accepted","created_at":"2026-05-14","updated_at":"2026-05-14"}],"plans":[{"id":"PLN-0046","file":"PLN-0046-profile-separation-specification.md","status":"done","created_at":"2026-05-14","updated_at":"2026-05-14","ref_decisions":["DEC-0023"]},{"id":"PLN-0047","file":"PLN-0047-firmware-runtime-profile-dispatch.md","status":"done","created_at":"2026-05-14","updated_at":"2026-05-14","ref_decisions":["DEC-0023"]},{"id":"PLN-0048","file":"PLN-0048-minimal-system-hub-pipeline.md","status":"done","created_at":"2026-05-14","updated_at":"2026-05-14","ref_decisions":["DEC-0023"]},{"id":"PLN-0049","file":"PLN-0049-system-profile-abi-gates.md","status":"open","created_at":"2026-05-14","updated_at":"2026-05-14","ref_decisions":["DEC-0023"]},{"id":"PLN-0050","file":"PLN-0050-system-pipeline-evidence-and-learning.md","status":"open","created_at":"2026-05-14","updated_at":"2026-05-14","ref_decisions":["DEC-0023"]}],"lessons":[]}
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
id: PLN-0048
|
id: PLN-0048
|
||||||
ticket: runtime-mode-separation-game-system
|
ticket: runtime-mode-separation-game-system
|
||||||
title: Minimal System Hub Pipeline
|
title: Minimal System Hub Pipeline
|
||||||
status: open
|
status: done
|
||||||
created: 2026-05-14
|
created: 2026-05-14
|
||||||
completed:
|
completed:
|
||||||
ref_decisions: [DEC-0023]
|
ref_decisions: [DEC-0023]
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user