diff --git a/include/lv_conf_m9.h b/include/lv_conf_m9.h new file mode 100644 index 0000000..db9237a --- /dev/null +++ b/include/lv_conf_m9.h @@ -0,0 +1,25 @@ +#pragma once + +// M9-specific LVGL config wrapper. +// +// Why this exists: +// - LVGL 8.4's lv_hal_indev.h unconditionally defines LV_INDEV_DEF_SCROLL_*. +// - Our shared lv_conf defines LV_INDEV_DEF_SCROLL_LIMIT for touch tuning, and +// M9's build flags define LV_INDEV_DEF_SCROLL_THROW. That combination emits +// macro-redefinition warnings, even though M9 has no touch input path. +// +// For M9, include the shared project LV config, then drop touch-scroll tuning +// macros so LVGL's keypad-only defaults can apply without warnings. +#ifndef LV_CONF_H +#define LV_CONF_H +#endif + +#include "lv_conf.h" + +#ifdef LV_INDEV_DEF_SCROLL_LIMIT +#undef LV_INDEV_DEF_SCROLL_LIMIT +#endif + +#ifdef LV_INDEV_DEF_SCROLL_THROW +#undef LV_INDEV_DEF_SCROLL_THROW +#endif diff --git a/platformio.ini b/platformio.ini index 0d67afa..46e4bbe 100644 --- a/platformio.ini +++ b/platformio.ini @@ -1143,13 +1143,17 @@ board_build.partitions = variants/thinknode_m9/partitions_m9_touch.csv ; DriveDiosInSleepMode (0x012A, FW 0x0308+) with CMD_PERR -> begin() = -706. ; The pre-script makes RadioLib's config() skip it on old FW (idempotent, ; per-env libdeps copy). See scripts/build/patch_radiolib_lr11x0.py. -extra_scripts = pre:scripts/build/pre_gen_baked.py, pre:scripts/inject_wifi_env.py, pre:scripts/build/patch_radiolib_lr11x0.py, merge-bin.py +extra_scripts = pre:scripts/build/pre_gen_baked.py, pre:scripts/inject_wifi_env.py, pre:scripts/build/patch_radiolib_lr11x0.py, pre:scripts/build/patch_meshcore_rv3028_define.py, merge-bin.py + +build_unflags = + -std=gnu++11 + -std=gnu++14 build_flags = ; 1.17 core: ESP32Board.cpp includes -> MicroNMEALocationProvider.h (header-only ; provider), so MicroNMEA never chains into the core lib's LDF scope -- hand it the path. -I"${platformio.libdeps_dir}/${this.__env__}/MicroNMEA/src" - -Wno-deprecated-declarations -Wno-unused-parameter -DNDEBUG -DRADIOLIB_STATIC_ONLY=1 -DRADIOLIB_GODMODE=1 + -Wno-deprecated-declarations -Wno-unused-parameter -Wno-cpp -Wno-overflow -Wno-return-type -std=gnu++17 -DNDEBUG -DRADIOLIB_STATIC_ONLY=1 -DRADIOLIB_GODMODE=1 -D MC_VENDORED_TOUCH_APP -D LORA_FREQ=869.618 -D LORA_BW=62.5 @@ -1331,9 +1335,8 @@ build_flags = -D HAS_TOUCH_UI=1 -D FIRMWARE_OTA_ENV='"ThinkNode_M9_companion_radio_touch"' -D ENABLE_ADVERT_ON_BOOT=0 - -D LV_CONF_PATH=lv_conf.h + -D LV_CONF_PATH=lv_conf_m9.h -D LV_CONF_INCLUDE_SIMPLE=1 - -D LV_INDEV_DEF_SCROLL_THROW=7 -D MAX_CONTACTS=2000 -D MAX_GROUP_CHANNELS=40 -D DISPLAY_CLASS=ST7789LCDDisplay diff --git a/scripts/build/patch_meshcore_rv3028_define.py b/scripts/build/patch_meshcore_rv3028_define.py new file mode 100644 index 0000000..ab88690 --- /dev/null +++ b/scripts/build/patch_meshcore_rv3028_define.py @@ -0,0 +1,34 @@ +Import("env") +import os + +MARKER = "wadamesh-rv3028-guard-patch" +OLD = "#define RV3028_ADDRESS 0x52" +NEW = """#ifndef RV3028_ADDRESS +#define RV3028_ADDRESS 0x52 +#endif // wadamesh-rv3028-guard-patch""" + +path = os.path.join( + env.subst("$PROJECT_LIBDEPS_DIR"), + env.subst("$PIOENV"), + "MeshCore", + "src", + "helpers", + "AutoDiscoverRTCClock.cpp", +) + +if not os.path.isfile(path): + print("[patch_meshcore_rv3028_define] WARNING: %s not found (libdeps not fetched yet?)" % path) + print("[patch_meshcore_rv3028_define] WARNING: MeshCore NOT patched - re-run build once libdeps exist") +else: + with open(path) as f: + src = f.read() + + if MARKER in src: + print("[patch_meshcore_rv3028_define] already patched") + elif OLD in src: + with open(path, "w") as f: + f.write(src.replace(OLD, NEW, 1)) + print("[patch_meshcore_rv3028_define] patched RV3028_ADDRESS guard in AutoDiscoverRTCClock.cpp") + else: + print("[patch_meshcore_rv3028_define] WARNING: pattern not found - MeshCore version drift?") + print("[patch_meshcore_rv3028_define] WARNING: check AutoDiscoverRTCClock.cpp by hand, NOT patched") \ No newline at end of file diff --git a/src/ui-touch/SnakeGame.cpp b/src/ui-touch/SnakeGame.cpp index f83b429..4ba731b 100644 --- a/src/ui-touch/SnakeGame.cpp +++ b/src/ui-touch/SnakeGame.cpp @@ -25,9 +25,12 @@ SnakeGame* SnakeGame::s_active = nullptr; bool SnakeGame::isOpen() { return s_active != nullptr && s_active->root_ != nullptr; } void SnakeGame::steer(int dx, int dy) { - if (!s_active || !s_active->started_ || s_active->over_) return; + if (!s_active || s_active->over_) return; // Trackball deltas -> one cardinal direction (dominant axis). if (dx == 0 && dy == 0) return; + // Keyboard-only boards (M9) have no touch "New game" tap target; first + // directional input should start immediately. + if (!s_active->started_) s_active->startGame(); const int adx = dx < 0 ? -dx : dx, ady = dy < 0 ? -dy : dy; if (adx >= ady) s_active->setDir(dx > 0 ? 1 : -1, 0); else s_active->setDir(0, dy > 0 ? 1 : -1); @@ -105,7 +108,7 @@ void SnakeGame::updateScoreLabel() { if (over_) lv_label_set_text_fmt(score_, TR("Game over \xe2\x80\x94 score %d (tap to restart)"), score_val_); else if (paused_) lv_label_set_text_fmt(score_, TR("Paused \xe2\x80\x94 score %d"), score_val_); else if (started_) lv_label_set_text_fmt(score_, TR("score %d"), score_val_); - else lv_label_set_text(score_, TR("Snake \xe2\x80\x94 swipe or roll the trackball")); + else lv_label_set_text(score_, TR("Snake \xe2\x80\x94 swipe, roll, or press a direction")); } void SnakeGame::step() { diff --git a/src/ui-touch/SnakeGame.h b/src/ui-touch/SnakeGame.h index 426ffe7..7bc63ed 100644 --- a/src/ui-touch/SnakeGame.h +++ b/src/ui-touch/SnakeGame.h @@ -6,9 +6,10 @@ // Self-contained Snake mini-game launched from the Apps drawer. // // Owns a full-screen overlay on lv_layer_top: a canvas playfield filling the -// unoccupied screen, a score line, and a close button. The game waits on a -// "New game" button (doesn't start moving on open). Steer by swipe OR trackball -// (UITask routes the trackball here via isOpen()/steer() and hides the cursor); +// unoccupied screen, a score line, and a close button. The game can start from +// the "New game" button OR from the first directional steer input. Steer by +// swipe/gesture, trackball, or hardware directional keys (UITask routes board +// input here via isOpen()/steer()); // tap to restart after a game over; the X closes it. One instance at a time. // // Decoupled from UITask internals — depends only on LVGL and lvglPsramAlloc. diff --git a/src/ui-touch/UITask.cpp b/src/ui-touch/UITask.cpp index d366ee1..c3e66af 100644 --- a/src/ui-touch/UITask.cpp +++ b/src/ui-touch/UITask.cpp @@ -38153,6 +38153,7 @@ static bool m9HandleNavKey(int key) { s_nav_show = true; if (g_lv.task) g_lv.task->noteUserInput(); return true; case M9_KEY_HOME: if (s_setup_root) return true; + s_nav_ta_editing = false; // Home is global, including while a textarea is being edited if (s_apppage_close) { // A full-screen app page (Lua app, Snake, Web…) isn't a popup-registry // row — close it and stop: one action per press, so HOME on the Home @@ -38458,6 +38459,10 @@ if (g_lv.task && g_lv.task->isManualLock()) { lv_obj_t* ta = ta_focused; #endif #if defined(HAS_M9_KEYBOARD) + // Unlike directional keys and Back, the dedicated Home key is global. Route + // it before the textarea split so edit mode cannot swallow it as an unknown + // non-printable byte. + if (key == M9_KEY_HOME && m9HandleNavKey(key)) return; if (m9HandleArrowKey(key, ta)) return; // ← runs BEFORE the if(!ta) split #endif if (!ta) {