diff --git a/apps/README.md b/apps/README.md index f4b7ec8a..6b809d10 100644 --- a/apps/README.md +++ b/apps/README.md @@ -14,10 +14,14 @@ The directories here define the target structure we are converging toward. For Linux bring-up: +- `apps/linux_cardputer_zero` is the Cardputer Zero portable Linux device app + shell. It owns the `cardputerzero` product target boundary and selects the + `cardputer_compact` UX pack while framebuffer, evdev, launch, and packaging + validation remain pending. - `apps/linux_sim_shell` is the final simulator and developer-tooling app shell. - `apps/linux_uconsole_gtk` is the final GTK/uConsole app shell. - `removed root linux_sim` and `removed root linux_uconsole` are transitional historical roots that may be reached only through declared compatibility adapters. -- `removed root linux_rpi` remains a historical bring-up root - until a final Linux device app shell owns the product path. +- `removed root linux_rpi` remains a historical bring-up root and must not be + treated as the Cardputer Zero product app shell. diff --git a/apps/linux_cardputer_zero/APP_SHELL_MANIFEST.md b/apps/linux_cardputer_zero/APP_SHELL_MANIFEST.md new file mode 100644 index 00000000..0a1e8933 --- /dev/null +++ b/apps/linux_cardputer_zero/APP_SHELL_MANIFEST.md @@ -0,0 +1,55 @@ +# App Shell Manifest: linux_cardputer_zero + +## Role + +Product app shell / target app shell. + +## Target Family + +Cardputer Zero portable Linux device. + +## Renderer Family + +Linux device renderer. The first build slice uses the shared ASCII/runtime +adoption path so target identity and UX selection are build-closed before the +framebuffer and evdev owner are promoted into this shell. + +## Board Facts + +- board id: `cardputerzero` +- display: 320 x 170 logical pixels +- input: built-in keyboard, real key mapping still needs device sampling +- pointer/touch/trackball: not present in current board facts + +## Build Entrypoint + +- `builds/linux_cmake` + +## Responsibilities + +May: + +- select the `cardputerzero` target profile +- select the Cardputer Zero device UX profile +- bind Cardputer Zero board facts into Linux runtime startup +- own future framebuffer, evdev, packaging, and launch details for this device + +Must not: + +- identify itself as a Linux simulator +- depend on simulator demo data as product truth +- define protocol, chat, map, or storage semantics +- absorb shared Linux runtime code that belongs in `platform/linux/common` +- hide missing real-device hardware integration behind simulator naming + +## Thin App Shell Entrypoint Declaration + +```text +trail_mate_linux_cardputer_zero_start(target_profile) +``` + +## Current Status + +Device app shell baseline. This establishes the product target, board facts, UX +selection, and CMake wiring. Real framebuffer, evdev, and device packaging are +the next hardware-closure slices. diff --git a/apps/linux_cardputer_zero/CMakeLists.txt b/apps/linux_cardputer_zero/CMakeLists.txt new file mode 100644 index 00000000..19e00d87 --- /dev/null +++ b/apps/linux_cardputer_zero/CMakeLists.txt @@ -0,0 +1,39 @@ +cmake_minimum_required(VERSION 3.20) + +project(TrailMateLinuxCardputerZero LANGUAGES CXX) + +include(CTest) + +set(TRAIL_MATE_REPO_ROOT + "${CMAKE_CURRENT_LIST_DIR}/../.." + CACHE PATH "Trail Mate repository root") + +include("${TRAIL_MATE_REPO_ROOT}/cmake/TrailMateUxPacks.cmake") +trailmate_add_ui_lvgl_ux_packs(trailmate_ui_lvgl_ux_packs) + +add_library(trailmate_linux_cardputer_zero_shell + src/linux_cardputer_zero_app_shell.cpp + "${TRAIL_MATE_REPO_ROOT}/modules/product_composition/src/target_profile.cpp" + "${TRAIL_MATE_REPO_ROOT}/modules/product_composition/src/target_ux_binding.cpp") + +target_include_directories(trailmate_linux_cardputer_zero_shell + PUBLIC + "${CMAKE_CURRENT_LIST_DIR}/src" + "${TRAIL_MATE_REPO_ROOT}" + "${TRAIL_MATE_REPO_ROOT}/modules/product_composition/include" + "${TRAIL_MATE_REPO_ROOT}/modules/ui_lvgl_ux_packs/include") + +target_link_libraries(trailmate_linux_cardputer_zero_shell + PUBLIC + trailmate_ui_lvgl_ux_packs) + +target_compile_features(trailmate_linux_cardputer_zero_shell PUBLIC cxx_std_17) + +if(BUILD_TESTING) + add_executable(trailmate_linux_cardputer_zero_app_shell_smoke + tests/linux_cardputer_zero_app_shell_smoke.cpp) + target_link_libraries(trailmate_linux_cardputer_zero_app_shell_smoke + PRIVATE trailmate_linux_cardputer_zero_shell) + add_test(NAME trailmate_linux_cardputer_zero_app_shell_smoke + COMMAND trailmate_linux_cardputer_zero_app_shell_smoke) +endif() diff --git a/apps/linux_cardputer_zero/README.md b/apps/linux_cardputer_zero/README.md new file mode 100644 index 00000000..3b29f1a1 --- /dev/null +++ b/apps/linux_cardputer_zero/README.md @@ -0,0 +1,18 @@ +# Cardputer Zero Linux App Shell + +This app shell is the Trail Mate product route for the Cardputer Zero portable +Linux device. It is not the Linux simulator. + +The first slice intentionally keeps the runtime entry small: the shell validates +the `cardputerzero` target profile, consumes the `boards/cardputerzero` facts, +selects the `cardputer_compact` UX pack, and builds through +`builds/linux_cmake`. That gives the device a real product boundary before the +framebuffer, evdev, launch, and package owners are filled in. + +Known hardware facts in this repo: + +- display: 320 x 170 logical pixels +- input: built-in keyboard +- touch, pointer, and trackball: absent in current board facts + +The simulator remains a separate development shell under `apps/linux_sim_shell`. diff --git a/apps/linux_cardputer_zero/src/linux_cardputer_zero_app_shell.cpp b/apps/linux_cardputer_zero/src/linux_cardputer_zero_app_shell.cpp new file mode 100644 index 00000000..88a0eb05 --- /dev/null +++ b/apps/linux_cardputer_zero/src/linux_cardputer_zero_app_shell.cpp @@ -0,0 +1,75 @@ +#include "linux_cardputer_zero_app_shell.h" + +#include "product_composition/target_ux_binding.h" +#include "ui_lvgl_ux_packs/ux/ux_pack_registry.h" + +#include + +namespace trailmate +{ +namespace apps +{ +namespace linux_cardputer_zero +{ + +LinuxCardputerZeroAppShell::LinuxCardputerZeroAppShell( + LinuxCardputerZeroAppShellConfig config) + : config_(config) +{ +} + +const LinuxCardputerZeroAppShellConfig& +LinuxCardputerZeroAppShell::config() const +{ + return config_; +} + +const char* LinuxCardputerZeroAppShell::targetId() const +{ + return config_.target_id; +} + +const product_composition::TargetProfile* +LinuxCardputerZeroAppShell::targetProfile() const +{ + return product_composition::findTargetProfile(targetId()); +} + +const char* LinuxCardputerZeroAppShell::activeUxPackId() const +{ + const auto* binding = product_composition::findTargetUxBinding(targetId()); + return binding != nullptr ? binding->active_ux_pack_id : nullptr; +} + +const boards::cardputerzero::CardputerZeroBoardFacts& +LinuxCardputerZeroAppShell::boardFacts() const +{ + return boards::cardputerzero::kBoardFacts; +} + +bool LinuxCardputerZeroAppShell::validate() const +{ + const auto& facts = boardFacts(); + const auto* profile = targetProfile(); + return config_.target_id != nullptr && + profile != nullptr && + std::strcmp(profile->target_id, "cardputerzero") == 0 && + std::strcmp(profile->board_id, facts.board_id) == 0 && + std::strcmp(profile->app_shell, "apps/linux_cardputer_zero") == 0 && + profile->platform == product_composition::TargetPlatform::Linux && + profile->renderer == product_composition::TargetRenderer::Ascii && + profile->has_display == facts.display_present && + profile->has_keyboard == facts.keyboard_present && + profile->has_touch == facts.touch_present && + profile->has_trackball == facts.trackball_present && + facts.logical_display_width == 320 && + facts.logical_display_height == 170 && + product_composition::findTargetUxBinding(targetId()) != nullptr && + config_.ux_pack_id != nullptr && + std::strcmp(config_.ux_pack_id, activeUxPackId()) == 0 && + ui_lvgl_ux::findUxPackById(activeUxPackId()) != nullptr; +} + +} // namespace linux_cardputer_zero +} // namespace apps +} // namespace trailmate diff --git a/apps/linux_cardputer_zero/src/linux_cardputer_zero_app_shell.h b/apps/linux_cardputer_zero/src/linux_cardputer_zero_app_shell.h new file mode 100644 index 00000000..82a3c0fa --- /dev/null +++ b/apps/linux_cardputer_zero/src/linux_cardputer_zero_app_shell.h @@ -0,0 +1,39 @@ +#pragma once + +#include "boards/cardputerzero/board_facts.h" + +#include "product_composition/target_profile.h" + +namespace trailmate +{ +namespace apps +{ +namespace linux_cardputer_zero +{ + +struct LinuxCardputerZeroAppShellConfig +{ + const char* target_id = "cardputerzero"; + const char* ux_pack_id = "cardputer_compact"; +}; + +class LinuxCardputerZeroAppShell +{ + public: + LinuxCardputerZeroAppShell() = default; + explicit LinuxCardputerZeroAppShell(LinuxCardputerZeroAppShellConfig config); + + const LinuxCardputerZeroAppShellConfig& config() const; + const char* targetId() const; + const product_composition::TargetProfile* targetProfile() const; + const char* activeUxPackId() const; + const boards::cardputerzero::CardputerZeroBoardFacts& boardFacts() const; + bool validate() const; + + private: + LinuxCardputerZeroAppShellConfig config_{}; +}; + +} // namespace linux_cardputer_zero +} // namespace apps +} // namespace trailmate diff --git a/apps/linux_cardputer_zero/tests/linux_cardputer_zero_app_shell_smoke.cpp b/apps/linux_cardputer_zero/tests/linux_cardputer_zero_app_shell_smoke.cpp new file mode 100644 index 00000000..8b060df1 --- /dev/null +++ b/apps/linux_cardputer_zero/tests/linux_cardputer_zero_app_shell_smoke.cpp @@ -0,0 +1,39 @@ +#include "linux_cardputer_zero_app_shell.h" + +#include "ui_lvgl_ux_packs/ux/ux_menu_provider.h" +#include "ui_presentation/menu/menu_model.h" + +#include +#include + +int main() +{ + trailmate::apps::linux_cardputer_zero::LinuxCardputerZeroAppShell shell; + assert(shell.validate()); + + const auto& config = shell.config(); + assert(std::strcmp(config.target_id, "cardputerzero") == 0); + assert(std::strcmp(config.ux_pack_id, "cardputer_compact") == 0); + assert(std::strcmp(shell.targetId(), "cardputerzero") == 0); + assert(std::strcmp(shell.activeUxPackId(), "cardputer_compact") == 0); + + const auto& facts = shell.boardFacts(); + assert(std::strcmp(facts.board_id, "cardputerzero") == 0); + assert(facts.logical_display_width == 320); + assert(facts.logical_display_height == 170); + assert(facts.keyboard_present); + assert(!facts.touch_present); + assert(!facts.pointer_present); + assert(!facts.trackball_present); + + const auto* profile = shell.targetProfile(); + assert(profile != nullptr); + assert(profile->platform == product_composition::TargetPlatform::Linux); + assert(profile->renderer == product_composition::TargetRenderer::Ascii); + assert(std::strcmp(profile->app_shell, "apps/linux_cardputer_zero") == 0); + + ui::menu::MenuModel menu; + assert(ui_lvgl_ux::buildMenuForUxPack(shell.activeUxPackId(), menu)); + assert(menu.size() > 0); + return 0; +} diff --git a/apps/linux_sim_shell/CMakeLists.txt b/apps/linux_sim_shell/CMakeLists.txt index b0096d78..225504d4 100644 --- a/apps/linux_sim_shell/CMakeLists.txt +++ b/apps/linux_sim_shell/CMakeLists.txt @@ -741,6 +741,7 @@ if(BUILD_TESTING) lvgl_descriptor_menu_model lvgl_descriptor_renderer_probe compatibility_menu_binding + cardputer_compact_ux_pack compatibility_ux_pack uconsole_desktop_ux_pack tiny_node_status_ux_pack diff --git a/apps/linux_sim_shell/src/linux_sim_app_shell.cpp b/apps/linux_sim_shell/src/linux_sim_app_shell.cpp index e54a5878..45703f17 100644 --- a/apps/linux_sim_shell/src/linux_sim_app_shell.cpp +++ b/apps/linux_sim_shell/src/linux_sim_app_shell.cpp @@ -24,7 +24,7 @@ const LinuxSimAppShellConfig& LinuxSimAppShell::config() const const char* LinuxSimAppShell::targetId() const { - return config_.product_target_id; + return config_.target_id; } const product_composition::TargetProfile* LinuxSimAppShell::targetProfile() const @@ -42,7 +42,6 @@ bool LinuxSimAppShell::validate() const { const auto& historical_source = linuxSimHistoricalSourceDescriptor(); return config_.target_id != nullptr && - config_.product_target_id != nullptr && targetProfile() != nullptr && product_composition::findTargetUxBinding(targetId()) != nullptr && config_.ux_pack_id != nullptr && diff --git a/apps/linux_sim_shell/src/linux_sim_app_shell.h b/apps/linux_sim_shell/src/linux_sim_app_shell.h index 2fabc9f8..d97380d9 100644 --- a/apps/linux_sim_shell/src/linux_sim_app_shell.h +++ b/apps/linux_sim_shell/src/linux_sim_app_shell.h @@ -14,7 +14,6 @@ namespace linux_sim_shell struct LinuxSimAppShellConfig { const char* target_id = "linux_sim"; - const char* product_target_id = "cardputerzero"; const char* ux_pack_id = "simulator_full"; const char* historical_source = linuxSimHistoricalSourceDescriptor().historical_root_name; diff --git a/apps/linux_sim_shell/tests/linux_sim_app_shell_smoke.cpp b/apps/linux_sim_shell/tests/linux_sim_app_shell_smoke.cpp index 48c6e09f..9127cfa0 100644 --- a/apps/linux_sim_shell/tests/linux_sim_app_shell_smoke.cpp +++ b/apps/linux_sim_shell/tests/linux_sim_app_shell_smoke.cpp @@ -15,12 +15,13 @@ int main() const auto& config = shell.config(); assert(std::strcmp(config.target_id, "linux_sim") == 0); - assert(std::strcmp(config.product_target_id, "cardputerzero") == 0); - assert(std::strcmp(shell.targetId(), "cardputerzero") == 0); + assert(std::strcmp(shell.targetId(), "linux_sim") == 0); assert(std::strcmp(config.ux_pack_id, "simulator_full") == 0); assert(std::strcmp(shell.activeUxPackId(), "simulator_full") == 0); assert(shell.targetProfile() != nullptr); assert(std::strcmp(shell.targetProfile()->app_shell, "apps/linux_sim_shell") == 0); + assert(shell.targetProfile()->status == + product_composition::TargetSupportStatus::Active); const auto& descriptor = trailmate::apps::linux_sim_shell::linuxSimHistoricalSourceDescriptor(); assert(std::strcmp(config.historical_source, diff --git a/boards/cardputerzero/BOARD.md b/boards/cardputerzero/BOARD.md index 4646662c..747e6c0f 100644 --- a/boards/cardputerzero/BOARD.md +++ b/boards/cardputerzero/BOARD.md @@ -12,7 +12,8 @@ This record describes current repo evidence for the Linux Cardputer Zero route. - board id: `cardputerzero` - current build entry evidence: `builds/linux_cmake` -- current implementation evidence: `removed root linux_rpi` +- current app shell evidence: `apps/linux_cardputer_zero` +- historical implementation evidence: `removed root linux_rpi` - current shared Linux code: `platform/linux/common` ## Confirmed Facts @@ -20,4 +21,13 @@ This record describes current repo evidence for the Linux Cardputer Zero route. - logical display size used by current common Linux shell: 320 x 170 - keyboard input is required but real device key mapping still needs sampling - display/input ownership for the real Pi OS path is not yet closed -- current final shell is not proven as a dedicated app directory in this repo +- current dedicated app shell baseline is build-owned by + `apps/linux_cardputer_zero` + +## Pending Hardware Evidence + +- framebuffer/display handoff on real Cardputer Zero hardware +- evdev keyboard mapping sampled from the real device +- launch/package route for the portable Linux device + +The Linux simulator remains a separate target under `apps/linux_sim_shell`. diff --git a/builds/linux_cmake/CMakeLists.txt b/builds/linux_cmake/CMakeLists.txt index 57c0f7b4..c47a3998 100644 --- a/builds/linux_cmake/CMakeLists.txt +++ b/builds/linux_cmake/CMakeLists.txt @@ -11,6 +11,8 @@ option(TRAIL_MATE_BUILD_LINUX_UCONSOLE_GTK "Build Linux uConsole GTK app shell" ON) option(TRAIL_MATE_BUILD_LINUX_SIM_SHELL "Build Linux simulator app shell" ON) +option(TRAIL_MATE_BUILD_LINUX_CARDPUTER_ZERO + "Build Linux Cardputer Zero app shell" ON) include(CTest) @@ -25,3 +27,9 @@ if(TRAIL_MATE_BUILD_LINUX_SIM_SHELL) "${TRAIL_MATE_REPO_ROOT}/apps/linux_sim_shell" "${CMAKE_BINARY_DIR}/apps/linux_sim_shell") endif() + +if(TRAIL_MATE_BUILD_LINUX_CARDPUTER_ZERO) + add_subdirectory( + "${TRAIL_MATE_REPO_ROOT}/apps/linux_cardputer_zero" + "${CMAKE_BINARY_DIR}/apps/linux_cardputer_zero") +endif() diff --git a/builds/linux_cmake/CMakePresets.json b/builds/linux_cmake/CMakePresets.json index 61b0b6b5..29c1492c 100644 --- a/builds/linux_cmake/CMakePresets.json +++ b/builds/linux_cmake/CMakePresets.json @@ -14,6 +14,7 @@ "cacheVariables": { "CMAKE_BUILD_TYPE": "Debug", "BUILD_TESTING": "ON", + "TRAIL_MATE_BUILD_LINUX_CARDPUTER_ZERO": "ON", "TRAIL_MATE_BUILD_LINUX_SIM_SHELL": "ON", "TRAIL_MATE_BUILD_LINUX_UCONSOLE_GTK": "ON" } @@ -25,6 +26,18 @@ "binaryDir": "${sourceDir}/build/linux-simulator-debug", "cacheVariables": { "TRAIL_MATE_BUILD_LINUX_SIM_SHELL": "ON", + "TRAIL_MATE_BUILD_LINUX_CARDPUTER_ZERO": "OFF", + "TRAIL_MATE_BUILD_LINUX_UCONSOLE_GTK": "OFF" + } + }, + { + "name": "linux-cardputer-zero-debug", + "displayName": "Linux Cardputer Zero shell debug", + "inherits": "linux-debug", + "binaryDir": "${sourceDir}/build/linux-cardputer-zero-debug", + "cacheVariables": { + "TRAIL_MATE_BUILD_LINUX_CARDPUTER_ZERO": "ON", + "TRAIL_MATE_BUILD_LINUX_SIM_SHELL": "OFF", "TRAIL_MATE_BUILD_LINUX_UCONSOLE_GTK": "OFF" } }, @@ -34,6 +47,7 @@ "inherits": "linux-debug", "binaryDir": "${sourceDir}/build/linux-uconsole-debug", "cacheVariables": { + "TRAIL_MATE_BUILD_LINUX_CARDPUTER_ZERO": "OFF", "TRAIL_MATE_BUILD_LINUX_SIM_SHELL": "OFF", "TRAIL_MATE_BUILD_LINUX_UCONSOLE_GTK": "ON" } @@ -46,6 +60,7 @@ "cacheVariables": { "CMAKE_BUILD_TYPE": "Release", "BUILD_TESTING": "OFF", + "TRAIL_MATE_BUILD_LINUX_CARDPUTER_ZERO": "OFF", "TRAIL_MATE_BUILD_LINUX_SIM_SHELL": "OFF", "TRAIL_MATE_BUILD_LINUX_UCONSOLE_GTK": "ON" } @@ -60,6 +75,10 @@ "name": "linux-simulator-debug-build", "configurePreset": "linux-simulator-debug" }, + { + "name": "linux-cardputer-zero-debug-build", + "configurePreset": "linux-cardputer-zero-debug" + }, { "name": "linux-uconsole-debug-build", "configurePreset": "linux-uconsole-debug" @@ -87,6 +106,13 @@ "outputOnFailure": true } }, + { + "name": "linux-cardputer-zero-debug-test", + "configurePreset": "linux-cardputer-zero-debug", + "output": { + "outputOnFailure": true + } + }, { "name": "linux-uconsole-debug-test", "configurePreset": "linux-uconsole-debug", diff --git a/cmake/TrailMateLinuxSources.cmake b/cmake/TrailMateLinuxSources.cmake index a7d3e04f..37c67d56 100644 --- a/cmake/TrailMateLinuxSources.cmake +++ b/cmake/TrailMateLinuxSources.cmake @@ -391,6 +391,7 @@ set(TRAIL_MATE_LINUX_UI_SHELL_SOURCES "${TRAIL_MATE_UI_LVGL_UX_PACKS_SRC_ROOT}/runtime/lvgl_menu_runtime_adapter.cpp" "${TRAIL_MATE_UI_LVGL_UX_PACKS_SRC_ROOT}/runtime/lvgl_screen_host_adapter.cpp" "${TRAIL_MATE_UI_LVGL_UX_PACKS_SRC_ROOT}/runtime/lvgl_screen_graph_bridge.cpp" + "${TRAIL_MATE_UI_LVGL_UX_PACKS_SRC_ROOT}/packs/cardputer_compact_ux_pack.cpp" "${TRAIL_MATE_UI_LVGL_UX_PACKS_SRC_ROOT}/packs/compatibility_ux_pack.cpp" "${TRAIL_MATE_UI_LVGL_UX_PACKS_SRC_ROOT}/packs/uconsole_desktop_ux_pack.cpp" "${TRAIL_MATE_UI_LVGL_UX_PACKS_SRC_ROOT}/packs/tiny_node_status_ux_pack.cpp" diff --git a/cmake/TrailMateUxPacks.cmake b/cmake/TrailMateUxPacks.cmake index 89428b77..435aa5fb 100644 --- a/cmake/TrailMateUxPacks.cmake +++ b/cmake/TrailMateUxPacks.cmake @@ -31,6 +31,7 @@ function(trailmate_add_ui_lvgl_ux_packs target_name) "${TRAIL_MATE_REPO_ROOT}/modules/ui_lvgl_ux_packs/src/runtime/lvgl_primary_screen_graph_runtime.cpp" "${TRAIL_MATE_REPO_ROOT}/modules/ui_lvgl_ux_packs/src/runtime/lvgl_descriptor_menu_model.cpp" "${TRAIL_MATE_REPO_ROOT}/modules/ui_lvgl_ux_packs/src/runtime/lvgl_descriptor_renderer_probe.cpp" + "${TRAIL_MATE_REPO_ROOT}/modules/ui_lvgl_ux_packs/src/packs/cardputer_compact_ux_pack.cpp" "${TRAIL_MATE_REPO_ROOT}/modules/ui_lvgl_ux_packs/src/packs/compatibility_ux_pack.cpp" "${TRAIL_MATE_REPO_ROOT}/modules/ui_lvgl_ux_packs/src/packs/uconsole_desktop_ux_pack.cpp" "${TRAIL_MATE_REPO_ROOT}/modules/ui_lvgl_ux_packs/src/packs/tiny_node_status_ux_pack.cpp" diff --git a/docs/audits/TARGET_UI_FINAL_OWNERSHIP_REPORT.md b/docs/audits/TARGET_UI_FINAL_OWNERSHIP_REPORT.md index 45790176..c9d7710b 100644 --- a/docs/audits/TARGET_UI_FINAL_OWNERSHIP_REPORT.md +++ b/docs/audits/TARGET_UI_FINAL_OWNERSHIP_REPORT.md @@ -91,7 +91,6 @@ not hidden inside the shell. The following gaps are real and intentionally recorded instead of guessed: - final executable UX packs for `tab5_touch`, `tdisplayp4_touch`, - `pager_compact`, `deck_full`, `watch_compact`, `cardputer_compact`, and - `node_headless`; + `pager_compact`, `deck_full`, `watch_compact`, and `node_headless`; - ESP-IDF target defaults for `tlora_pager`, `tdeck`, and `twatch`; -- dedicated Cardputer Zero app shell decision. +- Cardputer Zero framebuffer, evdev, launch, and packaging validation. diff --git a/docs/audits/TARGET_UX_PACK_GAP_REPORT.md b/docs/audits/TARGET_UX_PACK_GAP_REPORT.md index d7dfbcbf..ae439018 100644 --- a/docs/audits/TARGET_UX_PACK_GAP_REPORT.md +++ b/docs/audits/TARGET_UX_PACK_GAP_REPORT.md @@ -4,6 +4,7 @@ Batch 3 records final desired UX pack IDs for every target, but this repository currently has only these executable pack IDs: - `compatibility` +- `cardputer_compact` - `uconsole_desktop` - `tiny_node_status` - `simulator_full` @@ -20,7 +21,7 @@ runtime implementations. | `tdeck` | `deck_full` | `compatibility` | executable `deck_full` pack registered after IDF route evidence is closed | `modules/ui_lvgl_ux_packs + apps/esp32_lvgl` | | `twatch` | `watch_compact` | `compatibility` | executable `watch_compact` pack registered after IDF route evidence is closed | `modules/ui_lvgl_ux_packs + apps/esp32_lvgl` | | `uconsole` | `uconsole_desktop` | `uconsole_desktop` | none; current pack already resolves | `apps/linux_uconsole_gtk + modules/ui_gtk_runtime` | -| `cardputerzero` | `cardputer_compact` | `simulator_full` | final Cardputer Zero Linux device app shell or accepted simulator-shell route consumes `cardputer_compact` | `apps/linux_sim_shell + platform/linux/common` | +| `cardputerzero` | `cardputer_compact` | `cardputer_compact` | none for UX pack selection; real framebuffer, evdev, launch, and packaging validation remain tracked in the target matrix | `apps/linux_cardputer_zero + modules/ui_lvgl_ux_packs` | | `gat562_mesh_evb_pro` | `node_headless` | `tiny_node_status` | headless descriptor consumer becomes the active nRF52 node path | `apps/nrf52_node + modules/ui_headless_runtime` | ## Rule diff --git a/docs/specification/DEVICE_UX_PACK_ARCHITECTURE_SPEC.md b/docs/specification/DEVICE_UX_PACK_ARCHITECTURE_SPEC.md index 37ba463d..908fab45 100644 --- a/docs/specification/DEVICE_UX_PACK_ARCHITECTURE_SPEC.md +++ b/docs/specification/DEVICE_UX_PACK_ARCHITECTURE_SPEC.md @@ -89,7 +89,7 @@ Candidate future packs: deck_full pager_compact watch_quick -cardputer_wide +cardputer_compact tab5_touch tiny_node_status ``` @@ -98,6 +98,7 @@ Current executable baseline packs: ```text compatibility +cardputer_compact uconsole_desktop tiny_node_status simulator_full @@ -256,7 +257,7 @@ service, or board pin maps directly. | `deck_full` | keyboard/touch deck | full chat, full map, team actions, settings | | `pager_compact` | LoRa pager | compact navigation, quick messages, current GPS, status views | | `watch_quick` | watch-sized touch device | glanceable status, quick actions, compact team location | -| `cardputer_wide` | keyboard landscape device | dense chat and status, compact map | +| `cardputer_compact` | 320 x 170 keyboard landscape device | compact chat and status, compact map | | `tab5_touch` | larger touch display | full map, richer team, dashboard-first UX | | `tiny_node_status` | small node/status display | telemetry, radio/GPS/battery, no full workflows | diff --git a/docs/targets/TARGET_MATRIX.md b/docs/targets/TARGET_MATRIX.md index 95c550f3..7137000f 100644 --- a/docs/targets/TARGET_MATRIX.md +++ b/docs/targets/TARGET_MATRIX.md @@ -18,7 +18,8 @@ routes. | `tdeck` | `tdeck` | `builds/esp_idf` | `apps/esp32_lvgl` | ESP-IDF | LVGL | `deck_full` | `compatibility` | `deck_wide_ui` | `deck_full_manifest` | `deck_wide` | `PendingHardwareValidation` | existing target capability still records Arduino/PIO evidence | `apps/esp32_lvgl + builds/esp_idf + boards/tdeck` | | `twatch` | `twatch` | `builds/esp_idf` | `apps/esp32_lvgl` | ESP-IDF | LVGL | `watch_compact` | `compatibility` | `watch_compact_ui` | `watch_compact_manifest` | `watch_compact` | `PendingHardwareValidation` | current repo evidence is board and variant data, not migrated IDF defaults | `apps/esp32_lvgl + builds/esp_idf + boards/twatch` | | `uconsole` | `uconsole` | `builds/linux_cmake` | `apps/linux_uconsole_gtk` | Linux | GTK | `uconsole_desktop` | `uconsole_desktop` | `uconsole_desktop_ui` | `uconsole_desktop_manifest` | `uconsole_desktop` | `Active` | none for UX pack selection | `apps/linux_uconsole_gtk + builds/linux_cmake + boards/uconsole` | -| `cardputerzero` | `cardputerzero` | `builds/linux_cmake` | `apps/linux_sim_shell` | Linux | ASCII | `cardputer_compact` | `simulator_full` | `cardputer_compact_ui` | `cardputer_compact_manifest` | `cardputer_compact` | `ActiveWithFallback` | dedicated Linux device shell remains deferred by current repo evidence | `apps/linux_sim_shell + builds/linux_cmake + boards/cardputerzero` | +| `linux_sim` | `linux_sim` | `builds/linux_cmake` | `apps/linux_sim_shell` | Linux | ASCII | `simulator_full` | `simulator_full` | `simulator_full_ui` | `simulator_full_manifest` | `simulator_full` | `Active` | none for simulator UX pack selection | `apps/linux_sim_shell + builds/linux_cmake` | +| `cardputerzero` | `cardputerzero` | `builds/linux_cmake` | `apps/linux_cardputer_zero` | Linux | ASCII | `cardputer_compact` | `cardputer_compact` | `cardputer_compact_ui` | `cardputer_compact_manifest` | `cardputer_compact` | `PendingHardwareValidation` | framebuffer, evdev, launch, and packaging still need real device validation | `apps/linux_cardputer_zero + builds/linux_cmake + boards/cardputerzero` | | `gat562_mesh_evb_pro` | `gat562_mesh_evb_pro` | `builds/pio_nrf52` | `apps/nrf52_node` | PlatformIO | Headless | `node_headless` | `tiny_node_status` | `node_headless_ui` | `node_headless_manifest` | `headless_node` | `Headless` | current executable UX pack is `tiny_node_status`; board hardware still records a 128 x 64 display | `apps/nrf52_node + builds/pio_nrf52 + boards/gat562_mesh_evb_pro` | ## Pending Evidence @@ -28,7 +29,7 @@ routes. | `tlora_pager` | ESP-IDF target defaults and hardware validation for the requested IDF route | `builds/esp_idf + boards/tlora_pager` | | `tdeck` | ESP-IDF target defaults and hardware validation for the requested IDF route | `builds/esp_idf + boards/tdeck` | | `twatch` | ESP-IDF target defaults and hardware validation for the requested IDF route | `builds/esp_idf + boards/twatch` | -| `cardputerzero` | final dedicated Linux device app shell decision; current repo evidence points to Linux CMake plus simulator fallback | `apps/linux_sim_shell` until a proven dedicated shell exists | +| `cardputerzero` | real Cardputer Zero framebuffer, evdev, launch, and packaging validation | `apps/linux_cardputer_zero + boards/cardputerzero` | ## Batch 2 Status Tokens diff --git a/docs/targets/linux_targets.md b/docs/targets/linux_targets.md index 2c79763f..a686e6c3 100644 --- a/docs/targets/linux_targets.md +++ b/docs/targets/linux_targets.md @@ -16,7 +16,7 @@ UX Pack presents. | --- | --- | --- | --- | --- | --- | --- | | `uconsole` | `uconsole_aio2` placeholder | Linux | `builds/linux_cmake` | `apps/linux_uconsole_gtk` | `uconsole_desktop` | transitional | | `linux_sim` | simulator device profile | Linux | `builds/linux_cmake` | `apps/linux_sim_shell` | `simulator_full` | transitional | -| `linux_rpi_cardputer_zero` | Cardputer Zero / Pi OS device profile | Linux | `builds/linux_cmake` | future Linux device app shell | `cardputer_wide` | transitional | +| `cardputerzero` | Cardputer Zero portable Linux device profile | Linux | `builds/linux_cmake` | `apps/linux_cardputer_zero` | `cardputer_compact` | pending hardware validation | | `linux_unoq` | UNO Q device profile | Linux | `builds/linux_cmake` | future Linux UNO Q app shell | `uconsole_desktop` placeholder | planned | | `linux_headless` | host/headless profile | Linux | `builds/linux_cmake` | future Linux headless app shell | `headless_status` | planned | @@ -33,6 +33,10 @@ Linux CMake wrappers should invoke selected Linux app shells. They must not absorb GTK, simulator, framebuffer, device-shell, or runtime behavior into `builds/linux_cmake`. +`cardputerzero` is no longer described as a future Raspberry Pi simulator path. +Its current owner is `apps/linux_cardputer_zero`; the remaining work is real +Cardputer Zero framebuffer, evdev, launch, and package validation. + ## Non-Goals This document does not move Linux CMake files, GTK source, simulator source, diff --git a/docs/ux_profiles/README.md b/docs/ux_profiles/README.md index 9f048765..20961e68 100644 --- a/docs/ux_profiles/README.md +++ b/docs/ux_profiles/README.md @@ -33,7 +33,7 @@ Phase 8 profiles: - `deck_full.md` - `pager_compact.md` - `watch_quick.md` -- `cardputer_wide.md` +- `cardputer_compact.md` - `tab5_touch.md` - `tiny_node_status.md` - `uconsole_desktop.md` diff --git a/docs/ux_profiles/cardputer_compact.md b/docs/ux_profiles/cardputer_compact.md new file mode 100644 index 00000000..ee32fe5c --- /dev/null +++ b/docs/ux_profiles/cardputer_compact.md @@ -0,0 +1,50 @@ +# UX Profile: cardputer_compact + +## Screen Class + +Compact 320 x 170 landscape keyboard device. + +## Input Model + +Keyboard-first input. Pointer, touch, and trackball are absent in the current +Cardputer Zero board facts. + +## Feature Set + +Compact chat/status workflow with compact map and practical GPS/team actions. + +## Screen Set + +Dashboard, Chat, Compact Map/GPS, Team, Settings. + +## Map Mode + +Compact 320 x 170 landscape map with offline tiles and current-position focus. + +## Chat Mode + +Quick message chat list and compose optimized for keyboard entry. + +## Team Action Mode + +Quick location plus compact command/status actions. + +## GPS Mode + +Compact GPS status with route/tracker surfaces deferred. + +## Modal/Picker Strategy + +Keyboard-first compact modals and list pickers. + +## Renderer Family + +Executable UX pack `cardputer_compact`; current first Linux device-shell slice +uses ASCII renderer until framebuffer ownership is validated. + +## Deferred Decisions + +Real-device keyboard sampling, framebuffer handoff, launch, and packaging remain +deferred. + +Board describes. Target chooses. UX Pack presents. Renderer draws. diff --git a/docs/ux_profiles/cardputer_wide.md b/docs/ux_profiles/cardputer_wide.md deleted file mode 100644 index 4a46942b..00000000 --- a/docs/ux_profiles/cardputer_wide.md +++ /dev/null @@ -1,48 +0,0 @@ -# UX Profile: cardputer_wide - -## Screen Class - -Small landscape keyboard device. - -## Input Model - -Keyboard, directional controls, limited pointer/touch depending on target. - -## Feature Set - -Dense chat/status workflow with compact map and practical GPS/team actions. - -## Screen Set - -Dashboard, Chat, Compact Map/GPS, Team, Settings. - -## Map Mode - -Compact landscape map with offline tiles and current-position focus. - -## Chat Mode - -Dense chat list and compose optimized for keyboard entry. - -## Team Action Mode - -Quick location plus compact command/status actions. - -## GPS Mode - -Compact GPS status with route/tracker surfaces deferred. - -## Modal/Picker Strategy - -Keyboard-first compact modals and list pickers. - -## Renderer Family - -LVGL or Linux framebuffer LVGL depending on target. - -## Deferred Decisions - -Final Cardputer Zero shell split, keyboard bindings, and hardware UX profile -name remain deferred. - -Board describes. Target chooses. UX Pack presents. Renderer draws. diff --git a/modules/product_composition/src/target_build_binding.cpp b/modules/product_composition/src/target_build_binding.cpp index c57d5343..cb2865ee 100644 --- a/modules/product_composition/src/target_build_binding.cpp +++ b/modules/product_composition/src/target_build_binding.cpp @@ -58,11 +58,18 @@ constexpr TargetBuildBinding kTargetBuildBindings[] = { "linux_cmake", }, { - "cardputerzero", + "linux_sim", "builds/linux_cmake", "apps/linux_sim_shell", nullptr, - "linux_fallback_shell", + "linux_simulator", + }, + { + "cardputerzero", + "builds/linux_cmake", + "apps/linux_cardputer_zero", + nullptr, + "linux_device_shell", }, { "gat562_mesh_evb_pro", diff --git a/modules/product_composition/src/target_profile.cpp b/modules/product_composition/src/target_profile.cpp index 0df7b034..e7f42373 100644 --- a/modules/product_composition/src/target_profile.cpp +++ b/modules/product_composition/src/target_profile.cpp @@ -148,18 +148,38 @@ constexpr TargetProfile kTargetProfiles[] = { true, false, }, + { + "linux_sim", + "linux_sim", + "builds/linux_cmake", + "apps/linux_sim_shell", + "simulator_full", + "simulator_full_ui", + "simulator_full_manifest", + "simulator_full", + TargetPlatform::Linux, + TargetRenderer::Ascii, + TargetSupportStatus::Active, + true, + true, + true, + false, + false, + false, + false, + }, { "cardputerzero", "cardputerzero", "builds/linux_cmake", - "apps/linux_sim_shell", + "apps/linux_cardputer_zero", "cardputer_compact", "cardputer_compact_ui", "cardputer_compact_manifest", "cardputer_compact", TargetPlatform::Linux, TargetRenderer::Ascii, - TargetSupportStatus::ActiveWithFallback, + TargetSupportStatus::PendingHardwareValidation, true, false, true, diff --git a/modules/product_composition/src/target_ux_binding.cpp b/modules/product_composition/src/target_ux_binding.cpp index ba9c1f75..95f7c8bb 100644 --- a/modules/product_composition/src/target_ux_binding.cpp +++ b/modules/product_composition/src/target_ux_binding.cpp @@ -15,7 +15,8 @@ constexpr TargetUxBinding kTargetUxBindings[] = { {"tdeck", "deck_full", "compatibility", "compatibility", false}, {"twatch", "watch_compact", "compatibility", "compatibility", false}, {"uconsole", "uconsole_desktop", "uconsole_desktop", nullptr, true}, - {"cardputerzero", "cardputer_compact", "simulator_full", "simulator_full", false}, + {"linux_sim", "simulator_full", "simulator_full", nullptr, true}, + {"cardputerzero", "cardputer_compact", "cardputer_compact", nullptr, true}, {"gat562_mesh_evb_pro", "node_headless", "tiny_node_status", "tiny_node_status", false}, }; diff --git a/modules/product_composition/tests/test_target_build_binding.cpp b/modules/product_composition/tests/test_target_build_binding.cpp index 5143572f..36efb620 100644 --- a/modules/product_composition/tests/test_target_build_binding.cpp +++ b/modules/product_composition/tests/test_target_build_binding.cpp @@ -8,7 +8,7 @@ int main() std::size_t count = 0; const auto* all = product_composition::allTargetBuildBindings(&count); assert(all != nullptr); - assert(count == 9); + assert(count == 10); const auto* bindings = product_composition::esp32LvglTargetBuildBindings(&count); assert(bindings != nullptr); @@ -50,10 +50,17 @@ int main() assert(std::strcmp(uconsole->build_entrypoint, "builds/linux_cmake") == 0); assert(std::strcmp(uconsole->app_shell, "apps/linux_uconsole_gtk") == 0); + const auto* linux_sim = product_composition::findTargetBuildBinding("linux_sim"); + assert(linux_sim != nullptr); + assert(std::strcmp(linux_sim->build_entrypoint, "builds/linux_cmake") == 0); + assert(std::strcmp(linux_sim->app_shell, "apps/linux_sim_shell") == 0); + assert(std::strcmp(linux_sim->status, "linux_simulator") == 0); + const auto* cardputer = product_composition::findTargetBuildBinding("cardputerzero"); assert(cardputer != nullptr); assert(std::strcmp(cardputer->build_entrypoint, "builds/linux_cmake") == 0); - assert(std::strcmp(cardputer->app_shell, "apps/linux_sim_shell") == 0); + assert(std::strcmp(cardputer->app_shell, "apps/linux_cardputer_zero") == 0); + assert(std::strcmp(cardputer->status, "linux_device_shell") == 0); const auto* gat562 = product_composition::findTargetBuildBinding("gat562_mesh_evb_pro"); assert(gat562 != nullptr); diff --git a/modules/product_composition/tests/test_target_profile.cpp b/modules/product_composition/tests/test_target_profile.cpp index 989f98db..07efc5c9 100644 --- a/modules/product_composition/tests/test_target_profile.cpp +++ b/modules/product_composition/tests/test_target_profile.cpp @@ -8,7 +8,7 @@ int main() std::size_t count = 0; const auto* all = product_composition::allTargetProfiles(&count); assert(all != nullptr); - assert(count == 9); + assert(count == 10); const auto* profiles = product_composition::esp32LvglTargetProfiles(&count); assert(profiles != nullptr); @@ -61,9 +61,20 @@ int main() assert(uconsole->renderer == product_composition::TargetRenderer::Gtk); assert(uconsole->platform == product_composition::TargetPlatform::Linux); + const auto* linux_sim = product_composition::findTargetProfile("linux_sim"); + assert(linux_sim != nullptr); + assert(linux_sim->renderer == product_composition::TargetRenderer::Ascii); + assert(linux_sim->platform == product_composition::TargetPlatform::Linux); + assert(std::strcmp(linux_sim->app_shell, "apps/linux_sim_shell") == 0); + assert(linux_sim->status == product_composition::TargetSupportStatus::Active); + const auto* cardputer = product_composition::findTargetProfile("cardputerzero"); assert(cardputer != nullptr); assert(cardputer->renderer == product_composition::TargetRenderer::Ascii); + assert(cardputer->platform == product_composition::TargetPlatform::Linux); + assert(std::strcmp(cardputer->app_shell, "apps/linux_cardputer_zero") == 0); + assert(cardputer->status == + product_composition::TargetSupportStatus::PendingHardwareValidation); const auto* gat562 = product_composition::findTargetProfile("gat562_mesh_evb_pro"); assert(gat562 != nullptr); diff --git a/modules/product_composition/tests/test_target_ux_binding.cpp b/modules/product_composition/tests/test_target_ux_binding.cpp index 5f19f096..174e2eb5 100644 --- a/modules/product_composition/tests/test_target_ux_binding.cpp +++ b/modules/product_composition/tests/test_target_ux_binding.cpp @@ -8,7 +8,7 @@ int main() std::size_t count = 0; const auto* bindings = product_composition::allTargetUxBindings(&count); assert(bindings != nullptr); - assert(count == 9); + assert(count == 10); const auto* tab5 = product_composition::findTargetUxBinding("tab5"); assert(tab5 != nullptr); @@ -23,10 +23,19 @@ int main() assert(uconsole->fallback_ux_pack_id == nullptr); assert(uconsole->final_ux_pack_available); + const auto* linux_sim = product_composition::findTargetUxBinding("linux_sim"); + assert(linux_sim != nullptr); + assert(std::strcmp(linux_sim->desired_ux_pack_id, "simulator_full") == 0); + assert(std::strcmp(linux_sim->active_ux_pack_id, "simulator_full") == 0); + assert(linux_sim->fallback_ux_pack_id == nullptr); + assert(linux_sim->final_ux_pack_available); + const auto* cardputer = product_composition::findTargetUxBinding("cardputerzero"); assert(cardputer != nullptr); assert(std::strcmp(cardputer->desired_ux_pack_id, "cardputer_compact") == 0); - assert(std::strcmp(cardputer->active_ux_pack_id, "simulator_full") == 0); + assert(std::strcmp(cardputer->active_ux_pack_id, "cardputer_compact") == 0); + assert(cardputer->fallback_ux_pack_id == nullptr); + assert(cardputer->final_ux_pack_available); const auto* gat562 = product_composition::findTargetUxBinding("gat562_mesh_evb_pro"); assert(gat562 != nullptr); diff --git a/modules/ui_lvgl_ux_packs/include/ui_lvgl_ux_packs/packs/cardputer_compact_ux_pack.h b/modules/ui_lvgl_ux_packs/include/ui_lvgl_ux_packs/packs/cardputer_compact_ux_pack.h new file mode 100644 index 00000000..7a6d5c97 --- /dev/null +++ b/modules/ui_lvgl_ux_packs/include/ui_lvgl_ux_packs/packs/cardputer_compact_ux_pack.h @@ -0,0 +1,18 @@ +#pragma once + +#include "ui_lvgl_ux_packs/ux/ux_pack.h" + +namespace ui_lvgl_ux +{ + +class CardputerCompactUxPack final : public IUxPack +{ + public: + const char* id() const override; + const DeviceUxProfile& profile() const override; + const UxFeatureSet& features() const override; + void buildScreens(ScreenRegistry& out) const override; + void buildInputBindings(InputBindingSet& out) const override; +}; + +} // namespace ui_lvgl_ux diff --git a/modules/ui_lvgl_ux_packs/src/packs/cardputer_compact_ux_pack.cpp b/modules/ui_lvgl_ux_packs/src/packs/cardputer_compact_ux_pack.cpp new file mode 100644 index 00000000..9c50badd --- /dev/null +++ b/modules/ui_lvgl_ux_packs/src/packs/cardputer_compact_ux_pack.cpp @@ -0,0 +1,72 @@ +#include "ui_lvgl_ux_packs/packs/cardputer_compact_ux_pack.h" + +namespace ui_lvgl_ux +{ + +const char* CardputerCompactUxPack::id() const +{ + return "cardputer_compact"; +} + +const DeviceUxProfile& CardputerCompactUxPack::profile() const +{ + static const DeviceUxProfile profile{ + "cardputer_compact", + ScreenClass::CompactHandheld, + InputModel::Keyboard, + MapMode::Compact, + ChatMode::QuickMessage, + true, + true, + true, + true, + }; + return profile; +} + +const UxFeatureSet& CardputerCompactUxPack::features() const +{ + static const UxFeatureSet features{ + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + }; + return features; +} + +void CardputerCompactUxPack::buildScreens(ScreenRegistry& out) const +{ + out.clear(); + (void)out.add({ScreenId::Dashboard, "Dashboard", true}); + (void)out.add({ScreenId::Chat, "Chat", true}); + (void)out.add({ScreenId::Contacts, "Contacts", true}); + (void)out.add({ScreenId::Map, "Map", true}); + (void)out.add({ScreenId::Gps, "GPS", true}); + (void)out.add({ScreenId::Team, "Team", true}); + (void)out.add({ScreenId::Tracker, "Tracker", true}); + (void)out.add({ScreenId::Settings, "Settings", true}); +} + +void CardputerCompactUxPack::buildInputBindings(InputBindingSet& out) const +{ + out.clear(); + (void)out.add({InputAction::Up, "Keyboard up"}); + (void)out.add({InputAction::Down, "Keyboard down"}); + (void)out.add({InputAction::Left, "Keyboard left"}); + (void)out.add({InputAction::Right, "Keyboard right"}); + (void)out.add({InputAction::Select, "Enter"}); + (void)out.add({InputAction::Back, "Escape"}); + (void)out.add({InputAction::Menu, "Menu"}); + (void)out.add({InputAction::Compose, "Compose"}); + (void)out.add({InputAction::MapZoomIn, "Plus"}); + (void)out.add({InputAction::MapZoomOut, "Minus"}); +} + +} // namespace ui_lvgl_ux diff --git a/modules/ui_lvgl_ux_packs/src/ux/ux_pack_registry.cpp b/modules/ui_lvgl_ux_packs/src/ux/ux_pack_registry.cpp index fa094583..420d36e8 100644 --- a/modules/ui_lvgl_ux_packs/src/ux/ux_pack_registry.cpp +++ b/modules/ui_lvgl_ux_packs/src/ux/ux_pack_registry.cpp @@ -1,5 +1,6 @@ #include "ui_lvgl_ux_packs/ux/ux_pack_registry.h" +#include "ui_lvgl_ux_packs/packs/cardputer_compact_ux_pack.h" #include "ui_lvgl_ux_packs/packs/compatibility_ux_pack.h" #include "ui_lvgl_ux_packs/packs/simulator_full_ux_pack.h" #include "ui_lvgl_ux_packs/packs/tiny_node_status_ux_pack.h" @@ -18,12 +19,14 @@ const IUxPack* findUxPackById(const char* id) } static const CompatibilityUxPack compatibility_pack; + static const CardputerCompactUxPack cardputer_compact_pack; static const UConsoleDesktopUxPack uconsole_desktop_pack; static const TinyNodeStatusUxPack tiny_node_status_pack; static const SimulatorFullUxPack simulator_full_pack; const IUxPack* const packs[] = { &compatibility_pack, + &cardputer_compact_pack, &uconsole_desktop_pack, &tiny_node_status_pack, &simulator_full_pack, diff --git a/modules/ui_lvgl_ux_packs/tests/test_cardputer_compact_ux_pack.cpp b/modules/ui_lvgl_ux_packs/tests/test_cardputer_compact_ux_pack.cpp new file mode 100644 index 00000000..23cd0d1a --- /dev/null +++ b/modules/ui_lvgl_ux_packs/tests/test_cardputer_compact_ux_pack.cpp @@ -0,0 +1,30 @@ +#include "ui_lvgl_ux_packs/packs/cardputer_compact_ux_pack.h" + +#include +#include + +int main() +{ + ui_lvgl_ux::CardputerCompactUxPack pack; + assert(std::strcmp(pack.id(), "cardputer_compact") == 0); + assert(pack.profile().screen_class == ui_lvgl_ux::ScreenClass::CompactHandheld); + assert(pack.profile().input_model == ui_lvgl_ux::InputModel::Keyboard); + assert(pack.profile().map_mode == ui_lvgl_ux::MapMode::Compact); + assert(pack.profile().chat_mode == ui_lvgl_ux::ChatMode::QuickMessage); + assert(pack.features().chat); + assert(pack.features().contacts); + assert(pack.features().map); + assert(pack.features().gps); + assert(pack.features().settings); + assert(!pack.features().walkie); + assert(!pack.features().sstv); + + ui_lvgl_ux::ScreenRegistry screens; + pack.buildScreens(screens); + assert(screens.size() == 8); + + ui_lvgl_ux::InputBindingSet bindings; + pack.buildInputBindings(bindings); + assert(bindings.size() == 10); + return 0; +} diff --git a/modules/ui_lvgl_ux_packs/tests/test_ux_pack_registry.cpp b/modules/ui_lvgl_ux_packs/tests/test_ux_pack_registry.cpp index 02ea1b5f..26aac2eb 100644 --- a/modules/ui_lvgl_ux_packs/tests/test_ux_pack_registry.cpp +++ b/modules/ui_lvgl_ux_packs/tests/test_ux_pack_registry.cpp @@ -11,16 +11,20 @@ int main() ui_lvgl_ux::findUxPackById("uconsole_desktop"); const ui_lvgl_ux::IUxPack* tiny = ui_lvgl_ux::findUxPackById("tiny_node_status"); + const ui_lvgl_ux::IUxPack* cardputer = + ui_lvgl_ux::findUxPackById("cardputer_compact"); const ui_lvgl_ux::IUxPack* simulator = ui_lvgl_ux::findUxPackById("simulator_full"); assert(compatibility != nullptr); assert(uconsole != nullptr); assert(tiny != nullptr); + assert(cardputer != nullptr); assert(simulator != nullptr); assert(std::strcmp(compatibility->id(), "compatibility") == 0); assert(std::strcmp(uconsole->id(), "uconsole_desktop") == 0); assert(std::strcmp(tiny->id(), "tiny_node_status") == 0); + assert(std::strcmp(cardputer->id(), "cardputer_compact") == 0); assert(std::strcmp(simulator->id(), "simulator_full") == 0); assert(ui_lvgl_ux::findUxPackById("missing") == nullptr); assert(ui_lvgl_ux::findUxPackById(nullptr) == nullptr);