mirror of
https://github.com/vicliu624/trail-mate.git
synced 2026-11-11 14:47:39 +00:00
Compose the CM0 fullscreen application and standard Debian package, align the Cardputer Zero shell, and share protocol, configuration, audio and storage services with embedded targets through existing platform seams. Add the paginated on-device TMAP creator using Center's published producer, private workspace recovery and direct keyboard shortcuts. Preserve unfinished management work behind its existing opt-in capability. Include native, ARM and shared-core regression fixtures, integration records, packaging helpers and dependency/license updates. Keep local build trees, device credentials, produced packages and validation logs outside version control. Validation before integration: ESP stack hygiene, Reticulum scope guard, staged whitespace checks and GitNexus scope audit. Prior device/build evidence and remaining hardware/package boundaries are recorded in the acceptance documents.
183 lines
5.5 KiB
C++
183 lines
5.5 KiB
C++
#pragma once
|
||
|
||
#include <chrono>
|
||
#include <cstdint>
|
||
#include <deque>
|
||
#include <memory>
|
||
#include <vector>
|
||
|
||
#include "app/linux_app_facade.h"
|
||
#include "core/canvas.h"
|
||
#include "platform/surface_presenter.h"
|
||
|
||
#include "lvgl.h"
|
||
|
||
namespace trailmate::cardputer_zero
|
||
{
|
||
namespace app
|
||
{
|
||
struct InputEvent;
|
||
}
|
||
|
||
namespace linux_ui
|
||
{
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// ShellSession
|
||
//
|
||
// Owns the app facade, shared UI startup sequence, input event queue, and
|
||
// per-frame tick logic. Does NOT own LVGL lifecycle (lv_init/lv_deinit),
|
||
// display, or framebuffer. That responsibility lives in the *LvglHost
|
||
// classes.
|
||
//
|
||
// Both the simulator and the real device shell share this session object.
|
||
// ---------------------------------------------------------------------------
|
||
|
||
class ShellSession
|
||
{
|
||
public:
|
||
ShellSession();
|
||
~ShellSession();
|
||
|
||
ShellSession(const ShellSession&) = delete;
|
||
ShellSession& operator=(const ShellSession&) = delete;
|
||
|
||
/// Initialize the app facade and begin the shared UI startup sequence.
|
||
/// Must be called after LVGL has been initialized by the host.
|
||
bool begin();
|
||
// Call before an externally owned LVGL instance is destroyed.
|
||
void releaseUiBindings();
|
||
|
||
/// Drive one frame worth of app-layer work: update core services, tick
|
||
/// the event runtime, dispatch pending events.
|
||
void tick();
|
||
|
||
/// Push simulated or evdev input events into the session queue.
|
||
void enqueueInputs(const std::vector<app::InputEvent>& events);
|
||
app::TextInputState textInputState();
|
||
|
||
/// Returns true once the startup sequence has finalized.
|
||
bool ready() const noexcept;
|
||
|
||
/// Access the underlying app facade.
|
||
MinimalLinuxAppFacade& facade() noexcept { return app_facade_; }
|
||
const MinimalLinuxAppFacade& facade() const noexcept
|
||
{
|
||
return app_facade_;
|
||
}
|
||
|
||
private:
|
||
friend class CanvasLvglHost;
|
||
|
||
struct QueuedKeyEvent
|
||
{
|
||
std::uint32_t key{};
|
||
lv_indev_state_t state{};
|
||
std::shared_ptr<const app::TextEdit> edit{};
|
||
};
|
||
|
||
/// Called by the LVGL host's read-input callback to dequeue one key event.
|
||
/// Returns false when the queue is empty.
|
||
bool dequeueKeyEvent(std::uint32_t* key, lv_indev_state_t* state);
|
||
|
||
/// Peek: returns true if at least one event is enqueued (used to set
|
||
/// continue_reading without consuming the next event).
|
||
bool hasPendingKeyEvent() const noexcept;
|
||
|
||
struct Impl;
|
||
std::unique_ptr<Impl> impl_;
|
||
MinimalLinuxAppFacade app_facade_;
|
||
bool initialized_{false};
|
||
};
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// CanvasLvglHost
|
||
//
|
||
// Owns the LVGL lifecycle (lv_init / lv_deinit), display, RGB565 buffer,
|
||
// keypad input device, and the framebuffer-to-Canvas copy step.
|
||
//
|
||
// Suitable for the SDL simulator and the custom Linux framebuffer shell.
|
||
// ---------------------------------------------------------------------------
|
||
|
||
class CanvasLvglHost
|
||
{
|
||
public:
|
||
explicit CanvasLvglHost(ShellSession& shell);
|
||
~CanvasLvglHost();
|
||
|
||
CanvasLvglHost(const CanvasLvglHost&) = delete;
|
||
CanvasLvglHost& operator=(const CanvasLvglHost&) = delete;
|
||
|
||
/// Drive one frame: tick the shell session, run lv_timer_handler(), and
|
||
/// (if dirty) copy the LVGL framebuffer to the output canvas.
|
||
void tick();
|
||
|
||
/// Read-only access to the output canvas for the surface presenter.
|
||
const core::Canvas& canvas() const noexcept;
|
||
|
||
/// LVGL callbacks — exact typed signatures matching LVGL's typedefs.
|
||
/// Implemented in the .cpp, where lvgl.h provides the full definitions.
|
||
static void flushCb(lv_display_t* display, const lv_area_t* area,
|
||
uint8_t* px_map);
|
||
static void readInputCb(lv_indev_t* indev, lv_indev_data_t* data);
|
||
|
||
private:
|
||
void copyFrameBufferToCanvas();
|
||
|
||
ShellSession& shell_;
|
||
lv_display_t* display_{};
|
||
lv_indev_t* keypad_{};
|
||
core::Canvas canvas_;
|
||
std::vector<std::uint16_t> frame_buffer_{};
|
||
bool dirty_{true};
|
||
};
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// NativeLvglHost
|
||
//
|
||
// Thin host for the M5Stack Linux SDK path where LVGL display and input are
|
||
// already owned by the SDK. Only drives the shell session tick each frame.
|
||
//
|
||
// Usage in SDK main loop:
|
||
//
|
||
// lv_init();
|
||
// initLinuxDisplay(); // SDK-owned fbdev / evdev
|
||
//
|
||
// ShellSession shell;
|
||
// shell.begin();
|
||
//
|
||
// NativeLvglHost host{shell};
|
||
// while (true) {
|
||
// host.tick();
|
||
// lv_timer_handler();
|
||
// usleep(1000);
|
||
// }
|
||
// ---------------------------------------------------------------------------
|
||
|
||
class NativeLvglHost
|
||
{
|
||
public:
|
||
explicit NativeLvglHost(ShellSession& shell) : shell_(shell) {}
|
||
|
||
/// Drive the shell session tick. Caller is responsible for
|
||
/// lv_timer_handler() and the main-loop sleep.
|
||
void tick() { shell_.tick(); }
|
||
|
||
private:
|
||
ShellSession& shell_;
|
||
};
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// Convenience – desktop simulator / custom-fbdev main loop
|
||
// ---------------------------------------------------------------------------
|
||
|
||
/// Create a ShellSession + CanvasLvglHost and run the classic frame-paced
|
||
/// main loop driven by a SurfacePresenter. Backward-compatible entrypoint.
|
||
void runShellUi(
|
||
platform::SurfacePresenter& presenter,
|
||
std::chrono::milliseconds auto_exit_after = std::chrono::milliseconds::zero(),
|
||
bool tmap_creation = false);
|
||
|
||
} // namespace linux_ui
|
||
} // namespace trailmate::cardputer_zero
|