feat(crowpanel-35): add Elecrow CrowPanel 3.5" (ESP32-S3, ILI9488 + GT911) touch target

- New crowpanel_35 variant: display, SD, board and target files, plus board JSON
- Portrait mode is drawn rotated 180°; landscape stays at rotation 3
- Share the GT911 touch driver between Wio Tracker L2 and CrowPanel
  (WioTrackerL2Touch.cpp -> src/helpers/input/LgfxGt911Touch.cpp)
- platformio envs, flasher/site entries, release and merge-bin support
- Tests for the CrowPanel SD codec and merge-bin

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0132MkJ7RUV32mV9F7o4PJMm
This commit is contained in:
Michael A. CojocariandClaude Opus 5.5 committed 2026-10-02 20:16:06 -04:00
1 parent f7402e628c
commit dbecef0b6f
29 files changed
+1461 -118

No files matched your search

+27 -5
View File
@@ -56,9 +56,13 @@ static uint32_t _atoi(const char* sp) {
#include <SD_MMC.h>
#include <WioTrackerL2Io.h>
#endif
#if defined(HAS_TDECK_GT911) || defined(HAS_TDECK_PRO) || defined(HELTEC_LORA_V4_R8) || defined(TLORA_PAGER) || defined(HAS_THINKNODE_M9)
#if defined(HAS_TDECK_GT911) || defined(HAS_TDECK_PRO) || defined(HELTEC_LORA_V4_R8) || defined(TLORA_PAGER) || defined(HAS_THINKNODE_M9) || defined(HAS_CROWPANEL_35)
#if defined(HAS_CROWPANEL_35)
#include <CrowPanel35SD.h>
#else
#include <SD.h>
#include "SdFastClock.h" // post-mount operating-clock raise (SD_SPI_FAST_HZ boards)
#endif
#include <Preferences.h>
#if defined(TLORA_PAGER)
#include <mbedtls/sha256.h>
@@ -270,7 +274,7 @@ extern volatile uint8_t g_wifi_last_disc_reason;
#include "esp_task_wdt.h" // task-watchdog reconfigure — see setup() (GH #56)
#if defined(HAS_TDECK_GT911) || defined(HAS_TDECK_PRO) || defined(HELTEC_LORA_V4_R8) || defined(TLORA_PAGER) || defined(HAS_THINKNODE_M9)
#if defined(HAS_TDECK_GT911) || defined(HAS_TDECK_PRO) || defined(HELTEC_LORA_V4_R8) || defined(TLORA_PAGER) || defined(HAS_THINKNODE_M9) || defined(HAS_CROWPANEL_35)
// ---- SPIFFS -> SD migration (fixes the beta_36 "lost my profile" upgrades) ----
// Users who flipped "Store data on SD" before beta_36 ran with the toggle IGNORED
// (the flag never survived a reboot), so their identity/prefs/contacts kept living
@@ -858,6 +862,9 @@ void setup() {
uint8_t r = touchPrefsGetUiRotation();
if (r == 1) display.setDisplayRotation(1);
else if (r == 3) display.setDisplayRotation(3);
#if defined(HAS_CROWPANEL_35)
else display.setDisplayRotation(0); // restore saved portrait
#endif
}
#endif
#if defined(HAS_TDECK_PRO)
@@ -1082,8 +1089,9 @@ void setup() {
Serial.println("[BOOT] wio-l2 SD_MMC unavailable; using SPIFFS");
}
#endif
#if defined(HAS_TDECK_GT911) || defined(HAS_TDECK_PRO) || defined(HELTEC_LORA_V4_R8) || defined(TLORA_PAGER) || defined(HAS_THINKNODE_M9)
#if defined(HAS_TDECK_GT911) || defined(HAS_TDECK_PRO) || defined(HELTEC_LORA_V4_R8) || defined(TLORA_PAGER) || defined(HAS_THINKNODE_M9) || defined(HAS_CROWPANEL_35)
{
#if !defined(HAS_CROWPANEL_35)
#if defined(TLORA_PAGER)
extern SPIClass* tloraPagerSharedSPI(); // display/radio/SD shared bus
#elif defined(HELTEC_LORA_V4_R8)
@@ -1092,6 +1100,7 @@ void setup() {
extern SPIClass* m9SharedSPI(); // radio/display/SD shared bus
#else
extern SPIClass* tdeckSharedSPI(); // LoRa SPI bus
#endif
#endif
bool setup_done = false;
{ Preferences _p; if (_p.begin("touch", true)) {
@@ -1115,6 +1124,7 @@ void setup() {
// device has no usable SPIFFS, the user opted in, or it's a brand-new device.
bool want_full_sd = !spiffs_ok || use_sd_pref || fresh_install;
#if !defined(HAS_CROWPANEL_35)
#if defined(TLORA_PAGER)
SPIClass* _spi = tloraPagerSharedSPI();
#elif defined(HELTEC_LORA_V4_R8)
@@ -1123,9 +1133,17 @@ void setup() {
SPIClass* _spi = m9SharedSPI();
#else
SPIClass* _spi = tdeckSharedSPI();
#endif
#endif
bool sd_mounted = false;
#if defined(TLORA_PAGER)
#if defined(HAS_CROWPANEL_35)
sdMountDiagBegin();
const bool begin_ok = SD.begin();
sd_mounted = begin_ok && SD.cardType() != CARD_NONE;
sdMountDiagAttempt(0, begin_ok, sd_mounted);
sdMountDiagSetMounted(sd_mounted, 0);
if (!sd_mounted) Serial.println("[BOOT] CrowPanel SD unavailable; using SPIFFS");
#elif defined(TLORA_PAGER)
sdMountDiagBegin();
if (!_spi) {
Serial.println("[BOOT] SD: shared SPI unavailable");
@@ -1317,6 +1335,10 @@ void setup() {
if (adopt) {
sd_storage = store.useSdStorage();
g_full_data_on_sd = sd_storage;
if (!sd_storage) {
g_contacts_on_sd = false;
Serial.println("[BOOT] SD data directory setup failed; using SPIFFS");
}
// On a genuine first run, persist the auto-pick so the "Store data on SD"
// toggle reflects it and the choice sticks on every later boot.
if (fresh_install && sd_storage && !use_sd_pref) {
@@ -1402,7 +1424,7 @@ void setup() {
#if defined(HAS_WIO_TRACKER_L2)
SdNvsPrefs::useFile(sd_storage ? (fs::FS*)&SD_MMC : (fs::FS*)&SPIFFS,
sd_storage ? "/meshcomod" : "/prefs");
#elif defined(HAS_TDECK_GT911) || defined(HAS_TDECK_PRO) || defined(HELTEC_LORA_V4_R8) || defined(TLORA_PAGER) || defined(HAS_THINKNODE_M9)
#elif defined(HAS_TDECK_GT911) || defined(HAS_TDECK_PRO) || defined(HELTEC_LORA_V4_R8) || defined(TLORA_PAGER) || defined(HAS_THINKNODE_M9) || defined(HAS_CROWPANEL_35)
SdNvsPrefs::useFile(sd_storage ? (fs::FS*)&SD : (fs::FS*)&SPIFFS,
sd_storage ? "/meshcomod" : "/prefs");
#else