rsdeck: dual-boot launcher, RNode mode, build pipeline

This commit is contained in:
DeFiDude
2026-06-10 18:38:49 -06:00
parent 16dedbfa3e
commit a2dee44b07
112 changed files with 20450 additions and 3 deletions
+7
View File
@@ -11,6 +11,7 @@
#include "config/BoardConfig.h"
#include "config/Config.h"
#include "platform/RsDeckModeSwitch.h"
#include "hal/Display.h"
#include "hal/TouchInput.h"
#include "hal/Trackball.h"
@@ -1073,6 +1074,12 @@ void setup() {
Serial.printf("[BOOT] Reset: %s (%d)\n", reasonStr, (int)reason);
Serial.printf("[BOOT] Heap: %lu PSRAM: %lu\n",
(unsigned long)ESP.getFreeHeap(), (unsigned long)ESP.getPsramSize());
// Dual-boot layout: re-arm the launcher so the next reset shows the chooser.
auto launcherBoot = rs_deck::returnToLauncherNextBoot();
if (!launcherBoot.ok) {
Serial.printf("[BOOT] Launcher return unavailable: %s\n", launcherBoot.message);
}
if (!psramFound() || heap_caps_get_largest_free_block(MALLOC_CAP_SPIRAM) < 1024 * 1024) {
Serial.printf("[BOOT] FATAL: PSRAM unavailable or too fragmented (largest=%lu)\n",
(unsigned long)heap_caps_get_largest_free_block(MALLOC_CAP_SPIRAM));
+76
View File
@@ -0,0 +1,76 @@
#pragma once
#include <Arduino.h>
#include "esp_ota_ops.h"
#include "esp_partition.h"
// Boot-mode selection for the rsDeck dual-boot layout (launcher/standalone/rnode
// in ota_0/1/2). On the legacy single-app layout ota_0 is the running standalone,
// so re-arming the launcher is a harmless self-select.
namespace rs_deck {
enum class FirmwareMode : uint8_t {
Launcher,
Standalone,
RNode,
};
struct SwitchResult {
bool ok;
const char* message;
};
inline esp_partition_subtype_t modeSubtype(FirmwareMode mode) {
switch (mode) {
case FirmwareMode::Launcher:
return ESP_PARTITION_SUBTYPE_APP_OTA_0;
case FirmwareMode::Standalone:
return ESP_PARTITION_SUBTYPE_APP_OTA_1;
case FirmwareMode::RNode:
return ESP_PARTITION_SUBTYPE_APP_OTA_2;
}
return ESP_PARTITION_SUBTYPE_APP_OTA_0;
}
inline const esp_partition_t* modePartition(FirmwareMode mode) {
return esp_partition_find_first(ESP_PARTITION_TYPE_APP, modeSubtype(mode), nullptr);
}
inline const char* modeName(FirmwareMode mode) {
switch (mode) {
case FirmwareMode::Launcher:
return "Launcher";
case FirmwareMode::Standalone:
return "Standalone";
case FirmwareMode::RNode:
return "RNode";
}
return "Unknown";
}
inline SwitchResult setNextBoot(FirmwareMode mode) {
const esp_partition_t* target = modePartition(mode);
if (!target) {
return {false, "target partition not found"};
}
esp_err_t err = esp_ota_set_boot_partition(target);
if (err != ESP_OK) {
return {false, esp_err_to_name(err)};
}
return {true, "boot partition updated"};
}
inline SwitchResult returnToLauncherNextBoot() {
return setNextBoot(FirmwareMode::Launcher);
}
// Snake_case aliases for the launcher and RNode helper.
inline esp_partition_subtype_t mode_subtype(FirmwareMode mode) { return modeSubtype(mode); }
inline const esp_partition_t* mode_partition(FirmwareMode mode) { return modePartition(mode); }
inline const char* mode_name(FirmwareMode mode) { return modeName(mode); }
inline SwitchResult set_next_boot(FirmwareMode mode) { return setNextBoot(mode); }
inline SwitchResult return_to_launcher_next_boot() { return returnToLauncherNextBoot(); }
} // namespace rs_deck