system/nxstore: add LVGL app-store UI.

Add nxstore, an LVGL-based frontend for nxpkg (system/nxpkg): lists
packages from the local index, installs/launches the selected one,
and supervises whatever it hands the screen to.

Card-based app list (populate_app_list()): each row shows name,
version, and description/status, install/launch state reflected via
icon glyph and color (LV_SYMBOL_DOWNLOAD/PLAY, accent/success color),
and a sliding-segment progress bar during install (no real byte-level
progress is available from pkg_install(), so this reads as
'actively working' without fabricating a percentage). Explicit
LV_STATE_PRESSED styling on every tappable row/button, since no LVGL
theme is loaded and a tap would otherwise give no visual feedback at
all.

Supervisor screen (build_run_screen()/nxstore_enter_running_screen()):
a launched app (e.g. a game that owns /dev/fb0 directly, not just
another LVGL client) gets a dedicated screen with a name label and a
Close button, confined to the border region the launched app's own
scaled/centered framebuffer output never draws into, so switching
back to it doesn't fight over pixels with whatever the app already
put in the framebuffer.

Close/reap handling (close_running_app_event_cb()/
nxstore_poll_running_app()): sends SIGTERM and polls waitpid(WNOHANG)
for the launched pid, but explicitly also treats waitpid() returning
ECHILD as 'already gone' rather than 'still running' - both the
close-button handler and the passive per-loop poll independently race
to reap the same child, so whichever one loses that race must not
spin forever waiting for a wait() that can now never succeed. Requires
the target app to install its own SIGTERM handler to exit cleanly
(this is why there is no generic force-kill fallback here: an
earlier version of this code called task_delete() when SIGTERM wasn't
reaped quickly enough, which was found on real hardware to hang the
entire board - not just the one task - when it landed mid
framebuffer/heap access on this flat-memory build).

Toast notifications (nxstore_toast()) provide a transient, unmissable
confirmation for install/uninstall/launch outcomes and app-closed
events, additive to the durable per-row subtitle text rather than a
replacement for it.

nxstore's own boot-time catalog sync waits (bounded, 15s) on
g_wifi_dhcp_ret before attempting a network fetch, since Wi-Fi
association completing doesn't imply DHCP has - an HTTP fetch
attempted in that window fails with -ENETUNREACH even though the
link itself is already up, indistinguishable from being genuinely
offline without this wait.

Assisted-by: Claude:claude-sonnet-5
Signed-off-by: aviralgarg05 <gargaviral99@gmail.com>
This commit is contained in:
aviralgarg05 2026-07-11 19:40:21 +05:30
parent f363a8f444
commit 778bc0e64c
6 changed files with 1905 additions and 0 deletions

View file

@ -0,0 +1,35 @@
# ##############################################################################
# apps/system/nxstore/CMakeLists.txt
#
# SPDX-License-Identifier: Apache-2.0
#
# Licensed to the Apache Software Foundation (ASF) under one or more contributor
# license agreements. See the NOTICE file distributed with this work for
# additional information regarding copyright ownership. The ASF licenses this
# file to you under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
#
# ##############################################################################
if(CONFIG_SYSTEM_NXSTORE)
nuttx_add_application(
NAME
${CONFIG_SYSTEM_NXSTORE_PROGNAME}
PRIORITY
${CONFIG_SYSTEM_NXSTORE_PRIORITY}
STACKSIZE
${CONFIG_SYSTEM_NXSTORE_STACKSIZE}
MODULE
${CONFIG_SYSTEM_NXSTORE}
SRCS
nxstore_main.c)
endif()

30
system/nxstore/Kconfig Normal file
View file

@ -0,0 +1,30 @@
#
# For a description of the syntax of this configuration file,
# see the file kconfig-language.txt in the NuttX tools repository.
#
config SYSTEM_NXSTORE
tristate "Nxstore LVGL App Store"
default n
depends on GRAPHICS_LVGL && SYSTEM_NXPKG
select NETUTILS_CJSON
---help---
Enable the Nxstore LVGL graphical application store frontend.
Lists packages from the local nxpkg repository, installs the
selected one via nxpkg, and launches it.
if SYSTEM_NXSTORE
config SYSTEM_NXSTORE_PROGNAME
string "Program name"
default "nxstore"
config SYSTEM_NXSTORE_PRIORITY
int "nxstore task priority"
default 100
config SYSTEM_NXSTORE_STACKSIZE
int "nxstore stack size"
default 8192
endif

25
system/nxstore/Make.defs Normal file
View file

@ -0,0 +1,25 @@
############################################################################
# apps/system/nxstore/Make.defs
#
# SPDX-License-Identifier: Apache-2.0
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership. The
# ASF licenses this file to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance with the
# License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
############################################################################
ifneq ($(CONFIG_SYSTEM_NXSTORE),)
CONFIGURED_APPS += $(APPDIR)/system/nxstore
endif

32
system/nxstore/Makefile Normal file
View file

@ -0,0 +1,32 @@
############################################################################
# apps/system/nxstore/Makefile
#
# SPDX-License-Identifier: Apache-2.0
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership. The
# ASF licenses this file to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance with the
# License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
############################################################################
include $(APPDIR)/Make.defs
PROGNAME = $(CONFIG_SYSTEM_NXSTORE_PROGNAME)
PRIORITY = $(CONFIG_SYSTEM_NXSTORE_PRIORITY)
STACKSIZE = $(CONFIG_SYSTEM_NXSTORE_STACKSIZE)
MODULE = $(CONFIG_SYSTEM_NXSTORE)
MAINSRC = nxstore_main.c
include $(APPDIR)/Application.mk

100
system/nxstore/README.txt Normal file
View file

@ -0,0 +1,100 @@
nxstore - an LVGL touchscreen app store for NuttX
=================================================
nxstore is a graphical front-end for system/nxpkg. It lists the
packages available in a nxpkg repository, installs the one you tap via
nxpkg, launches it, and supervises it with an on-screen "Close"
control. It is the touchscreen equivalent of driving the nxpkg CLI by
hand; both consume the same repository, so the repository/server setup
(layout, how to serve it, populating it with tools/export_pkg_repo.py,
pointing the board at it) is documented once, in system/nxpkg's
README.txt, and is not repeated here.
Dependencies
============
Kconfig: SYSTEM_NXSTORE depends on GRAPHICS_LVGL and SYSTEM_NXPKG and
selects NETUTILS_CJSON. It needs a working framebuffer (/dev/fb0) and
a touch input device (/dev/input0) - the same graphics/input stack
examples/lvgldemo uses. NETUTILS_CJSON is used to parse the
repository index and package manifests.
On-device lifecycle
===================
1. Browse - the app list is built from the repository index nxpkg
fetched. Installed packages show a launch action;
not-yet-installed ones show an install action.
2. Install - tapping an uninstalled package runs the nxpkg install
flow (download -> sha256 verify -> transactional
install) on a background worker thread, with progress
shown as a toast.
3. Launch - tapping an installed package spawns its payload
(posix_spawn) and switches to the "running" screen: a
thin bar across the top NXSTORE_BAR_HEIGHT pixels (see
include/system/nxstore_chrome.h) carrying the app name
and a Close button, with the rest of the framebuffer
left to the running app.
4. Close - see "Closing a running app" below.
Launched apps are given NXSTORE_LAUNCH_STACKSIZE (32 KiB) of stack -
posix_spawn's default (CONFIG_POSIX_SPAWN_DEFAULT_STACKSIZE, 2 KiB) is
far too small for a real LVGL/framebuffer app, and overflowing it does
not fail loudly (it corrupts adjacent heap, surfacing later as a crash
nowhere near the real cause).
Closing a running app: the cooperative-SIGTERM contract
=======================================================
This is the one thing an app author MUST get right to be launchable
from nxstore.
The Close button sends the running app SIGTERM and waits for it to
reap itself. It does NOT (and cannot safely) force-kill the task:
- On a build with CONFIG_SIG_DEFAULT disabled (the default), NuttX
has no default action for SIGTERM at all. Delivery does nothing
unless the app installs its own handler with sigaction().
- An earlier nxstore fell back to task_delete() when SIGTERM went
unreaped. On real hardware that force-kill landed while the app
was mid framebuffer/heap access and hung the *entire board* (not
just the task), requiring a physical power cycle. That fallback
was removed: there is no safe way to force-terminate an arbitrary
task from the outside here.
So an nxstore-launchable app must cooperate:
- Install an async-signal-safe SIGTERM handler that only sets a
volatile sig_atomic_t flag.
- Poll that flag from its own main loop and exit cleanly (freeing
the framebuffer, restoring input state, etc.) when it is set.
Apps whose main loop can never block indefinitely (they run to
completion on their own, or fail fast at startup) do not strictly need
a handler, but any app that renders in a long-lived loop does. See
these in-tree examples for the exact pattern:
- games/NXDoom (i_install_quit_signal / i_poll_quit_signal)
- examples/calculator
- games/cgol, games/brickmatch
If SIGTERM is not reaped within the timeout, nxstore keeps the running
screen up rather than returning to the app list - switching back while
the app might still be alive and drawing into the framebuffer would
just reproduce the original hang, hidden.
Configuration
=============
SYSTEM_NXSTORE_PROGNAME program/registration name (default nxstore)
SYSTEM_NXSTORE_PRIORITY task priority (default 100)
SYSTEM_NXSTORE_STACKSIZE nxstore's own stack (default 8192)
NXSTORE_LAUNCH_STACKSIZE (the stack given to launched apps) and
NXSTORE_BAR_HEIGHT (the reserved top bar) are compile-time constants in
the source / include/system/nxstore_chrome.h rather than Kconfig
options.

File diff suppressed because it is too large Load diff