|
ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
|
Zero-heap app framework: lifecycle + static registry + launcher (#146). More...
Go to the source code of this file.
Data Structures | |
| struct | ra8_app_vtable_t |
| App lifecycle callbacks (shared by all instances of one app). More... | |
| struct | ra8_app |
| struct | ra8_app_registry_t |
| Fixed table of registered apps + the focused index. More... | |
| struct | ra8_app_nav_t |
| A bounded back-stack of app ids layered over a registry (zero-heap). More... | |
Typedefs | |
| typedef struct ra8_app | ra8_app_t |
Enumerations | |
| enum | ra8_app_const_t : int16_t { k_ra8_app_none = -1 } |
| Sentinels for the app registry. More... | |
| enum | ra8_app_state_t : uint8_t { k_ra8_app_state_unmounted = 0U , k_ra8_app_state_background = 1U , k_ra8_app_state_foreground = 2U } |
| Lifecycle state of one app within the framework's state machine. More... | |
Functions | |
| ra8_err_t | ra8_app_registry_init (ra8_app_registry_t *reg, ra8_app_t **storage, uint16_t cap) |
| Bind a registry to caller-owned pointer storage (empty, no focus). | |
| ra8_err_t | ra8_app_register (ra8_app_registry_t *reg, ra8_app_t *app) |
| Register an app (calls its init once) and add it to the registry. | |
| ra8_err_t | ra8_app_find (const ra8_app_registry_t *reg, uint16_t id, int16_t *out_idx) |
| Find a registered app's index by id. | |
| ra8_err_t | ra8_app_launch (ra8_app_registry_t *reg, uint16_t id) |
| Launch (focus) the app with id, running the focus lifecycle. | |
| ra8_err_t | ra8_app_active (const ra8_app_registry_t *reg, ra8_app_t **out_app) |
| Get the currently focused app. | |
| ra8_err_t | ra8_app_route_input (ra8_app_registry_t *reg, const ra8_widget_event_t *ev, bool *out_handled) |
| Route an input event to the focused app. | |
| ra8_err_t | ra8_app_tick (ra8_app_registry_t *reg) |
| Run the focused app's per-frame tick (no-op if none / NULL). | |
| ra8_err_t | ra8_app_render (ra8_app_registry_t *reg) |
| Run the focused app's render (on-target; no-op if none / NULL). | |
| ra8_err_t | ra8_app_count (const ra8_app_registry_t *reg, uint16_t *out_count) |
| Number of registered apps (for the launcher to list). | |
| ra8_err_t | ra8_app_at (const ra8_app_registry_t *reg, uint16_t idx, ra8_app_t **out_app) |
| Get the app at registry index idx (launcher enumeration). | |
| ra8_err_t | ra8_app_state (const ra8_app_registry_t *reg, uint16_t id, ra8_app_state_t *out_state) |
| Report an app's lifecycle state, derived from the registry. | |
| ra8_err_t | ra8_app_uninstall (ra8_app_registry_t *reg, uint16_t id) |
| Uninstall (unmount) a removable, non-focused app from the registry. | |
| ra8_err_t | ra8_app_nav_init (ra8_app_nav_t *nav, ra8_app_registry_t *reg, uint16_t *storage, uint16_t cap) |
| Bind a navigation back-stack to a registry + caller-owned storage. | |
| ra8_err_t | ra8_app_nav_go (ra8_app_nav_t *nav, uint16_t id) |
| Focus app id, pushing the outgoing app onto the back-stack. | |
| ra8_err_t | ra8_app_nav_go_index (ra8_app_nav_t *nav, uint16_t idx) |
Focus the app at registry index idx (launcher select-by-position). | |
| ra8_err_t | ra8_app_nav_back (ra8_app_nav_t *nav, bool *out_popped) |
| Return to the most recently pushed app (pop the back-stack). | |
| ra8_err_t | ra8_app_nav_depth (const ra8_app_nav_t *nav, uint16_t *out_depth) |
| Current back-stack depth (apps the user can still go back through). | |
Zero-heap app framework: lifecycle + static registry + launcher (#146).
ra8_app makes each major function a first-class app with a lifecycle, launched from the chrome (issue #146): opening a book launches the EPUB reader app; the library organizer is an app; settings is an app. The framework owns nothing but the routing – it calls the active app's lifecycle, forwards input + render, and tracks focus. Each app builds its UI by composing ra8_widgets (issue #145), so an "app = a widget tree".
Zero-heap (NASA Rule 3): apps are static instances registered into a caller-owned pointer array. Nothing is allocated; the registry is a fixed table of ra8_app_t*.
Core uninstallable. Issue #146's headline rule – "core functionality should be able to be uninstalled" – is enforced two ways:
The lifecycle / registration / routing logic is pure (no framebuffer), so it is host-unit-tested; the per-app render is the only on-target callback. ra8_app_state reports each app's place in the state machine below, derived from the registry so it can never drift from the real focus / membership.
[Ring 5 / UI] {World: NS}
Definition in file ra8_app.h.
| typedef struct ra8_app ra8_app_t |
| enum ra8_app_const_t : int16_t |
| enum ra8_app_state_t : uint8_t |
Lifecycle state of one app within the framework's state machine.
Every app moves through a small, explicit state machine the framework drives: an unregistered app is mounted by ra8_app_register (its init runs), entering k_ra8_app_state_background; ra8_app_launch focuses it into k_ra8_app_state_foreground (and suspends the outgoing app back to k_ra8_app_state_background); ra8_app_uninstall unmounts a background app (its deinit runs) back to k_ra8_app_state_unmounted. The state is not a stored field: ra8_app_state derives it from the registry (membership + focused index), so the single source of truth is the registry and the reported state can never drift from the real focus / membership.
| Reported state | Condition |
|---|---|
| k_ra8_app_state_unmounted | id not registered (or after uninstall) |
| k_ra8_app_state_background | registered, not the focused app |
| k_ra8_app_state_foreground | registered and the focused (active) app |
|
nodiscard |
Get the currently focused app.
| [in] | reg | Registry. |
| [out] | out_app | Receives the active app pointer, or NULL if none. |
| k_ra8_ok | Reported (see *out_app). |
| k_ra8_err_null_ptr | reg or out_app is NULL. |
Definition at line 115 of file ra8_app.c.
References ra8_app_registry_t::active, ra8_app_registry_t::apps, k_ra8_app_none, k_ra8_ok, RA8_CHECK_NULL_PTR, and s_tag.
Referenced by app_launch_selfcheck(), app_shell_selfcheck(), ra8_app_nav_go(), wd_active_name(), and wd_service_request().
|
nodiscard |
Get the app at registry index idx (launcher enumeration).
| [in] | reg | Registry. |
| [in] | idx | Index in [0, count). |
| [out] | out_app | Receives the app pointer. |
| k_ra8_ok | Reported. |
| k_ra8_err_null_ptr | reg or out_app is NULL. |
| k_ra8_err_out_of_range | idx >= count. |
Definition at line 174 of file ra8_app.c.
References ra8_app_registry_t::apps, ra8_app_registry_t::count, k_ra8_err_out_of_range, k_ra8_ok, RA8_CHECK_NULL_PTR, and s_tag.
Referenced by app_shell_log_menu(), ra8_app_nav_go_index(), wd_neighbor_id(), wd_tabbar_on_input(), and wd_tabbar_render().
|
nodiscard |
Number of registered apps (for the launcher to list).
| [in] | reg | Registry. |
| [out] | out_count | Receives reg->count. |
Definition at line 166 of file ra8_app.c.
References ra8_app_registry_t::count, k_ra8_ok, RA8_CHECK_NULL_PTR, and s_tag.
Referenced by app_launch_banner(), app_shell_banner(), app_shell_log_menu(), app_shell_uninstall_demo(), wd_check_touch_dispatch(), wd_neighbor_id(), wd_print_banner(), wd_tabbar_on_input(), and wd_tabbar_render().
|
nodiscard |
Find a registered app's index by id.
| [in] | reg | Registry. |
| [in] | id | App id to find. |
| [out] | out_idx | Receives the index in [0, count), or k_ra8_app_none. |
| k_ra8_ok | Search done (see *out_idx). |
| k_ra8_err_null_ptr | reg or out_idx is NULL. |
Definition at line 34 of file ra8_app.c.
References ra8_app_registry_t::apps, ra8_app_registry_t::count, ra8_app::id, k_ra8_app_none, k_ra8_ok, RA8_CHECK_NULL_PTR, and s_tag.
Referenced by ra8_app_launch(), ra8_app_register(), ra8_app_state(), and ra8_app_uninstall().
|
nodiscard |
Launch (focus) the app with id, running the focus lifecycle.
If a different app is focused, its on_leave runs first; then the target becomes active and its on_enter runs. Launching the already-active app is an idempotent no-op (no lifecycle calls) so a re-tap on the current app does not flicker.
| [in,out] | reg | Registry. |
| [in] | id | App id to focus. |
| k_ra8_ok | Focused (or already focused). |
| k_ra8_err_null_ptr | reg is NULL. |
| k_ra8_err_not_found | No app has id. |
Definition at line 78 of file ra8_app.c.
References ra8_app_registry_t::active, ra8_app_registry_t::apps, k_ra8_app_none, k_ra8_err_not_found, k_ra8_ok, ra8_app_find(), RA8_CHECK_NULL_PTR, and s_tag.
Referenced by er_render_current(), er_render_nag_region(), main(), ra8_app_nav_back(), ra8_app_nav_go(), wa_run_two_apps(), wd_selfcheck(), and wd_service_request().
|
nodiscard |
Return to the most recently pushed app (pop the back-stack).
Pops the top of the back-stack and focuses that app through ra8_app_launch, firing the focus lifecycle. An empty back-stack is not an error – it reports *out_popped == false so a chrome can decide what "back" means at the root (exit, no-op, etc.). The pop is committed only after the launch succeeds.
| [in,out] | nav | Navigation state. |
| [out] | out_popped | Receives true if an app was popped + focused. |
| k_ra8_ok | Done (see out_popped); false at the root. |
| k_ra8_err_null_ptr | nav, nav->reg, or out_popped is NULL. |
| k_ra8_err_not_found | The popped id is no longer registered. |
Definition at line 251 of file ra8_app.c.
References ra8_app_nav_t::depth, k_ra8_ok, ra8_app_launch(), RA8_CHECK_NULL_PTR, ra8_app_nav_t::reg, s_tag, and ra8_app_nav_t::stack.
Referenced by app_launch_switch_and_back(), app_shell_back_to_root(), and app_shell_settings_round_trip().
|
nodiscard |
Current back-stack depth (apps the user can still go back through).
| [in] | nav | Navigation state. |
| [out] | out_depth | Receives nav->depth. |
| k_ra8_ok | Reported. |
| k_ra8_err_null_ptr | nav or out_depth is NULL. |
Definition at line 270 of file ra8_app.c.
References ra8_app_nav_t::depth, k_ra8_ok, RA8_CHECK_NULL_PTR, and s_tag.
Referenced by app_launch_enter_reader(), app_launch_switch_and_back(), app_shell_back_to_root(), app_shell_launch_library(), app_shell_open_reader(), and app_shell_settings_round_trip().
|
nodiscard |
Focus app id, pushing the outgoing app onto the back-stack.
Composes ra8_app_launch (so the focus lifecycle fires) and remembers the app that lost focus so ra8_app_nav_back can return to it. The outgoing app is pushed only when a different app was focused: launching the already focused app, or the very first launch (no prior focus), pushes nothing – the trail records real navigation, not idempotent re-taps. Capacity is checked before the launch so a full back-stack leaves the focus unchanged.
| [in,out] | nav | Navigation state. |
| [in] | id | App id to focus. |
| k_ra8_ok | Focused (and pushed if a different app left). |
| k_ra8_err_null_ptr | nav or nav->reg is NULL. |
| k_ra8_err_no_mem | A push was required but the back-stack is full. |
| k_ra8_err_not_found | No app has id (focus + trail unchanged). |
Definition at line 201 of file ra8_app.c.
References ra8_app_nav_t::cap, ra8_app_nav_t::depth, k_ra8_err_no_mem, k_ra8_ok, ra8_app_active(), ra8_app_launch(), RA8_CHECK_NULL_PTR, ra8_app_nav_t::reg, s_tag, and ra8_app_nav_t::stack.
Referenced by app_launch_enter_reader(), app_launch_switch_and_back(), app_shell_open_reader(), app_shell_settings_round_trip(), and ra8_app_nav_go_index().
|
nodiscard |
Focus the app at registry index idx (launcher select-by-position).
A home/launcher (the chrome) enumerates apps by position – ra8_app_count gives the tile count and ra8_app_at maps a tile back to its app – then lets the user pick the n-th tile. This is the bridge that resolves that position to the app's id and focuses it through ra8_app_nav_go, so the outgoing app is pushed onto the back-stack exactly as a by-id navigation would. It is the by-index sibling of ra8_app_nav_go: the launcher thinks in indices, the back-stack records ids, and this couples the two. A NULL slot at idx (a caller-cleared storage entry) is rejected rather than focused.
| [in,out] | nav | Navigation state. |
| [in] | idx | Registry index in [0, count) of the app to focus. |
| k_ra8_ok | Focused (and pushed if a different app left). |
| k_ra8_err_null_ptr | nav, nav->reg, or the slot at idx is NULL. |
| k_ra8_err_out_of_range | idx >= count. |
| k_ra8_err_no_mem | A push was required but the back-stack is full. |
| k_ra8_err_not_found | The resolved id is no longer registered. |
Definition at line 238 of file ra8_app.c.
References k_ra8_ok, ra8_app_at(), ra8_app_nav_go(), RA8_CHECK_NULL_PTR, ra8_app_nav_t::reg, and s_tag.
Referenced by app_shell_launch_library().
|
nodiscard |
Bind a navigation back-stack to a registry + caller-owned storage.
| [out] | nav | Navigation state to initialise. |
| [in] | reg | Registry the navigation focuses apps in (non-NULL). |
| [in] | storage | Array of uint16_t the back-stack fills with app ids. |
| [in] | cap | Capacity of storage (>= 1). |
| k_ra8_ok | Initialised. |
| k_ra8_err_null_ptr | nav, reg, or storage is NULL. |
| k_ra8_err_invalid_arg | cap is 0. |
Definition at line 186 of file ra8_app.c.
References ra8_app_nav_t::cap, ra8_app_nav_t::depth, k_ra8_err_invalid_arg, k_ra8_ok, RA8_CHECK_NULL_PTR, ra8_app_nav_t::reg, s_tag, and ra8_app_nav_t::stack.
Referenced by app_launch_register(), and app_shell_register().
|
nodiscard |
Register an app (calls its init once) and add it to the registry.
Rejects a duplicate id. On success the app's init (if any) runs; a non-ok init leaves the app unregistered and returns its error. This is the point a build-time guard (#if RA8_APP_X) wraps to exclude an app.
| [in,out] | reg | Registry. |
| [in] | app | App instance (non-NULL, vt non-NULL). |
| k_ra8_ok | Registered + initialised. |
| k_ra8_err_null_ptr | reg or app (or app->vt) is NULL. |
| k_ra8_err_no_mem | Registry already at cap. |
| k_ra8_err_conflict | An app with the same id is registered. |
| <init's | error> app->vt->init returned non-ok. |
Definition at line 48 of file ra8_app.c.
References ra8_app_registry_t::apps, ra8_app_registry_t::cap, ra8_app_registry_t::count, k_ra8_app_none, k_ra8_err_conflict, k_ra8_err_no_mem, k_ra8_ok, ra8_app_find(), RA8_CHECK_NULL_PTR, and s_tag.
Referenced by app_launch_register(), app_shell_add(), er_apps_init(), main(), and wd_register_apps().
|
nodiscard |
Bind a registry to caller-owned pointer storage (empty, no focus).
| [out] | reg | Registry to initialise. |
| [in] | storage | Array of ra8_app_t* the registry fills. |
| [in] | cap | Capacity of storage (>= 1). |
| k_ra8_ok | Initialised. |
| k_ra8_err_null_ptr | reg or storage is NULL. |
| k_ra8_err_invalid_arg | cap is 0. |
Definition at line 20 of file ra8_app.c.
References ra8_app_registry_t::active, ra8_app_registry_t::apps, ra8_app_registry_t::cap, ra8_app_registry_t::count, k_ra8_app_none, k_ra8_err_invalid_arg, k_ra8_ok, RA8_CHECK_NULL_PTR, and s_tag.
Referenced by app_launch_register(), app_shell_register(), er_apps_init(), main(), and wd_register_apps().
|
nodiscard |
Run the focused app's render (on-target; no-op if none / NULL).
| [in,out] | reg | Registry. |
Definition at line 153 of file ra8_app.c.
References ra8_app_registry_t::active, ra8_app_registry_t::apps, k_ra8_app_none, k_ra8_ok, RA8_CHECK_NULL_PTR, and s_tag.
Referenced by app_launch_enter_reader(), app_shell_launch_library(), app_shell_open_reader(), app_shell_settings_round_trip(), er_render_current(), er_render_nag_region(), wa_run_two_apps(), wd_render_active(), and wd_selfcheck().
|
nodiscard |
Route an input event to the focused app.
| [in,out] | reg | Registry. |
| [in] | ev | The event. |
| [out] | out_handled | Receives true if the active app consumed it. |
| k_ra8_ok | Routed (see *out_handled); false if no focus. |
| k_ra8_err_null_ptr | reg, ev, or out_handled is NULL. |
Definition at line 124 of file ra8_app.c.
References ra8_app_registry_t::active, ra8_app_registry_t::apps, k_ra8_app_none, k_ra8_ok, RA8_CHECK_NULL_PTR, and s_tag.
Referenced by app_launch_route_back(), app_shell_open_reader(), wd_check_touch_dispatch(), and wd_route_button().
|
nodiscard |
Report an app's lifecycle state, derived from the registry.
Maps id to a ra8_app_state_t: an id that is not registered reports k_ra8_app_state_unmounted; a registered app reports k_ra8_app_state_foreground when it is the registry's focused (active) app and k_ra8_app_state_background otherwise. Nothing is stored per app – the state is computed from membership plus the focused index, so it cannot disagree with ra8_app_active or ra8_app_find. A launcher uses this to draw the focused tile differently and to decide whether a "remove" affordance applies (only background apps can be uninstalled).
| [in] | reg | Registry. |
| [in] | id | App id to query. |
| [out] | out_state | Receives the derived ra8_app_state_t. |
| k_ra8_ok | Reported (see out_state). |
| k_ra8_err_null_ptr | reg or out_state is NULL. |
Definition at line 279 of file ra8_app.c.
References ra8_app_registry_t::active, k_ra8_app_none, k_ra8_app_state_background, k_ra8_app_state_foreground, k_ra8_app_state_unmounted, k_ra8_ok, ra8_app_find(), RA8_CHECK_NULL_PTR, and s_tag.
Referenced by app_shell_uninstall_demo().
|
nodiscard |
Run the focused app's per-frame tick (no-op if none / NULL).
| [in,out] | reg | Registry. |
Definition at line 140 of file ra8_app.c.
References ra8_app_registry_t::active, ra8_app_registry_t::apps, k_ra8_app_none, k_ra8_ok, RA8_CHECK_NULL_PTR, and s_tag.
|
nodiscard |
Uninstall (unmount) a removable, non-focused app from the registry.
The run-time half of #146's "core uninstallable" rule. Resolves id and:
After a successful uninstall the app is absent (ra8_app_find / ra8_app_count no longer see it) and ra8_app_state reports k_ra8_app_state_unmounted for its id. The app instance itself is caller-owned static storage and is left intact apart from initialized being cleared, so it may be re-registered later.
| [in,out] | reg | Registry. |
| [in] | id | App id to uninstall. |
| k_ra8_ok | Unmounted; the app left the registry. |
| k_ra8_err_null_ptr | reg (or the resolved registry slot) is NULL. |
| k_ra8_err_not_found | No app has id. |
| k_ra8_err_not_supported | id is a core app (removable == false). |
| k_ra8_err_busy | id is the focused app (navigate away first). |
Definition at line 329 of file ra8_app.c.
References ra8_app_registry_t::active, ra8_app_registry_t::apps, internal_app_remove_at(), k_ra8_app_none, k_ra8_err_busy, k_ra8_err_not_found, k_ra8_err_not_supported, k_ra8_ok, ra8_app_find(), RA8_CHECK_NULL_PTR, and s_tag.
Referenced by app_shell_uninstall_demo().