rsdeck: prepare dual-mode 2.0 release

This commit is contained in:
DeFiDude committed 2026-06-13 17:33:00 -06:00
1 parent e2dad27836
commit f6d6aff288
58 files changed
+984 -447

No files matched your search

+1 -1
View File
@@ -168,7 +168,7 @@ void AudioNotify::playError() {
void AudioNotify::playBoot() {
if (!_enabled || !_i2sReady) return;
// === RATDECK BOOT SEQUENCE ===
// === RSDECK BOOT SEQUENCE ===
// Sci-fi computer startup: sweep -> digital arpeggio -> confirmation
// Total ~550ms
+1 -1
View File
@@ -1,7 +1,7 @@
#pragma once
// =============================================================================
// Ratdeck — LilyGo T-Deck Plus Pin Definitions
// rsDeck — LilyGo T-Deck Plus Pin Definitions
// =============================================================================
// --- Power Control ---
+15 -13
View File
@@ -1,13 +1,13 @@
#pragma once
// =============================================================================
// Ratdeck — Compile-Time Configuration
// rsDeck — Compile-Time Configuration
// =============================================================================
#define RATDECK_VERSION_MAJOR 1
#define RATDECK_VERSION_MINOR 9
#define RATDECK_VERSION_PATCH 3
#define RATDECK_VERSION_STRING "1.9.3"
#define RSDECK_VERSION_MAJOR 2
#define RSDECK_VERSION_MINOR 0
#define RSDECK_VERSION_PATCH 0
#define RSDECK_VERSION_STRING "2.0.0"
// --- Feature Flags ---
#define HAS_DISPLAY true
@@ -19,10 +19,10 @@
// TODO(BLE): Revisit as a dedicated Ratspeak BLE Peer transport based on the
// rsReticulum GATT/fragmentation/anti-loop design, after T-Deck Plus memory,
// flash, power, and interop behavior are tested end to end.
#ifndef RATDECK_EXPERIMENTAL_BLE
#define RATDECK_EXPERIMENTAL_BLE 0
#ifndef RSDECK_EXPERIMENTAL_BLE
#define RSDECK_EXPERIMENTAL_BLE 0
#endif
#define HAS_BLE RATDECK_EXPERIMENTAL_BLE
#define HAS_BLE RSDECK_EXPERIMENTAL_BLE
#define HAS_SD true
#define HAS_AUDIO true
#define HAS_GPS true // UBlox MIA-M10Q UART GPS
@@ -43,6 +43,8 @@
#define PATH_MESSAGES "/messages"
// --- SD Card Paths ---
// Legacy path kept intentionally so existing Standalone users keep their data.
// TODO: Migrate to /rsdeck only with an explicit data migration plan.
#define SD_PATH_CONFIG_DIR "/ratdeck/config"
#define SD_PATH_USER_CONFIG "/ratdeck/config/user.json"
#define SD_PATH_MESSAGES "/ratdeck/messages"
@@ -56,14 +58,14 @@
#define TCP_CONNECT_TIMEOUT_MS 500
// --- Announce Flood Defense ---
#define RATDECK_MAX_ANNOUNCES_PER_SEC 5 // Transport-level rate limit (before Ed25519 verify)
#define RSDECK_MAX_ANNOUNCES_PER_SEC 5 // Transport-level rate limit (before Ed25519 verify)
// --- Limits ---
#define RATDECK_MAX_NODES 100 // Endpoint device, not transport node
#define RATDECK_MAX_MESSAGES_PER_CONV 100
#define RSDECK_MAX_NODES 100 // Endpoint device, not transport node
#define RSDECK_MAX_MESSAGES_PER_CONV 100
#define FLASH_MSG_CACHE_LIMIT 20
#define RATDECK_MAX_OUTQUEUE 20
#define RATDECK_LXMF_SINGLE_FRAME_MAX 254 // T-Deck-safe payload cap until resource transfers are fixed
#define RSDECK_MAX_OUTQUEUE 20
#define RSDECK_LXMF_SINGLE_FRAME_MAX 254 // T-Deck-safe payload cap until resource transfers are fixed
#define PATH_PERSIST_INTERVAL_MS 60000
// --- Power Management ---
+23 -1
View File
@@ -1,6 +1,26 @@
#include "UserConfig.h"
#include "config/BoardConfig.h"
namespace {
bool validLoRaFrequency(uint32_t freq) {
return (freq >= 863000000UL && freq <= 870000000UL) ||
(freq >= 902000000UL && freq <= 928000000UL) ||
(freq >= 920000000UL && freq <= 925000000UL);
}
}
void UserConfig::sanitizeSettings() {
if (_settings.radioRegion >= REGION_COUNT) _settings.radioRegion = REGION_AMERICAS;
if (!validLoRaFrequency(_settings.loraFrequency)) {
_settings.loraFrequency = REGION_FREQ[constrain((int)_settings.radioRegion, 0, REGION_COUNT - 1)];
}
_settings.loraSF = constrain(_settings.loraSF, 5, 12);
_settings.loraBW = constrain(_settings.loraBW, 7800UL, 500000UL);
_settings.loraCR = constrain(_settings.loraCR, 5, 8);
_settings.loraTxPower = constrain(_settings.loraTxPower, -9, 22);
_settings.loraPreamble = constrain(_settings.loraPreamble, 6L, 65L);
}
bool UserConfig::parseJson(const String& json) {
Serial.printf("[CONFIG] Parsing config (%d bytes)\n", json.length());
@@ -102,11 +122,13 @@ bool UserConfig::parseJson(const String& json) {
if (_settings.announceInterval > 360) _settings.announceInterval = 360;
_settings.devMode = doc["dev_mode"] | false;
sanitizeSettings();
Serial.println("[CONFIG] Settings loaded");
return true;
}
String UserConfig::serializeToJson() const {
String UserConfig::serializeToJson() {
sanitizeSettings();
JsonDocument doc;
doc["radio_region"] = _settings.radioRegion;
+2 -1
View File
@@ -111,7 +111,8 @@ public:
private:
bool parseJson(const String& json);
String serializeToJson() const;
String serializeToJson();
void sanitizeSettings();
UserSettings _settings;
};
+3 -3
View File
@@ -8,6 +8,6 @@
#include <lvgl.h>
LV_FONT_DECLARE(lv_font_ratdeck_10)
LV_FONT_DECLARE(lv_font_ratdeck_12)
LV_FONT_DECLARE(lv_font_ratdeck_14)
LV_FONT_DECLARE(lv_font_rsdeck_10)
LV_FONT_DECLARE(lv_font_rsdeck_12)
LV_FONT_DECLARE(lv_font_rsdeck_14)
@@ -1,7 +1,7 @@
/*******************************************************************************
* Size: 10 px
* Bpp: 4
* Opts: --no-compress --no-prefilter --bpp 4 --size 10 --font .pio/libdeps/ratdeck_915/lvgl/scripts/built_in_font/Montserrat-Medium.ttf -r 0x20-0x7F,0xA0-0xFF,0x100-0x17F,0x400-0x4FF --format lvgl -o src/fonts/lv_font_ratdeck_10.c --force-fast-kern-format
* Opts: --no-compress --no-prefilter --bpp 4 --size 10 --font .pio/libdeps/rsdeck_915/lvgl/scripts/built_in_font/Montserrat-Medium.ttf -r 0x20-0x7F,0xA0-0xFF,0x100-0x17F,0x400-0x4FF --format lvgl -o src/fonts/lv_font_rsdeck_10.c --force-fast-kern-format
******************************************************************************/
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
@@ -10,11 +10,11 @@
#include <lvgl.h>
#endif
#ifndef LV_FONT_RATDECK_10
#define LV_FONT_RATDECK_10 1
#ifndef LV_FONT_RSDECK_10
#define LV_FONT_RSDECK_10 1
#endif
#if LV_FONT_RATDECK_10
#if LV_FONT_RSDECK_10
/*-----------------
* BITMAPS
@@ -4614,9 +4614,9 @@ static lv_font_fmt_txt_dsc_t font_dsc = {
/*Initialize a public general font descriptor*/
#if LVGL_VERSION_MAJOR >= 8
const lv_font_t lv_font_ratdeck_10 = {
const lv_font_t lv_font_rsdeck_10 = {
#else
lv_font_t lv_font_ratdeck_10 = {
lv_font_t lv_font_rsdeck_10 = {
#endif
.get_glyph_dsc = lv_font_get_glyph_dsc_fmt_txt, /*Function pointer to get glyph's data*/
.get_glyph_bitmap = lv_font_get_bitmap_fmt_txt, /*Function pointer to get glyph's bitmap*/
@@ -4638,5 +4638,5 @@ lv_font_t lv_font_ratdeck_10 = {
#endif /*#if LV_FONT_RATDECK_10*/
#endif /*#if LV_FONT_RSDECK_10*/
@@ -1,7 +1,7 @@
/*******************************************************************************
* Size: 12 px
* Bpp: 4
* Opts: --no-compress --no-prefilter --bpp 4 --size 12 --font .pio/libdeps/ratdeck_915/lvgl/scripts/built_in_font/Montserrat-Medium.ttf -r 0x20-0x7F,0xA0-0xFF,0x100-0x17F,0x400-0x4FF --format lvgl -o src/fonts/lv_font_ratdeck_12.c --force-fast-kern-format
* Opts: --no-compress --no-prefilter --bpp 4 --size 12 --font .pio/libdeps/rsdeck_915/lvgl/scripts/built_in_font/Montserrat-Medium.ttf -r 0x20-0x7F,0xA0-0xFF,0x100-0x17F,0x400-0x4FF --format lvgl -o src/fonts/lv_font_rsdeck_12.c --force-fast-kern-format
******************************************************************************/
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
@@ -10,11 +10,11 @@
#include <lvgl.h>
#endif
#ifndef LV_FONT_RATDECK_12
#define LV_FONT_RATDECK_12 1
#ifndef LV_FONT_RSDECK_12
#define LV_FONT_RSDECK_12 1
#endif
#if LV_FONT_RATDECK_12
#if LV_FONT_RSDECK_12
/*-----------------
* BITMAPS
@@ -5565,9 +5565,9 @@ static lv_font_fmt_txt_dsc_t font_dsc = {
/*Initialize a public general font descriptor*/
#if LVGL_VERSION_MAJOR >= 8
const lv_font_t lv_font_ratdeck_12 = {
const lv_font_t lv_font_rsdeck_12 = {
#else
lv_font_t lv_font_ratdeck_12 = {
lv_font_t lv_font_rsdeck_12 = {
#endif
.get_glyph_dsc = lv_font_get_glyph_dsc_fmt_txt, /*Function pointer to get glyph's data*/
.get_glyph_bitmap = lv_font_get_bitmap_fmt_txt, /*Function pointer to get glyph's bitmap*/
@@ -5589,5 +5589,5 @@ lv_font_t lv_font_ratdeck_12 = {
#endif /*#if LV_FONT_RATDECK_12*/
#endif /*#if LV_FONT_RSDECK_12*/
@@ -1,7 +1,7 @@
/*******************************************************************************
* Size: 14 px
* Bpp: 4
* Opts: --no-compress --no-prefilter --bpp 4 --size 14 --font .pio/libdeps/ratdeck_915/lvgl/scripts/built_in_font/Montserrat-Medium.ttf -r 0x20-0x7F,0xA0-0xFF,0x100-0x17F,0x400-0x4FF --format lvgl -o src/fonts/lv_font_ratdeck_14.c --force-fast-kern-format
* Opts: --no-compress --no-prefilter --bpp 4 --size 14 --font .pio/libdeps/rsdeck_915/lvgl/scripts/built_in_font/Montserrat-Medium.ttf -r 0x20-0x7F,0xA0-0xFF,0x100-0x17F,0x400-0x4FF --format lvgl -o src/fonts/lv_font_rsdeck_14.c --force-fast-kern-format
******************************************************************************/
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
@@ -10,11 +10,11 @@
#include <lvgl.h>
#endif
#ifndef LV_FONT_RATDECK_14
#define LV_FONT_RATDECK_14 1
#ifndef LV_FONT_RSDECK_14
#define LV_FONT_RSDECK_14 1
#endif
#if LV_FONT_RATDECK_14
#if LV_FONT_RSDECK_14
/*-----------------
* BITMAPS
@@ -6251,9 +6251,9 @@ static lv_font_fmt_txt_dsc_t font_dsc = {
/*Initialize a public general font descriptor*/
#if LVGL_VERSION_MAJOR >= 8
const lv_font_t lv_font_ratdeck_14 = {
const lv_font_t lv_font_rsdeck_14 = {
#else
lv_font_t lv_font_ratdeck_14 = {
lv_font_t lv_font_rsdeck_14 = {
#endif
.get_glyph_dsc = lv_font_get_glyph_dsc_fmt_txt, /*Function pointer to get glyph's data*/
.get_glyph_bitmap = lv_font_get_bitmap_fmt_txt, /*Function pointer to get glyph's bitmap*/
@@ -6275,5 +6275,5 @@ lv_font_t lv_font_ratdeck_14 = {
#endif /*#if LV_FONT_RATDECK_14*/
#endif /*#if LV_FONT_RSDECK_14*/
+19 -8
View File
@@ -1,5 +1,5 @@
// =============================================================================
// Ratdeck — Main Entry Point
// rsDeck — Main Entry Point
// LilyGo T-Deck Plus: LovyanGFX Direct UI + microReticulum + LXMF Messaging
// =============================================================================
@@ -411,7 +411,7 @@ void onHotkeyAutoIface() {
}
void onHotkeyDiag() {
Serial.println("=== DIAGNOSTIC DUMP ===");
Serial.printf("Device: Ratdeck T-Deck Plus\n");
Serial.printf("Device: rsDeck T-Deck Plus\n");
Serial.printf("Identity: %s\n", rns.identityHash().c_str());
Serial.printf("Transport: %s\n", rns.isTransportActive() ? "ACTIVE" : "OFFLINE");
Serial.printf("Paths: %d Links: %d\n", (int)rns.pathCount(), (int)rns.linkCount());
@@ -425,6 +425,17 @@ void onHotkeyDiag() {
radio.getTxPower());
Serial.printf("Regulator: %s\n", LORA_USE_DCDC_REGULATOR ? "DC-DC" : "LDO");
Serial.printf("Preamble: %ld symbols\n", radio.getPreambleLength());
Serial.printf("Bitrate: %lu bps LDRO: %s frame255: %.0f ms\n",
(unsigned long)radio.getBitrate(),
radio.lowDataRateEnabled() ? "ON" : "off",
radio.getAirtime(MAX_PACKET_SIZE));
if (auto* loraIf = rns.loraInterface()) {
Serial.printf("LoRaIF: bitrate=%lu bps split_timeout=%lu ms frame=%.0f ms airtime=%.2f%%\n",
(unsigned long)loraIf->bitrate(),
loraIf->splitRxTimeoutMs(),
loraIf->singleFrameAirtimeMs(),
loraIf->airtimeUtilization() * 100.0f);
}
Serial.printf("IQ invert: %s\n", radio.getInvertIQ() ? "ON" : "off");
Serial.printf("SyncWord regs: 0x%02X%02X\n",
radio.readRegister(REG_SYNC_WORD_MSB_6X),
@@ -517,7 +528,7 @@ void onHotkeyRssiMonitor() {
void onHotkeyRadioTest() {
Serial.println("[TEST] Sending raw test packet...");
uint8_t header = 0xA0;
const char* testPayload = "RATDECK_TEST_1234567890";
const char* testPayload = "RSDECK_TEST_1234567890";
radio.beginPacket();
radio.write(header);
radio.write((const uint8_t*)testPayload, strlen(testPayload));
@@ -659,7 +670,7 @@ static bool selectDiagnosticPeer(const char* explicitArg, RNS::Bytes& destHash,
}
static std::string makeDiagnosticLxmfPayload(size_t length) {
static constexpr char kPrefix[] = "RATDECK-LXMF-TEST:";
static constexpr char kPrefix[] = "RSDECK-LXMF-TEST:";
static constexpr char kPattern[] =
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
@@ -1055,7 +1066,7 @@ void setup() {
delay(100);
Serial.println();
Serial.println("=================================");
Serial.printf(" Ratdeck v%s\n", RATDECK_VERSION_STRING);
Serial.printf(" rsDeck v%s\n", RSDECK_VERSION_STRING);
Serial.println(" LilyGo T-Deck Plus");
Serial.println("=================================");
@@ -1129,7 +1140,7 @@ void setup() {
delay(10);
if (sdStore.begin(&sharedSPI, SD_CS)) {
sdHadExistingData = sdStore.hasExistingData();
sdStore.formatForRatdeck();
sdStore.formatForRsDeck();
Serial.println("[SD] Card ready");
} else {
Serial.println("[SD] Not detected");
@@ -1715,7 +1726,7 @@ void setup() {
if (wipe) {
Serial.println("[BOOT] User chose to wipe old data");
lvDataCleanScreen.showStatus("Clearing old data...");
sdStore.wipeRatdeck();
sdStore.wipeRsDeck();
if (announceManager) announceManager->clearAll();
Serial.println("[BOOT] Old data cleared");
lvDataCleanScreen.showStatus("Done! Rebooting...");
@@ -1843,7 +1854,7 @@ void setup() {
keyboard.backlightOn();
}
Serial.println("[BOOT] Ratdeck ready");
Serial.println("[BOOT] rsDeck ready");
Serial.printf("[BOOT] Summary: radio=%s flash=%s sd=%s\n",
radioOnline ? "ONLINE" : "OFFLINE",
flash.isReady() ? "OK" : "FAIL",
+34 -14
View File
@@ -770,7 +770,13 @@ void SX1262::implicitHeaderMode() {
}
void SX1262::handleLowDataRate() {
_ldro = long((1 << _sf) / (getSignalBandwidth() / 1000)) > 16;
uint32_t bw = getSignalBandwidth();
if (_sf == 0 || bw == 0) {
_ldro = false;
return;
}
float symbolTimeMs = 1000.0f * (float)(1UL << _sf) / (float)bw;
_ldro = symbolTimeMs > 16.0f;
}
void SX1262::standby() {
@@ -785,23 +791,37 @@ void SX1262::sleep() {
float SX1262::getAirtime(uint16_t written) {
if (!_radioOnline) return 0;
float symbolRate = (float)getSignalBandwidth() / (float)(1 << _sf);
uint32_t bw = getSignalBandwidth();
uint8_t crDen = getCodingRate4();
if (_sf == 0 || bw == 0 || crDen < 5 || crDen > 8) return 0;
float symbolRate = (float)bw / (float)(1UL << _sf);
float symbolTimeMs = 1000.0 / symbolRate;
float loraSymbols;
float payloadSymbols;
if (_sf >= 7) {
loraSymbols = (8.0 * written + PHY_CRC_LORA_BITS - 4.0 * _sf + 8 + PHY_HEADER_LORA_SYMBOLS);
loraSymbols /= 4.0 * (_sf - 2 * (_ldro ? 1 : 0));
if (loraSymbols < 0) loraSymbols = 0;
loraSymbols = ceil(loraSymbols);
loraSymbols += _preambleLength + 0.25 + 8;
payloadSymbols = (8.0 * written + PHY_CRC_LORA_BITS - 4.0 * _sf + 8 + PHY_HEADER_LORA_SYMBOLS);
payloadSymbols /= 4.0 * (_sf - 2 * (_ldro ? 1 : 0));
if (payloadSymbols < 0) payloadSymbols = 0;
payloadSymbols = ceil(payloadSymbols) * crDen;
payloadSymbols += _preambleLength + 0.25 + 8;
} else {
loraSymbols = (8.0 * written + PHY_CRC_LORA_BITS - 4.0 * _sf + PHY_HEADER_LORA_SYMBOLS);
loraSymbols /= 4.0 * _sf;
if (loraSymbols < 0) loraSymbols = 0;
loraSymbols = ceil(loraSymbols);
loraSymbols += _preambleLength + 2.25 + 8;
payloadSymbols = (8.0 * written + PHY_CRC_LORA_BITS - 4.0 * _sf + PHY_HEADER_LORA_SYMBOLS);
payloadSymbols /= 4.0 * _sf;
if (payloadSymbols < 0) payloadSymbols = 0;
payloadSymbols = ceil(payloadSymbols) * crDen;
payloadSymbols += _preambleLength + 2.25 + 8;
}
return loraSymbols * symbolTimeMs;
return payloadSymbols * symbolTimeMs;
}
uint32_t SX1262::getBitrate() {
uint32_t bw = getSignalBandwidth();
uint8_t crDen = getCodingRate4();
if (_sf == 0 || bw == 0 || crDen < 5 || crDen > 8) return 0;
float bitrate = (float)_sf * (4.0f / (float)crDen) * (float)bw / (float)(1UL << _sf);
if (bitrate < 1.0f) return 1;
return (uint32_t)bitrate;
}
void IRAM_ATTR SX1262::onDio0Rise() {
+2
View File
@@ -65,6 +65,8 @@ public:
uint8_t getPacketType();
uint16_t getIrqFlags();
float getAirtime(uint16_t written);
uint32_t getBitrate();
bool lowDataRateEnabled() const { return _ldro; }
// --- FIFO access ---
void readBuffer(uint8_t* buffer, size_t size);
+19 -4
View File
@@ -152,13 +152,14 @@ void AnnounceManager::received_announce(
auto& node = _nodes[it->second];
if (node.lastSeen != 0 && now >= node.lastSeen &&
now - node.lastSeen < ANNOUNCE_MIN_INTERVAL_MS) return;
if (!name.empty()) node.name = name;
// Saved contacts own their local alias. Incoming announce app_data is
// still cached below, but must not reset the user-chosen contact name.
if (!name.empty() && !node.saved) node.name = name;
if (!idHex.empty()) node.identityHex = idHex;
node.lastSeen = now;
// hops_to() is expensive (linear routing table scan) — only call for saved contacts
if (node.saved) node.hops = RNS::Transport::hops_to(destination_hash);
if (_loraIf) { node.rssi = _loraIf->lastRxRssi(); node.snr = _loraIf->lastRxSnr(); }
if (node.saved) _contactsDirty = true;
// Name cache update — skip expensive toHex() for unnamed re-announces
if (!name.empty()) {
std::string destHex = destination_hash.toHex();
@@ -227,7 +228,14 @@ void AnnounceManager::received_announce(
DiscoveredNode node;
node.hash = destination_hash;
node.name = name.empty() ? destHex.substr(0, 12) : name;
if (!name.empty()) {
node.name = name;
} else {
auto cached = _nameCache.find(destHex);
node.name = (cached != _nameCache.end() && !cached->second.empty())
? cached->second
: destHex.substr(0, 12);
}
node.identityHex = idHex;
node.lastSeen = millis();
// Skip hops_to() for new (unsaved) nodes — resolved when added as contact
@@ -296,7 +304,14 @@ void AnnounceManager::addManualContact(const std::string& hexHash, const std::st
DiscoveredNode node;
node.hash = hash;
node.name = safeName.empty() ? hexHash.substr(0, 12) : safeName;
if (!safeName.empty()) {
node.name = safeName;
} else {
auto cached = _nameCache.find(hexHash);
node.name = (cached != _nameCache.end() && !cached->second.empty())
? cached->second
: hexHash.substr(0, 12);
}
node.lastSeen = millis();
node.saved = true;
_hashIndex[key] = (int)_nodes.size();
+9 -9
View File
@@ -26,7 +26,7 @@ bool LXMFManager::begin(ReticulumManager* rns, MessageStore* store) {
}
std::vector<LXMFMessage> pending = _store->loadPendingOutgoing();
for (auto& msg : pending) {
if ((int)_outQueue.size() >= RATDECK_MAX_OUTQUEUE) break;
if ((int)_outQueue.size() >= RSDECK_MAX_OUTQUEUE) break;
msg.lastRetryMs = 0;
_outQueue.push_back(msg);
}
@@ -121,7 +121,7 @@ bool LXMFManager::sendMessage(const RNS::Bytes& destHash, const std::string& con
msg.incoming = false;
msg.status = LXMFStatus::QUEUED;
if ((int)_outQueue.size() >= RATDECK_MAX_OUTQUEUE) {
if ((int)_outQueue.size() >= RSDECK_MAX_OUTQUEUE) {
Serial.println("[LXMF] Outbound queue full; refusing new message");
return false;
}
@@ -131,11 +131,11 @@ bool LXMFManager::sendMessage(const RNS::Bytes& destHash, const std::string& con
Serial.println("[LXMF] Message pack failed");
return false;
}
if (payload.size() > RATDECK_LXMF_SINGLE_FRAME_MAX) {
if (payload.size() > RSDECK_LXMF_SINGLE_FRAME_MAX) {
msg.status = LXMFStatus::FAILED;
if (_store) _store->saveMessage(msg);
Serial.printf("[LXMF] Message too large for T-Deck safe path (%d > %d); resource transfer disabled\n",
(int)payload.size(), RATDECK_LXMF_SINGLE_FRAME_MAX);
(int)payload.size(), RSDECK_LXMF_SINGLE_FRAME_MAX);
return true;
}
if (preference == DeliveryPreference::Link) {
@@ -267,9 +267,9 @@ bool LXMFManager::sendDirect(LXMFMessage& msg) {
if (payload.empty()) { Serial.println("[LXMF] packFull returned empty!"); msg.status = LXMFStatus::FAILED; return true; }
const std::string msgIdHex = msg.messageId.toHex();
const bool requireLink = _linkRequiredIds.count(msgIdHex) > 0;
if (payload.size() > RATDECK_LXMF_SINGLE_FRAME_MAX) {
if (payload.size() > RSDECK_LXMF_SINGLE_FRAME_MAX) {
Serial.printf("[LXMF] Refusing resource-sized message (%d bytes); T-Deck safe cap is %d\n",
(int)payload.size(), RATDECK_LXMF_SINGLE_FRAME_MAX);
(int)payload.size(), RSDECK_LXMF_SINGLE_FRAME_MAX);
msg.status = LXMFStatus::FAILED;
return true;
}
@@ -338,7 +338,7 @@ bool LXMFManager::sendDirect(LXMFMessage& msg) {
// Larger packets require split-frame over LoRa, which is unreliable — any single
// frame loss (CRC error, collision, half-duplex timing) kills the entire transfer
// with no recovery. Link-based delivery handles retransmission at the protocol level.
if (payloadBytes.size() <= RATDECK_LXMF_SINGLE_FRAME_MAX) {
if (payloadBytes.size() <= RSDECK_LXMF_SINGLE_FRAME_MAX) {
// Fits in single LoRa frame — send opportunistic
Serial.printf("[LXMF] sending opportunistic: %d bytes to %s\n",
(int)payloadBytes.size(), outDest.hash().toHex().substr(0, 12).c_str());
@@ -348,7 +348,7 @@ bool LXMFManager::sendDirect(LXMFMessage& msg) {
} else {
// Too large for single frame — need link + resource transfer
Serial.printf("[LXMF] Message needs link delivery (%d bytes > %d single-frame), retry %d\n",
(int)payloadBytes.size(), RATDECK_LXMF_SINGLE_FRAME_MAX, msg.retries);
(int)payloadBytes.size(), RSDECK_LXMF_SINGLE_FRAME_MAX, msg.retries);
if (msg.retries % 3 == 0 && (!_outLink || _outLinkDestHash != msg.destHash
|| _outLink.status() != RNS::Type::Link::ACTIVE)) {
ensureOutboundLink(outDest, msg.destHash, "resource transfer");
@@ -563,7 +563,7 @@ void LXMFManager::handleProofTimeoutHash(const std::string& receiptHash) {
_pendingProofs.erase(it);
p.proofAttempts++;
bool retry = p.proofAttempts < 3 && (int)_instance->_outQueue.size() < RATDECK_MAX_OUTQUEUE;
bool retry = p.proofAttempts < 3 && (int)_instance->_outQueue.size() < RSDECK_MAX_OUTQUEUE;
LXMFStatus nextStatus = retry ? LXMFStatus::QUEUED : LXMFStatus::FAILED;
if (_instance->_store) {
+2 -2
View File
@@ -244,7 +244,7 @@ bool ReticulumManager::begin(SX1262* radio, FlashStore* flash, bool loraEnabled)
if (packet.context() == RNS::Type::Packet::PATH_RESPONSE) return true;
// Adaptive rate: tighter during first 60s boot flood, then normal
unsigned int maxRate = (now < 60000) ? 3 : RATDECK_MAX_ANNOUNCES_PER_SEC;
unsigned int maxRate = (now < 60000) ? 3 : RSDECK_MAX_ANNOUNCES_PER_SEC;
if (++count > maxRate) { ReticulumManager::_announceFilterCount++; return false; }
return true;
@@ -349,7 +349,7 @@ void ReticulumManager::loop() {
// Synchronous persist — one cycle per call to spread I/O across intervals.
// Runs on core 1 (main loop) to avoid data races with microReticulum's
// single-threaded transport state. Ratdeck is an endpoint, not a transport
// single-threaded transport state. rsDeck is an endpoint, not a transport
// node, so path tables are intentionally not persisted across boots.
void ReticulumManager::persistData() {
unsigned long start = millis();
+1 -1
View File
@@ -1,7 +1,7 @@
#include "FlashStore.h"
bool FlashStore::begin() {
// Standalone ratdeck labels this partition "littlefs"; bmorcelli/Launcher
// Legacy standalone builds label this partition "littlefs"; bmorcelli/Launcher
// labels the equivalent partition "spiffs". Try ours first, fall back.
const char* labels[] = { "littlefs", "spiffs" };
bool mounted = false;
+5 -5
View File
@@ -362,8 +362,8 @@ bool MessageStore::saveMessage(LXMFMessage& msg) {
if (isPendingStatus(msg.status) && s.pendingCount < UINT16_MAX) s.pendingCount++;
if (msg.status == LXMFStatus::FAILED && s.failedCount < UINT16_MAX) s.failedCount++;
}
int limit = sdOk ? RATDECK_MAX_MESSAGES_PER_CONV
: ((_externalStorageEnabled && _sd && _sd->isReady()) ? FLASH_MSG_CACHE_LIMIT : RATDECK_MAX_MESSAGES_PER_CONV);
int limit = sdOk ? RSDECK_MAX_MESSAGES_PER_CONV
: ((_externalStorageEnabled && _sd && _sd->isReady()) ? FLASH_MSG_CACHE_LIMIT : RSDECK_MAX_MESSAGES_PER_CONV);
if (s.totalCount > limit) {
rebuildSummary(peerHex);
}
@@ -965,7 +965,7 @@ void MessageStore::enforceFlashLimit(const std::string& peerHex) {
}
entry = d.openNextFile();
}
int limit = (_externalStorageEnabled && _sd && _sd->isReady()) ? FLASH_MSG_CACHE_LIMIT : RATDECK_MAX_MESSAGES_PER_CONV;
int limit = (_externalStorageEnabled && _sd && _sd->isReady()) ? FLASH_MSG_CACHE_LIMIT : RSDECK_MAX_MESSAGES_PER_CONV;
if ((int)files.size() <= limit) return;
std::sort(files.begin(), files.end());
int excess = files.size() - limit;
@@ -993,9 +993,9 @@ void MessageStore::enforceSDLimit(const std::string& peerHex) {
}
entry = d.openNextFile();
}
if ((int)files.size() <= RATDECK_MAX_MESSAGES_PER_CONV) return;
if ((int)files.size() <= RSDECK_MAX_MESSAGES_PER_CONV) return;
std::sort(files.begin(), files.end());
int excess = files.size() - RATDECK_MAX_MESSAGES_PER_CONV;
int excess = files.size() - RSDECK_MAX_MESSAGES_PER_CONV;
for (int i = 0; i < excess; i++) {
_sd->remove(files[i].c_str());
}
+5 -5
View File
@@ -176,9 +176,9 @@ String SDStore::readString(const char* path) {
return result;
}
bool SDStore::wipeRatdeck() {
bool SDStore::wipeRsDeck() {
if (!_ready) return false;
Serial.println("[SD] Wiping /ratdeck/ ...");
Serial.println("[SD] Wiping rsDeck legacy /ratdeck/ data ...");
wipeDir("/ratdeck/messages");
wipeDir("/ratdeck/contacts");
wipeDir("/ratdeck/identity");
@@ -186,7 +186,7 @@ bool SDStore::wipeRatdeck() {
wipeDir("/ratdeck/transport");
SD.rmdir("/ratdeck");
Serial.println("[SD] Wipe complete, recreating dirs...");
return formatForRatdeck();
return formatForRsDeck();
}
void SDStore::wipeDir(const char* path) {
@@ -221,9 +221,9 @@ bool SDStore::hasExistingData() {
return false;
}
bool SDStore::formatForRatdeck() {
bool SDStore::formatForRsDeck() {
if (!_ready) return false;
Serial.println("[SD] Creating Ratdeck directory structure...");
Serial.println("[SD] Creating rsDeck legacy /ratdeck/ directory structure...");
bool ok = true;
ok &= ensureDir("/ratdeck");
ok &= ensureDir("/ratdeck/config");
+2 -2
View File
@@ -25,8 +25,8 @@ public:
uint64_t totalBytes() const;
uint64_t usedBytes() const;
bool formatForRatdeck();
bool wipeRatdeck();
bool formatForRsDeck();
bool wipeRsDeck();
bool hasExistingData();
private:
+4 -4
View File
@@ -21,7 +21,7 @@ BLEInterface::~BLEInterface() {
bool BLEInterface::start() {
_framesMutex = xSemaphoreCreateMutex();
NimBLEDevice::init("Ratdeck");
NimBLEDevice::init("rsDeck");
NimBLEDevice::setMTU(512);
_pServer = NimBLEDevice::createServer();
@@ -29,13 +29,13 @@ bool BLEInterface::start() {
_pService = _pServer->createService(SERVICE_UUID);
// TX: Ratdeck -> remote (NOTIFY)
// TX: rsDeck -> remote (NOTIFY)
_pTxChar = _pService->createCharacteristic(
TX_CHAR_UUID,
NIMBLE_PROPERTY::NOTIFY
);
// RX: remote -> Ratdeck (WRITE)
// RX: remote -> rsDeck (WRITE)
_pRxChar = _pService->createCharacteristic(
RX_CHAR_UUID,
NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::WRITE_NR
@@ -47,7 +47,7 @@ bool BLEInterface::start() {
NimBLEAdvertising* pAdv = NimBLEDevice::getAdvertising();
pAdv->addServiceUUID(SERVICE_UUID);
pAdv->setName("Ratdeck");
pAdv->setName("rsDeck");
pAdv->start();
_active = true;
+1 -1
View File
@@ -79,7 +79,7 @@ private:
static constexpr uint8_t FRAME_ESC = 0x7D;
static constexpr uint8_t FRAME_XOR = 0x20;
// Custom UUIDs for Ratdeck BLE transport
// Custom UUIDs for rsDeck BLE transport
static constexpr const char* SERVICE_UUID = "e2f0a5b1-c3d4-4e56-8f90-1a2b3c4d5e6f";
static constexpr const char* TX_CHAR_UUID = "e2f0a5b2-c3d4-4e56-8f90-1a2b3c4d5e6f";
static constexpr const char* RX_CHAR_UUID = "e2f0a5b3-c3d4-4e56-8f90-1a2b3c4d5e6f";
+4 -4
View File
@@ -11,7 +11,7 @@ bool BLESideband::begin(NimBLEServer* existingServer) {
_pServer = existingServer;
_ownServer = false;
} else {
NimBLEDevice::init("Ratdeck");
NimBLEDevice::init("rsDeck");
_pServer = NimBLEDevice::createServer();
_ownServer = true;
}
@@ -19,13 +19,13 @@ bool BLESideband::begin(NimBLEServer* existingServer) {
// Create Nordic UART Service (don't set server callbacks — BLEInterface owns them)
_pService = _pServer->createService(NUS_SERVICE_UUID);
// TX: Ratdeck -> Sideband (NOTIFY)
// TX: rsDeck -> Sideband (NOTIFY)
_pTxChar = _pService->createCharacteristic(
NUS_TX_UUID,
NIMBLE_PROPERTY::NOTIFY
);
// RX: Sideband -> Ratdeck (WRITE)
// RX: Sideband -> rsDeck (WRITE)
_pRxChar = _pService->createCharacteristic(
NUS_RX_UUID,
NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::WRITE_NR
@@ -39,7 +39,7 @@ bool BLESideband::begin(NimBLEServer* existingServer) {
_pServer->start();
NimBLEAdvertising* pAdv = NimBLEDevice::getAdvertising();
pAdv->addServiceUUID(NUS_SERVICE_UUID);
pAdv->setName("Ratdeck");
pAdv->setName("rsDeck");
pAdv->start();
} else {
// Add NUS UUID to existing advertising
+54 -7
View File
@@ -1,6 +1,7 @@
#include "LoRaInterface.h"
#include "config/BoardConfig.h"
#include <algorithm>
#include <cmath>
// RNode on-air framing constants (from RNode_Firmware Framing.h / Config.h)
// Every LoRa packet has a 1-byte header: upper nibble = random sequence, lower nibble = flags
@@ -14,9 +15,9 @@ LoRaInterface::LoRaInterface(SX1262* radio, const char* name)
{
_IN = true;
_OUT = true;
_bitrate = 2000;
// Reticulum MTU (500 bytes) — split-packet framing allows up to 2x254 = 508 bytes
_HW_MTU = RNS::Type::Reticulum::MTU;
refreshRadioTiming(true);
}
LoRaInterface::~LoRaInterface() {
@@ -30,6 +31,7 @@ bool LoRaInterface::start() {
return false;
}
_online = true;
refreshRadioTiming(true);
_radio->receive();
Serial.println("[LORA_IF] Interface started (split-packet enabled, MTU=500)");
return true;
@@ -42,6 +44,7 @@ void LoRaInterface::stop() {
void LoRaInterface::send_outgoing(const RNS::Bytes& data) {
if (!_online || !_radio) return;
refreshRadioTiming();
// Reject packets exceeding Reticulum MTU (500 bytes)
if (data.size() > RNS::Type::Reticulum::MTU) {
@@ -73,6 +76,7 @@ void LoRaInterface::send_outgoing(const RNS::Bytes& data) {
}
void LoRaInterface::transmitNow(const RNS::Bytes& data) {
refreshRadioTiming();
uint8_t header = (uint8_t)(random(256)) & RNODE_NIBBLE_SEQ;
bool needsSplit = (data.size() > RNODE_SINGLE_MTU);
@@ -129,6 +133,7 @@ void LoRaInterface::transmitNow(const RNS::Bytes& data) {
void LoRaInterface::loop() {
if (!_online || !_radio) return;
refreshRadioTiming();
// Handle async TX completion
if (_txPending) {
@@ -170,8 +175,10 @@ void LoRaInterface::loop() {
}
// Split RX timeout: discard stale partial packets and drain deferred TX
if (_splitRxPending && (millis() - _splitRxTimestamp > SPLIT_RX_TIMEOUT_MS)) {
Serial.println("[LORA_IF] RX SPLIT timeout, discarding partial");
if (_splitRxPending && (millis() - _splitRxTimestamp > _splitRxTimeoutMs)) {
unsigned long age = millis() - _splitRxTimestamp;
Serial.printf("[LORA_IF] RX SPLIT timeout after %lums (limit=%lums frame=%.0fms), discarding partial\n",
age, _splitRxTimeoutMs, _singleFrameAirtimeMs);
_splitRxPending = false;
_splitRxBuffer = RNS::Bytes();
// Drain any TX that was deferred during split RX hold
@@ -226,14 +233,14 @@ void LoRaInterface::loop() {
_splitRxBuffer = RNS::Bytes(raw + RNODE_HEADER_L, payloadSize);
_splitRxTimestamp = millis();
Serial.printf("[LORA_IF] RX SPLIT frame 1: %d bytes (seq=0x%02X), RSSI=%d, SNR=%.1f\n",
payloadSize, seq, _lastRxRssi, _lastRxSnr);
Serial.printf("[LORA_IF] RX SPLIT frame 1: %d bytes (seq=0x%02X), RSSI=%d, SNR=%.1f, timeout=%lums\n",
payloadSize, seq, _lastRxRssi, _lastRxSnr, _splitRxTimeoutMs);
_radio->receive();
return;
} else if (seq == _splitRxSeq) {
// Second frame matches — reassemble
Serial.printf("[LORA_IF] RX SPLIT frame 2: %d bytes (seq=0x%02X), RSSI=%d, SNR=%.1f\n",
payloadSize, seq, _lastRxRssi, _lastRxSnr);
Serial.printf("[LORA_IF] RX SPLIT frame 2: %d bytes (seq=0x%02X), RSSI=%d, SNR=%.1f, age=%lums\n",
payloadSize, seq, _lastRxRssi, _lastRxSnr, millis() - _splitRxTimestamp);
_splitRxBuffer.append(raw + RNODE_HEADER_L, payloadSize);
int totalSize = _splitRxBuffer.size();
@@ -293,3 +300,43 @@ float LoRaInterface::airtimeUtilization() const {
float windowMs = std::min((float)elapsed, (float)AIRTIME_WINDOW_MS);
return _airtimeAccumMs / windowMs;
}
unsigned long LoRaInterface::computeSplitRxTimeoutMs(float frameAirtimeMs) const {
if (frameAirtimeMs <= 0) return SPLIT_RX_TIMEOUT_FLOOR_MS;
float raw = frameAirtimeMs * SPLIT_RX_TIMEOUT_MULT + SPLIT_RX_TIMEOUT_MARGIN_MS;
unsigned long rounded = (unsigned long)(ceil(raw / 500.0f) * 500.0f);
return std::min(SPLIT_RX_TIMEOUT_CEIL_MS,
std::max(SPLIT_RX_TIMEOUT_FLOOR_MS, rounded));
}
void LoRaInterface::refreshRadioTiming(bool forceLog) {
if (!_radio || !_radio->isRadioOnline()) {
if (_bitrate == 0) _bitrate = 1;
return;
}
unsigned long now = millis();
if (!forceLog && _lastTimingRefreshMs != 0 && (now - _lastTimingRefreshMs) < 1000) return;
_lastTimingRefreshMs = now;
uint32_t newBitrate = _radio->getBitrate();
if (newBitrate == 0) newBitrate = (_bitrate > 0) ? _bitrate : 1;
float newFrameAirtime = _radio->getAirtime(MAX_PACKET_SIZE);
unsigned long newTimeout = computeSplitRxTimeoutMs(newFrameAirtime);
bool changed = forceLog || newBitrate != _bitrate ||
newTimeout != _splitRxTimeoutMs ||
fabsf(newFrameAirtime - _singleFrameAirtimeMs) >= 1.0f;
_bitrate = newBitrate;
_singleFrameAirtimeMs = newFrameAirtime;
_splitRxTimeoutMs = newTimeout;
if (changed) {
Serial.printf("[LORA_IF] timing: bitrate=%lu bps frame=%.0fms split_timeout=%lums ldro=%s\n",
(unsigned long)_bitrate,
_singleFrameAirtimeMs,
_splitRxTimeoutMs,
_radio->lowDataRateEnabled() ? "on" : "off");
}
}
+12 -1
View File
@@ -23,12 +23,17 @@ public:
int lastRxRssi() const { return _lastRxRssi; }
float lastRxSnr() const { return _lastRxSnr; }
bool isOnline() const { return _online; }
unsigned long splitRxTimeoutMs() const { return _splitRxTimeoutMs; }
float singleFrameAirtimeMs() const { return _singleFrameAirtimeMs; }
uint32_t bitrate() const { return _bitrate; }
protected:
virtual void send_outgoing(const RNS::Bytes& data) override;
private:
void transmitNow(const RNS::Bytes& data);
void refreshRadioTiming(bool forceLog = false);
unsigned long computeSplitRxTimeoutMs(float frameAirtimeMs) const;
SX1262* _radio;
bool _txPending = false;
@@ -44,11 +49,17 @@ private:
uint8_t _splitTxHeader = 0;
// Split-packet RX state: reassemble two LoRa frames into one Reticulum packet
static constexpr unsigned long SPLIT_RX_TIMEOUT_MS = 5000;
static constexpr unsigned long SPLIT_RX_TIMEOUT_FLOOR_MS = 5000;
static constexpr unsigned long SPLIT_RX_TIMEOUT_CEIL_MS = 60000;
static constexpr unsigned long SPLIT_RX_TIMEOUT_MARGIN_MS = 2000;
static constexpr float SPLIT_RX_TIMEOUT_MULT = 1.5f;
bool _splitRxPending = false;
uint8_t _splitRxSeq = 0;
RNS::Bytes _splitRxBuffer;
unsigned long _splitRxTimestamp = 0;
unsigned long _splitRxTimeoutMs = SPLIT_RX_TIMEOUT_FLOOR_MS;
float _singleFrameAirtimeMs = 0;
unsigned long _lastTimingRefreshMs = 0;
int _lastRxRssi = 0;
float _lastRxSnr = 0;
+1 -1
View File
@@ -37,7 +37,7 @@ void WiFiInterface::startAP() {
if (_apSSID.isEmpty()) {
uint32_t chip = ESP.getEfuseMac() & 0xFFFF;
char ssid[32];
snprintf(ssid, sizeof(ssid), "ratdeck-%04x", chip);
snprintf(ssid, sizeof(ssid), "rsdeck-%04x", chip);
_apSSID = ssid;
}
+4 -4
View File
@@ -32,7 +32,7 @@ void LvStatusBar::create(lv_obj_t* parent) {
_lblTime = lv_label_create(_bar);
lv_obj_set_size(_lblTime, kTimeW, Theme::STATUS_BAR_H);
lv_label_set_long_mode(_lblTime, LV_LABEL_LONG_CLIP);
lv_obj_set_style_text_font(_lblTime, &lv_font_ratdeck_12, 0);
lv_obj_set_style_text_font(_lblTime, &lv_font_rsdeck_12, 0);
lv_obj_set_style_text_align(_lblTime, LV_TEXT_ALIGN_LEFT, 0);
lv_label_set_text(_lblTime, "--:--");
lv_obj_align(_lblTime, LV_ALIGN_LEFT_MID, 4, 0);
@@ -42,14 +42,14 @@ void LvStatusBar::create(lv_obj_t* parent) {
lv_obj_set_size(_lblLinks, kLinksW, Theme::STATUS_BAR_H);
lv_label_set_long_mode(_lblLinks, LV_LABEL_LONG_CLIP);
lv_label_set_recolor(_lblLinks, true);
lv_obj_set_style_text_font(_lblLinks, &lv_font_ratdeck_10, 0);
lv_obj_set_style_text_font(_lblLinks, &lv_font_rsdeck_10, 0);
lv_obj_set_style_text_align(_lblLinks, LV_TEXT_ALIGN_CENTER, 0);
lv_obj_align(_lblLinks, LV_ALIGN_LEFT_MID, kLinksX, 0);
// Right: battery percentage.
_lblBatt = lv_label_create(_bar);
lv_obj_set_size(_lblBatt, kBattW, Theme::STATUS_BAR_H);
lv_obj_set_style_text_font(_lblBatt, &lv_font_ratdeck_10, 0);
lv_obj_set_style_text_font(_lblBatt, &lv_font_rsdeck_10, 0);
lv_obj_set_style_text_align(_lblBatt, LV_TEXT_ALIGN_RIGHT, 0);
lv_label_set_long_mode(_lblBatt, LV_LABEL_LONG_CLIP);
lv_obj_align(_lblBatt, LV_ALIGN_RIGHT_MID, -4, 0);
@@ -66,7 +66,7 @@ void LvStatusBar::create(lv_obj_t* parent) {
_lblToast = lv_label_create(_toast);
lv_obj_set_width(_lblToast, Theme::SCREEN_W - 12);
lv_label_set_long_mode(_lblToast, LV_LABEL_LONG_DOT);
lv_obj_set_style_text_font(_lblToast, &lv_font_ratdeck_12, 0);
lv_obj_set_style_text_font(_lblToast, &lv_font_rsdeck_12, 0);
lv_obj_set_style_text_color(_lblToast, lv_color_hex(Theme::BG), 0);
lv_obj_set_style_text_align(_lblToast, LV_TEXT_ALIGN_CENTER, 0);
lv_obj_center(_lblToast);
+2 -2
View File
@@ -49,7 +49,7 @@ void LvTabBar::create(lv_obj_t* parent) {
_labels[i] = lv_label_create(_cells[i]);
lv_obj_set_size(_labels[i], Theme::TAB_W - 4, 14);
lv_label_set_long_mode(_labels[i], LV_LABEL_LONG_CLIP);
lv_obj_set_style_text_font(_labels[i], &lv_font_ratdeck_10, 0);
lv_obj_set_style_text_font(_labels[i], &lv_font_rsdeck_10, 0);
lv_obj_set_style_text_align(_labels[i], LV_TEXT_ALIGN_CENTER, 0);
lv_label_set_text(_labels[i], TAB_NAMES[i]);
lv_obj_align(_labels[i], LV_ALIGN_CENTER, 0, 2);
@@ -63,7 +63,7 @@ void LvTabBar::create(lv_obj_t* parent) {
_badgeLabels[i] = lv_label_create(_badges[i]);
lv_label_set_long_mode(_badgeLabels[i], LV_LABEL_LONG_CLIP);
lv_obj_set_style_text_font(_badgeLabels[i], &lv_font_ratdeck_10, 0);
lv_obj_set_style_text_font(_badgeLabels[i], &lv_font_rsdeck_10, 0);
lv_obj_set_style_text_align(_badgeLabels[i], LV_TEXT_ALIGN_CENTER, 0);
lv_obj_center(_badgeLabels[i]);
}
+14 -14
View File
@@ -120,23 +120,23 @@ void init(lv_disp_t* disp) {
// Screen background (LV_USE_THEME_DEFAULT is disabled in lv_conf.h).
lv_style_init(&s_screen);
lv_style_set_bg_opa(&s_screen, LV_OPA_COVER);
lv_style_set_text_font(&s_screen, &lv_font_ratdeck_14);
lv_style_set_text_font(&s_screen, &lv_font_rsdeck_14);
// Labels
lv_style_init(&s_label);
lv_style_set_text_font(&s_label, &lv_font_ratdeck_14);
lv_style_set_text_font(&s_label, &lv_font_rsdeck_14);
lv_style_init(&s_labelMuted);
lv_style_set_text_font(&s_labelMuted, &lv_font_ratdeck_12);
lv_style_set_text_font(&s_labelMuted, &lv_font_rsdeck_12);
lv_style_init(&s_labelAccent);
lv_style_set_text_font(&s_labelAccent, &lv_font_ratdeck_14);
lv_style_set_text_font(&s_labelAccent, &lv_font_rsdeck_14);
// Buttons
lv_style_init(&s_btn);
lv_style_set_bg_opa(&s_btn, LV_OPA_COVER);
lv_style_set_border_width(&s_btn, 1);
lv_style_set_text_font(&s_btn, &lv_font_ratdeck_12);
lv_style_set_text_font(&s_btn, &lv_font_rsdeck_12);
lv_style_set_radius(&s_btn, 3);
lv_style_set_pad_top(&s_btn, 5);
lv_style_set_pad_bottom(&s_btn, 5);
@@ -171,7 +171,7 @@ void init(lv_disp_t* disp) {
lv_style_init(&s_textarea);
lv_style_set_bg_opa(&s_textarea, LV_OPA_COVER);
lv_style_set_border_width(&s_textarea, 1);
lv_style_set_text_font(&s_textarea, &lv_font_ratdeck_14);
lv_style_set_text_font(&s_textarea, &lv_font_rsdeck_14);
lv_style_set_radius(&s_textarea, 3);
lv_style_set_pad_all(&s_textarea, 6);
@@ -189,7 +189,7 @@ void init(lv_disp_t* disp) {
// List items
lv_style_init(&s_listBtn);
lv_style_set_bg_opa(&s_listBtn, LV_OPA_COVER);
lv_style_set_text_font(&s_listBtn, &lv_font_ratdeck_12);
lv_style_set_text_font(&s_listBtn, &lv_font_rsdeck_12);
lv_style_set_border_width(&s_listBtn, 1);
lv_style_set_border_side(&s_listBtn, LV_BORDER_SIDE_BOTTOM);
lv_style_set_pad_top(&s_listBtn, 5);
@@ -208,7 +208,7 @@ void init(lv_disp_t* disp) {
lv_style_init(&s_dropdown);
lv_style_set_bg_opa(&s_dropdown, LV_OPA_COVER);
lv_style_set_border_width(&s_dropdown, 1);
lv_style_set_text_font(&s_dropdown, &lv_font_ratdeck_12);
lv_style_set_text_font(&s_dropdown, &lv_font_rsdeck_12);
lv_style_set_radius(&s_dropdown, 3);
lv_style_set_pad_all(&s_dropdown, 4);
@@ -220,7 +220,7 @@ void init(lv_disp_t* disp) {
// Section header (for list section dividers like "Contacts (3)")
lv_style_init(&s_sectionHeader);
lv_style_set_bg_opa(&s_sectionHeader, LV_OPA_TRANSP);
lv_style_set_text_font(&s_sectionHeader, &lv_font_ratdeck_10);
lv_style_set_text_font(&s_sectionHeader, &lv_font_rsdeck_10);
lv_style_set_text_letter_space(&s_sectionHeader, 0);
lv_style_set_border_width(&s_sectionHeader, 1);
lv_style_set_border_side(&s_sectionHeader, LV_BORDER_SIDE_BOTTOM);
@@ -249,7 +249,7 @@ void init(lv_disp_t* disp) {
// Roller - no border so selected row highlight extends edge-to-edge
lv_style_init(&s_roller);
lv_style_set_bg_opa(&s_roller, LV_OPA_COVER);
lv_style_set_text_font(&s_roller, &lv_font_ratdeck_14);
lv_style_set_text_font(&s_roller, &lv_font_rsdeck_14);
lv_style_set_border_width(&s_roller, 0);
// Persistent shell bars.
@@ -262,7 +262,7 @@ void init(lv_disp_t* disp) {
lv_style_init(&s_statusToast);
lv_style_set_bg_opa(&s_statusToast, LV_OPA_COVER);
lv_style_set_text_font(&s_statusToast, &lv_font_ratdeck_12);
lv_style_set_text_font(&s_statusToast, &lv_font_rsdeck_12);
lv_style_set_pad_all(&s_statusToast, 0);
lv_style_set_radius(&s_statusToast, 0);
@@ -277,7 +277,7 @@ void init(lv_disp_t* disp) {
lv_style_init(&s_tabCell);
lv_style_set_bg_opa(&s_tabCell, LV_OPA_COVER);
lv_style_set_border_width(&s_tabCell, 0);
lv_style_set_text_font(&s_tabCell, &lv_font_ratdeck_10);
lv_style_set_text_font(&s_tabCell, &lv_font_rsdeck_10);
lv_style_set_pad_all(&s_tabCell, 0);
lv_style_set_radius(&s_tabCell, 0);
@@ -288,7 +288,7 @@ void init(lv_disp_t* disp) {
lv_style_init(&s_badge);
lv_style_set_bg_opa(&s_badge, LV_OPA_COVER);
lv_style_set_text_font(&s_badge, &lv_font_ratdeck_10);
lv_style_set_text_font(&s_badge, &lv_font_rsdeck_10);
lv_style_set_radius(&s_badge, 3);
lv_style_set_pad_all(&s_badge, 0);
@@ -297,7 +297,7 @@ void init(lv_disp_t* disp) {
// Apply screen style to default theme
lv_obj_add_style(lv_scr_act(), &s_screen, 0);
Serial.println("[LVGL] Ratdeck field-console theme initialized");
Serial.println("[LVGL] rsDeck field-console theme initialized");
}
void refresh() {
+1 -1
View File
@@ -2,7 +2,7 @@
#include <lvgl.h>
// Ratdeck LVGL theme: compact field-console styles for LVGL 8.3.
// rsDeck LVGL theme: compact field-console styles for LVGL 8.3.
namespace LvTheme {
void init(lv_disp_t* disp);
+1 -1
View File
@@ -1,6 +1,6 @@
#include "Theme.h"
// Dark column is the original Ratdeck palette, verbatim. Light column is
// Dark column is the original rsDeck palette, verbatim. Light column is
// derived: same hue family, brand greens/cyan darkened for light-bg contrast.
#define THEME_COLORS(X) \
X(BG, 0x05080A, 0xF2F6F4) \
+1 -1
View File
@@ -3,7 +3,7 @@
#include <cstdint>
// =============================================================================
// Ratdeck design constants
// rsDeck design constants
// Field-console palette tuned for the 320x240 LVGL surface.
// Colors are runtime-switchable (Dark = original palette, Light = derived);
// the value tables live in Theme.cpp. Identifiers keep their original
+7 -7
View File
@@ -84,13 +84,13 @@ lv_obj_t* createEmptyState(lv_obj_t* parent) {
lv_obj_clear_flag(shoulders, LV_OBJ_FLAG_SCROLLABLE);
lv_obj_t* title = lv_label_create(box);
lv_obj_set_style_text_font(title, &lv_font_ratdeck_14, 0);
lv_obj_set_style_text_font(title, &lv_font_rsdeck_14, 0);
lv_obj_set_style_text_color(title, lv_color_hex(Theme::TEXT_SECONDARY), 0);
lv_label_set_text(title, "No trusted contacts");
lv_obj_align(title, LV_ALIGN_TOP_MID, 0, 49);
lv_obj_t* hint = lv_label_create(box);
lv_obj_set_style_text_font(hint, &lv_font_ratdeck_10, 0);
lv_obj_set_style_text_font(hint, &lv_font_rsdeck_10, 0);
lv_obj_set_style_text_color(hint, lv_color_hex(Theme::TEXT_MUTED), 0);
lv_label_set_text(hint, "Saved peers appear here");
lv_obj_align(hint, LV_ALIGN_TOP_MID, 0, 70);
@@ -194,13 +194,13 @@ void LvContactsScreen::rebuildList() {
}, LV_EVENT_FOCUSED, nullptr);
lv_obj_t* qrLbl = lv_label_create(qrRow);
lv_obj_set_style_text_font(qrLbl, &lv_font_ratdeck_14, 0);
lv_obj_set_style_text_font(qrLbl, &lv_font_rsdeck_14, 0);
lv_obj_set_style_text_color(qrLbl, lv_color_hex(Theme::ACCENT), 0);
lv_label_set_text(qrLbl, "Share My QR");
lv_obj_align(qrLbl, LV_ALIGN_LEFT_MID, 12, 0);
lv_obj_t* hintLbl = lv_label_create(qrRow);
lv_obj_set_style_text_font(hintLbl, &lv_font_ratdeck_10, 0);
lv_obj_set_style_text_font(hintLbl, &lv_font_rsdeck_10, 0);
lv_obj_set_style_text_color(hintLbl, lv_color_hex(Theme::TEXT_MUTED), 0);
lv_label_set_text(hintLbl, "Enter");
lv_obj_align(hintLbl, LV_ALIGN_RIGHT_MID, -12, 0);
@@ -247,7 +247,7 @@ void LvContactsScreen::rebuildList() {
LxmFaceAvatar::render(avatar.canvas, String(hashHex.c_str()));
lv_obj_t* nameLbl = lv_label_create(row);
lv_obj_set_style_text_font(nameLbl, &lv_font_ratdeck_14, 0);
lv_obj_set_style_text_font(nameLbl, &lv_font_rsdeck_14, 0);
lv_obj_set_style_text_color(nameLbl, lv_color_hex(Theme::ACCENT), 0);
lv_label_set_long_mode(nameLbl, LV_LABEL_LONG_CLIP);
lv_obj_set_width(nameLbl, Theme::CONTENT_W - kContactTextX - 72);
@@ -256,7 +256,7 @@ void LvContactsScreen::rebuildList() {
lv_obj_set_pos(nameLbl, kContactTextX, 2);
lv_obj_t* metaLbl = lv_label_create(row);
lv_obj_set_style_text_font(metaLbl, &lv_font_ratdeck_10, 0);
lv_obj_set_style_text_font(metaLbl, &lv_font_rsdeck_10, 0);
lv_obj_set_style_text_color(metaLbl, lv_color_hex(Theme::TEXT_SECONDARY), 0);
lv_obj_set_style_text_align(metaLbl, LV_TEXT_ALIGN_RIGHT, 0);
lv_label_set_long_mode(metaLbl, LV_LABEL_LONG_CLIP);
@@ -266,7 +266,7 @@ void LvContactsScreen::rebuildList() {
lv_obj_set_pos(metaLbl, Theme::CONTENT_W - 72, 5);
lv_obj_t* idLbl = lv_label_create(row);
lv_obj_set_style_text_font(idLbl, &lv_font_ratdeck_10, 0);
lv_obj_set_style_text_font(idLbl, &lv_font_rsdeck_10, 0);
lv_obj_set_style_text_color(idLbl, lv_color_hex(Theme::TEXT_MUTED), 0);
lv_label_set_long_mode(idLbl, LV_LABEL_LONG_CLIP);
lv_obj_set_width(idLbl, Theme::CONTENT_W - kContactTextX - 8);
+11 -11
View File
@@ -61,7 +61,7 @@ void LvDataCleanScreen::createUI(lv_obj_t* parent) {
_selectedYes = false;
_confirmWipe = false;
lv_obj_t* eyebrow = makeLabel(parent, "STORAGE CHECK", &lv_font_ratdeck_10,
lv_obj_t* eyebrow = makeLabel(parent, "STORAGE CHECK", &lv_font_rsdeck_10,
Theme::TEXT_SECONDARY, 220, LV_TEXT_ALIGN_CENTER,
LV_LABEL_LONG_DOT);
lv_obj_align(eyebrow, LV_ALIGN_TOP_MID, 0, 10);
@@ -72,17 +72,17 @@ void LvDataCleanScreen::createUI(lv_obj_t* parent) {
lv_obj_align(title, LV_ALIGN_TOP_MID, 0, 28);
lv_obj_t* msg = makeLabel(parent,
"Ratdeck found older data on the SD card.",
&lv_font_ratdeck_12, Theme::TEXT_PRIMARY, 268, LV_TEXT_ALIGN_CENTER);
"rsDeck found older data on the SD card.",
&lv_font_rsdeck_12, Theme::TEXT_PRIMARY, 268, LV_TEXT_ALIGN_CENTER);
lv_obj_align(msg, LV_ALIGN_TOP_MID, 0, 58);
lv_obj_t* prompt = makeLabel(parent,
"Keeping data is safest. Erase only for a clean setup.",
&lv_font_ratdeck_12, Theme::TEXT_SECONDARY, 276, LV_TEXT_ALIGN_CENTER);
&lv_font_rsdeck_12, Theme::TEXT_SECONDARY, 276, LV_TEXT_ALIGN_CENTER);
lv_obj_align(prompt, LV_ALIGN_TOP_MID, 0, 82);
_noBox = makeChoice(parent, 28, 122);
_noLabel = makeLabel(_noBox, "KEEP DATA", &lv_font_ratdeck_12,
_noLabel = makeLabel(_noBox, "KEEP DATA", &lv_font_rsdeck_12,
Theme::TEXT_PRIMARY, 112, LV_TEXT_ALIGN_CENTER,
LV_LABEL_LONG_DOT);
lv_obj_center(_noLabel);
@@ -96,7 +96,7 @@ void LvDataCleanScreen::createUI(lv_obj_t* parent) {
}, LV_EVENT_CLICKED, this);
_yesBox = makeChoice(parent, 166, 122);
_yesLabel = makeLabel(_yesBox, "ERASE", &lv_font_ratdeck_12,
_yesLabel = makeLabel(_yesBox, "ERASE", &lv_font_rsdeck_12,
Theme::TEXT_PRIMARY, 112, LV_TEXT_ALIGN_CENTER,
LV_LABEL_LONG_DOT);
lv_obj_center(_yesLabel);
@@ -112,26 +112,26 @@ void LvDataCleanScreen::createUI(lv_obj_t* parent) {
if (self->_doneCb) self->_doneCb(true);
}, LV_EVENT_CLICKED, this);
_confirmLabel = makeLabel(parent, "", &lv_font_ratdeck_12,
_confirmLabel = makeLabel(parent, "", &lv_font_rsdeck_12,
Theme::WARNING_CLR, 280, LV_TEXT_ALIGN_CENTER);
lv_obj_align(_confirmLabel, LV_ALIGN_TOP_MID, 0, 164);
_hintLabel = makeLabel(parent, "Left/Right choose Enter continues",
&lv_font_ratdeck_12, Theme::ACCENT,
&lv_font_rsdeck_12, Theme::ACCENT,
286, LV_TEXT_ALIGN_CENTER, LV_LABEL_LONG_DOT);
lv_obj_align(_hintLabel, LV_ALIGN_TOP_MID, 0, 188);
_statusLabel = makeLabel(parent, "", &lv_font_ratdeck_12,
_statusLabel = makeLabel(parent, "", &lv_font_rsdeck_12,
Theme::PRIMARY, 286, LV_TEXT_ALIGN_CENTER);
lv_obj_align(_statusLabel, LV_ALIGN_TOP_MID, 0, 140);
lv_obj_add_flag(_statusLabel, LV_OBJ_FLAG_HIDDEN);
updateSelection();
lv_obj_t* ver = makeLabel(parent, "", &lv_font_ratdeck_10,
lv_obj_t* ver = makeLabel(parent, "", &lv_font_rsdeck_10,
Theme::TEXT_MUTED, 120, LV_TEXT_ALIGN_CENTER,
LV_LABEL_LONG_DOT);
char verBuf[32];
snprintf(verBuf, sizeof(verBuf), "v%s", RATDECK_VERSION_STRING);
snprintf(verBuf, sizeof(verBuf), "v%s", RSDECK_VERSION_STRING);
lv_label_set_text(ver, verBuf);
lv_obj_align(ver, LV_ALIGN_BOTTOM_MID, 0, -10);
}
+5 -5
View File
@@ -34,8 +34,8 @@ lv_obj_t* makeRow(lv_obj_t* parent) {
void addHelpRow(lv_obj_t* parent, const char* keys, const char* action) {
lv_obj_t* row = makeRow(parent);
makeLabel(row, keys, &lv_font_ratdeck_10, Theme::ACCENT, 72, LV_TEXT_ALIGN_LEFT);
makeLabel(row, action, &lv_font_ratdeck_10, Theme::TEXT_PRIMARY, 178, LV_TEXT_ALIGN_LEFT);
makeLabel(row, keys, &lv_font_rsdeck_10, Theme::ACCENT, 72, LV_TEXT_ALIGN_LEFT);
makeLabel(row, action, &lv_font_rsdeck_10, Theme::TEXT_PRIMARY, 178, LV_TEXT_ALIGN_LEFT);
}
} // namespace
@@ -60,8 +60,8 @@ void LvHelpOverlay::create() {
lv_obj_t* header = makeRow(_overlay);
lv_obj_set_height(header, 16);
makeLabel(header, "HELP", &lv_font_ratdeck_12, Theme::ACCENT, 70, LV_TEXT_ALIGN_LEFT);
makeLabel(header, "Ratspeak.org", &lv_font_ratdeck_10,
makeLabel(header, "HELP", &lv_font_rsdeck_12, Theme::ACCENT, 70, LV_TEXT_ALIGN_LEFT);
makeLabel(header, "Ratspeak.org", &lv_font_rsdeck_10,
Theme::TEXT_SECONDARY, 180, LV_TEXT_ALIGN_RIGHT);
addHelpRow(_overlay, "Trackball", "Move selection");
@@ -75,7 +75,7 @@ void LvHelpOverlay::create() {
addHelpRow(_overlay, "Ctrl+D/I/T/R", "Diagnostics tools");
lv_obj_t* footer = makeLabel(_overlay, "Any key or tap closes",
&lv_font_ratdeck_10, Theme::TEXT_MUTED,
&lv_font_rsdeck_10, Theme::TEXT_MUTED,
260, LV_TEXT_ALIGN_CENTER);
lv_obj_set_style_pad_top(footer, 2, 0);
+12 -12
View File
@@ -60,7 +60,7 @@ lv_obj_t* makeLabel(lv_obj_t* parent, lv_coord_t x, lv_coord_t y, lv_coord_t w,
}
lv_obj_t* makeCaption(lv_obj_t* parent, const char* text) {
lv_obj_t* lbl = makeLabel(parent, 7, 4, 84, &lv_font_ratdeck_10,
lv_obj_t* lbl = makeLabel(parent, 7, 4, 84, &lv_font_rsdeck_10,
Theme::TEXT_MUTED, text);
lv_obj_set_style_text_letter_space(lbl, 1, 0);
return lbl;
@@ -71,7 +71,7 @@ lv_obj_t* makeChip(lv_obj_t* parent, lv_coord_t x, const char* title,
lv_obj_t* chip = makePanel(parent, x, kChipY, kCellW, kChipH,
Theme::BG_ELEVATED, Theme::BORDER);
makeCaption(chip, title);
*valueLabel = makeLabel(chip, 7, 18, 84, &lv_font_ratdeck_12,
*valueLabel = makeLabel(chip, 7, 18, 84, &lv_font_rsdeck_12,
Theme::TEXT_SECONDARY, "...");
return chip;
}
@@ -81,7 +81,7 @@ lv_obj_t* makeStat(lv_obj_t* parent, lv_coord_t x, const char* title,
lv_obj_t* stat = makePanel(parent, x, kStatY, kCellW, kStatH,
Theme::BG_ELEVATED, Theme::BORDER);
makeCaption(stat, title);
*valueLabel = makeLabel(stat, 7, 17, 84, &lv_font_ratdeck_14,
*valueLabel = makeLabel(stat, 7, 17, 84, &lv_font_rsdeck_14,
Theme::TEXT_PRIMARY, "0");
return stat;
}
@@ -172,23 +172,23 @@ void LvHomeScreen::createUI(lv_obj_t* parent) {
_avatarSeed = "";
_lblConsoleTitle = makeLabel(_identityPanel, 58, 6, 116,
&lv_font_ratdeck_10, Theme::ACCENT,
&lv_font_rsdeck_10, Theme::ACCENT,
"IDENTITY:");
lv_obj_set_style_text_letter_space(_lblConsoleTitle, 1, 0);
_lblStatus = makeLabel(_identityPanel, 184, 6, 114, &lv_font_ratdeck_10,
_lblStatus = makeLabel(_identityPanel, 184, 6, 114, &lv_font_rsdeck_10,
Theme::TEXT_SECONDARY, "OFFLINE",
LV_TEXT_ALIGN_RIGHT);
lv_obj_set_style_text_letter_space(_lblStatus, 1, 0);
_lblName = makeLabel(_identityPanel, 58, 21, 240, &lv_font_ratdeck_14,
_lblName = makeLabel(_identityPanel, 58, 21, 240, &lv_font_rsdeck_14,
Theme::TEXT_PRIMARY, "...");
lv_label_set_long_mode(_lblName, LV_LABEL_LONG_DOT);
_lblId = makeLabel(_identityPanel, 58, 41, 136, &lv_font_ratdeck_10,
_lblId = makeLabel(_identityPanel, 58, 41, 136, &lv_font_rsdeck_10,
Theme::TEXT_SECONDARY, "LXMF ----");
_lblIdentity = makeLabel(_identityPanel, 198, 41, 100,
&lv_font_ratdeck_10, Theme::TEXT_MUTED,
&lv_font_rsdeck_10, Theme::TEXT_MUTED,
"ID ----", LV_TEXT_ALIGN_RIGHT);
_chipLora = makeChip(parent, kPad, "LORA", &_lblLoraState);
@@ -226,10 +226,10 @@ void LvHomeScreen::createUI(lv_obj_t* parent) {
lv_obj_t* footer = makePanel(parent, kPad, kFooterY, 198, kFooterH,
Theme::BG_ELEVATED, Theme::BORDER);
_lblSummary = makeLabel(footer, 8, 6, 182, &lv_font_ratdeck_12,
_lblSummary = makeLabel(footer, 8, 6, 182, &lv_font_rsdeck_12,
Theme::TEXT_SECONDARY, "Waiting for transport");
lv_label_set_long_mode(_lblSummary, LV_LABEL_LONG_DOT);
_lblLastAnnounce = makeLabel(footer, 8, 23, 182, &lv_font_ratdeck_10,
_lblLastAnnounce = makeLabel(footer, 8, 23, 182, &lv_font_rsdeck_10,
Theme::TEXT_MUTED, "Announced: never");
lv_label_set_long_mode(_lblLastAnnounce, LV_LABEL_LONG_CLIP);
@@ -246,7 +246,7 @@ void LvHomeScreen::createUI(lv_obj_t* parent) {
lv_obj_set_style_pad_all(_btnAnnounce, 0, 0);
_lblAnnounceAction = lv_label_create(_btnAnnounce);
lv_obj_set_style_text_font(_lblAnnounceAction, &lv_font_ratdeck_12, 0);
lv_obj_set_style_text_font(_lblAnnounceAction, &lv_font_rsdeck_12, 0);
lv_obj_set_style_text_color(_lblAnnounceAction, lv_color_hex(Theme::ACCENT), 0);
lv_label_set_text(_lblAnnounceAction, "ANNOUNCE");
lv_obj_center(_lblAnnounceAction);
@@ -291,7 +291,7 @@ void LvHomeScreen::refreshUI() {
String dh = _rns->destinationHashHex();
displayName = "Ratspeak.org-" + dh.substring(0, 3);
} else {
displayName = "Ratdeck";
displayName = "rsDeck";
}
lv_label_set_text(_lblName, displayName.c_str());
+1 -1
View File
@@ -7,7 +7,7 @@ void LvMapScreen::createUI(lv_obj_t* parent) {
lv_obj_clear_flag(parent, LV_OBJ_FLAG_SCROLLABLE);
lv_obj_t* lbl = lv_label_create(parent);
lv_obj_set_style_text_font(lbl, &lv_font_ratdeck_14, 0);
lv_obj_set_style_text_font(lbl, &lv_font_rsdeck_14, 0);
lv_obj_set_style_text_color(lbl, lv_color_hex(Theme::TEXT_MUTED), 0);
lv_label_set_text(lbl, "Map\n\nComing soon\n\nNode topology view\nwill appear here");
lv_obj_set_style_text_align(lbl, LV_TEXT_ALIGN_CENTER, 0);
+13 -13
View File
@@ -155,7 +155,7 @@ void LvMessageView::createUI(lv_obj_t* parent) {
lv_obj_set_flex_flow(parent, LV_FLEX_FLOW_COLUMN);
lv_obj_set_style_pad_row(parent, 0, 0);
const lv_font_t* font = &lv_font_ratdeck_12;
const lv_font_t* font = &lv_font_rsdeck_12;
// Header bar (top)
_header = lv_obj_create(parent);
@@ -170,27 +170,27 @@ void LvMessageView::createUI(lv_obj_t* parent) {
lv_obj_clear_flag(_header, LV_OBJ_FLAG_SCROLLABLE);
lv_obj_t* backLbl = lv_label_create(_header);
lv_obj_set_style_text_font(backLbl, &lv_font_ratdeck_14, 0);
lv_obj_set_style_text_font(backLbl, &lv_font_rsdeck_14, 0);
lv_obj_set_style_text_color(backLbl, lv_color_hex(Theme::PRIMARY), 0);
lv_label_set_text(backLbl, "<");
lv_obj_align(backLbl, LV_ALIGN_LEFT_MID, 6, 0);
_lblHeader = lv_label_create(_header);
lv_obj_set_style_text_font(_lblHeader, &lv_font_ratdeck_14, 0);
lv_obj_set_style_text_font(_lblHeader, &lv_font_rsdeck_14, 0);
lv_obj_set_style_text_color(_lblHeader, lv_color_hex(Theme::ACCENT), 0);
lv_label_set_long_mode(_lblHeader, LV_LABEL_LONG_DOT);
lv_obj_set_width(_lblHeader, 188);
lv_obj_set_pos(_lblHeader, 22, 3);
_lblHeaderMeta = lv_label_create(_header);
lv_obj_set_style_text_font(_lblHeaderMeta, &lv_font_ratdeck_10, 0);
lv_obj_set_style_text_font(_lblHeaderMeta, &lv_font_rsdeck_10, 0);
lv_obj_set_style_text_color(_lblHeaderMeta, lv_color_hex(Theme::TEXT_SECONDARY), 0);
lv_label_set_long_mode(_lblHeaderMeta, LV_LABEL_LONG_DOT);
lv_obj_set_width(_lblHeaderMeta, Theme::CONTENT_W - 30);
lv_obj_set_pos(_lblHeaderMeta, 22, 21);
_lblHeaderState = lv_label_create(_header);
lv_obj_set_style_text_font(_lblHeaderState, &lv_font_ratdeck_10, 0);
lv_obj_set_style_text_font(_lblHeaderState, &lv_font_rsdeck_10, 0);
lv_obj_set_style_text_color(_lblHeaderState, lv_color_hex(Theme::TEXT_MUTED), 0);
lv_label_set_text(_lblHeaderState, "UNKNOWN");
lv_obj_align(_lblHeaderState, LV_ALIGN_TOP_RIGHT, -8, 8);
@@ -255,7 +255,7 @@ void LvMessageView::createUI(lv_obj_t* parent) {
lv_obj_add_style(_btnSend, LvTheme::styleBtn(), 0);
lv_obj_set_style_pad_all(_btnSend, 0, 0);
lv_obj_t* sendLbl = lv_label_create(_btnSend);
lv_obj_set_style_text_font(sendLbl, &lv_font_ratdeck_10, 0);
lv_obj_set_style_text_font(sendLbl, &lv_font_rsdeck_10, 0);
lv_obj_set_style_text_color(sendLbl, lv_color_hex(Theme::PRIMARY), 0);
lv_label_set_text(sendLbl, "SEND");
lv_obj_center(sendLbl);
@@ -384,7 +384,7 @@ void LvMessageView::refreshUI() {
void LvMessageView::appendMessage(const LXMFMessage& msg) {
if (!_msgScroll) return;
const lv_font_t* font = &lv_font_ratdeck_12;
const lv_font_t* font = &lv_font_rsdeck_12;
int textW = textWidthForBubble(msg.content);
if (!msg.incoming && textW < 96) textW = 96;
int boxW = textW + 16;
@@ -455,7 +455,7 @@ void LvMessageView::appendMessage(const LXMFMessage& msg) {
if (hasTime) {
lv_obj_t* timeLbl = lv_label_create(meta);
lv_obj_set_style_text_font(timeLbl, &lv_font_ratdeck_10, 0);
lv_obj_set_style_text_font(timeLbl, &lv_font_rsdeck_10, 0);
lv_obj_set_style_text_color(timeLbl, lv_color_hex(Theme::TEXT_MUTED), 0);
lv_label_set_text(timeLbl, timeBuf);
lv_obj_align(timeLbl, LV_ALIGN_LEFT_MID, 0, 0);
@@ -463,7 +463,7 @@ void LvMessageView::appendMessage(const LXMFMessage& msg) {
if (!msg.incoming) {
statusLbl = lv_label_create(meta);
lv_obj_set_style_text_font(statusLbl, &lv_font_ratdeck_10, 0);
lv_obj_set_style_text_font(statusLbl, &lv_font_rsdeck_10, 0);
applyStatusGlyph(statusLbl, msg.status);
lv_obj_align(statusLbl, LV_ALIGN_RIGHT_MID, 0, 0);
}
@@ -519,13 +519,13 @@ void LvMessageView::rebuildMessages() {
lv_obj_align(icon, LV_ALIGN_TOP_MID, 0, 13);
lv_obj_t* title = lv_label_create(empty);
lv_obj_set_style_text_font(title, &lv_font_ratdeck_14, 0);
lv_obj_set_style_text_font(title, &lv_font_rsdeck_14, 0);
lv_obj_set_style_text_color(title, lv_color_hex(Theme::TEXT_PRIMARY), 0);
lv_label_set_text(title, "No messages yet");
lv_obj_align(title, LV_ALIGN_TOP_MID, 0, 32);
lv_obj_t* sub = lv_label_create(empty);
lv_obj_set_style_text_font(sub, &lv_font_ratdeck_12, 0);
lv_obj_set_style_text_font(sub, &lv_font_rsdeck_12, 0);
lv_obj_set_style_text_color(sub, lv_color_hex(Theme::TEXT_SECONDARY), 0);
lv_label_set_text(sub, "Thread is quiet");
lv_obj_align(sub, LV_ALIGN_TOP_MID, 0, 54);
@@ -724,7 +724,7 @@ void LvMessageView::showSendModeMenu() {
lv_obj_clear_flag(_sendOverlay, LV_OBJ_FLAG_SCROLLABLE);
lv_obj_t* title = lv_label_create(_sendOverlay);
lv_obj_set_style_text_font(title, &lv_font_ratdeck_12, 0);
lv_obj_set_style_text_font(title, &lv_font_rsdeck_12, 0);
lv_obj_set_style_text_color(title, lv_color_hex(Theme::ACCENT), 0);
lv_label_set_text(title, "Send mode");
lv_obj_align(title, LV_ALIGN_TOP_MID, 0, 0);
@@ -748,7 +748,7 @@ void LvMessageView::showSendModeMenu() {
}, LV_EVENT_CLICKED, this);
_sendLabels[i] = lv_label_create(row);
lv_obj_set_style_text_font(_sendLabels[i], &lv_font_ratdeck_12, 0);
lv_obj_set_style_text_font(_sendLabels[i], &lv_font_rsdeck_12, 0);
lv_label_set_text(_sendLabels[i], labels[i]);
lv_obj_center(_sendLabels[i]);
_sendRows[i] = row;
+8 -8
View File
@@ -121,13 +121,13 @@ void LvMessagesScreen::createUI(lv_obj_t* parent) {
lv_obj_align(emptyIcon, LV_ALIGN_TOP_MID, 0, 15);
lv_obj_t* emptyTitle = lv_label_create(_lblEmpty);
lv_obj_set_style_text_font(emptyTitle, &lv_font_ratdeck_14, 0);
lv_obj_set_style_text_font(emptyTitle, &lv_font_rsdeck_14, 0);
lv_obj_set_style_text_color(emptyTitle, lv_color_hex(Theme::TEXT_PRIMARY), 0);
lv_label_set_text(emptyTitle, "No conversations");
lv_obj_align(emptyTitle, LV_ALIGN_TOP_MID, 0, 34);
lv_obj_t* emptySub = lv_label_create(_lblEmpty);
lv_obj_set_style_text_font(emptySub, &lv_font_ratdeck_12, 0);
lv_obj_set_style_text_font(emptySub, &lv_font_rsdeck_12, 0);
lv_obj_set_style_text_color(emptySub, lv_color_hex(Theme::TEXT_SECONDARY), 0);
lv_label_set_text(emptySub, "LXMF inbox is clear");
lv_obj_align(emptySub, LV_ALIGN_TOP_MID, 0, 56);
@@ -241,8 +241,8 @@ void LvMessagesScreen::rebuildList() {
for (auto& ci : _sortedConvs) _sortedPeers.push_back(ci.peerHex);
// Build list items with focus group support
const lv_font_t* nameFont = &lv_font_ratdeck_14;
const lv_font_t* smallFont = &lv_font_ratdeck_12;
const lv_font_t* nameFont = &lv_font_rsdeck_14;
const lv_font_t* smallFont = &lv_font_rsdeck_12;
for (int i = 0; i < count; i++) {
const auto& ci = _sortedConvs[i];
@@ -319,7 +319,7 @@ void LvMessagesScreen::rebuildList() {
char timeBuf[8];
if (formatClock(ci.lastTs, timeBuf, sizeof(timeBuf))) {
lv_obj_t* timeLbl = lv_label_create(row);
lv_obj_set_style_text_font(timeLbl, &lv_font_ratdeck_10, 0);
lv_obj_set_style_text_font(timeLbl, &lv_font_rsdeck_10, 0);
lv_obj_set_style_text_color(timeLbl, lv_color_hex(ci.hasUnread ? Theme::PRIMARY : Theme::TEXT_MUTED), 0);
lv_label_set_text(timeLbl, timeBuf);
lv_obj_align(timeLbl, LV_ALIGN_TOP_RIGHT, -8, 7);
@@ -370,7 +370,7 @@ void LvMessagesScreen::rebuildList() {
lv_obj_clear_flag(chip, LV_OBJ_FLAG_SCROLLABLE);
lv_obj_t* chipLbl = lv_label_create(chip);
lv_obj_set_style_text_font(chipLbl, &lv_font_ratdeck_10, 0);
lv_obj_set_style_text_font(chipLbl, &lv_font_rsdeck_10, 0);
lv_obj_set_style_text_color(chipLbl, lv_color_hex(chipColor), 0);
lv_label_set_text(chipLbl, chipBuf);
lv_obj_center(chipLbl);
@@ -430,7 +430,7 @@ void LvMessagesScreen::rebuildActionOverlay(const char* title, const char* const
lv_obj_clear_flag(_actionOverlay, LV_OBJ_FLAG_SCROLLABLE);
lv_obj_t* titleLbl = lv_label_create(_actionOverlay);
lv_obj_set_style_text_font(titleLbl, &lv_font_ratdeck_12, 0);
lv_obj_set_style_text_font(titleLbl, &lv_font_rsdeck_12, 0);
lv_obj_set_style_text_color(titleLbl, lv_color_hex(Theme::ACCENT), 0);
lv_label_set_long_mode(titleLbl, LV_LABEL_LONG_DOT);
lv_obj_set_width(titleLbl, 220);
@@ -458,7 +458,7 @@ void LvMessagesScreen::rebuildActionOverlay(const char* title, const char* const
}, LV_EVENT_CLICKED, this);
lv_obj_t* lbl = lv_label_create(row);
lv_obj_set_style_text_font(lbl, &lv_font_ratdeck_12, 0);
lv_obj_set_style_text_font(lbl, &lv_font_rsdeck_12, 0);
lv_obj_set_style_text_color(lbl, lv_color_hex(Theme::TEXT_PRIMARY), 0);
lv_label_set_long_mode(lbl, LV_LABEL_LONG_DOT);
lv_obj_set_width(lbl, 200);
+8 -8
View File
@@ -46,7 +46,7 @@ lv_obj_t* makeActionButton(lv_obj_t* parent, const char* text, lv_coord_t y) {
lv_obj_set_style_pad_all(btn, 0, 0);
lv_obj_t* lbl = lv_label_create(btn);
lv_obj_set_style_text_font(lbl, &lv_font_ratdeck_12, 0);
lv_obj_set_style_text_font(lbl, &lv_font_rsdeck_12, 0);
lv_obj_set_style_text_color(lbl, lv_color_hex(Theme::ACCENT), 0);
lv_label_set_long_mode(lbl, LV_LABEL_LONG_DOT);
lv_obj_set_width(lbl, 150);
@@ -66,7 +66,7 @@ void LvNameInputScreen::createUI(lv_obj_t* parent) {
lv_obj_set_style_bg_color(parent, lv_color_hex(Theme::BG), 0);
lv_obj_set_style_bg_opa(parent, LV_OPA_COVER, 0);
lv_obj_t* eyebrow = makeLabel(parent, "FIRST BOOT", &lv_font_ratdeck_10,
lv_obj_t* eyebrow = makeLabel(parent, "FIRST BOOT", &lv_font_rsdeck_10,
Theme::TEXT_SECONDARY, 220, LV_TEXT_ALIGN_CENTER,
LV_LABEL_LONG_DOT);
lv_obj_align(eyebrow, LV_ALIGN_TOP_MID, 0, 13);
@@ -79,7 +79,7 @@ void LvNameInputScreen::createUI(lv_obj_t* parent) {
lv_obj_t* prompt = makeLabel(parent,
"Choose the name other operators see on announces.",
&lv_font_ratdeck_12, Theme::TEXT_PRIMARY, 250, LV_TEXT_ALIGN_CENTER);
&lv_font_rsdeck_12, Theme::TEXT_PRIMARY, 250, LV_TEXT_ALIGN_CENTER);
lv_obj_align(prompt, LV_ALIGN_TOP_MID, 0, 70);
_textarea = lv_textarea_create(parent);
@@ -90,13 +90,13 @@ void LvNameInputScreen::createUI(lv_obj_t* parent) {
lv_textarea_set_placeholder_text(_textarea, "Optional");
lv_obj_add_style(_textarea, LvTheme::styleTextarea(), 0);
lv_obj_add_style(_textarea, LvTheme::styleTextareaFocused(), LV_STATE_FOCUSED);
lv_obj_set_style_text_font(_textarea, &lv_font_ratdeck_14, 0);
lv_obj_set_style_text_font(_textarea, &lv_font_rsdeck_14, 0);
lv_group_add_obj(LvInput::group(), _textarea);
lv_group_focus_obj(_textarea);
lv_obj_t* note = makeLabel(parent,
"Leave blank to generate a Ratdeck name from this identity.",
&lv_font_ratdeck_12, Theme::TEXT_SECONDARY, 260, LV_TEXT_ALIGN_CENTER);
"Leave blank to generate a rsDeck name from this identity.",
&lv_font_rsdeck_12, Theme::TEXT_SECONDARY, 260, LV_TEXT_ALIGN_CENTER);
lv_obj_align(note, LV_ALIGN_TOP_MID, 0, 154);
_doneButton = makeActionButton(parent, "DONE", 184);
@@ -106,11 +106,11 @@ void LvNameInputScreen::createUI(lv_obj_t* parent) {
self->submit(false);
}, LV_EVENT_CLICKED, this);
lv_obj_t* ver = makeLabel(parent, "", &lv_font_ratdeck_10,
lv_obj_t* ver = makeLabel(parent, "", &lv_font_rsdeck_10,
Theme::TEXT_MUTED, 120, LV_TEXT_ALIGN_CENTER,
LV_LABEL_LONG_DOT);
char verBuf[32];
snprintf(verBuf, sizeof(verBuf), "v%s", RATDECK_VERSION_STRING);
snprintf(verBuf, sizeof(verBuf), "v%s", RSDECK_VERSION_STRING);
lv_label_set_text(ver, verBuf);
lv_obj_align(ver, LV_ALIGN_BOTTOM_MID, 0, -10);
}
+13 -13
View File
@@ -80,13 +80,13 @@ lv_obj_t* createEmptyState(lv_obj_t* parent) {
}
lv_obj_t* title = lv_label_create(box);
lv_obj_set_style_text_font(title, &lv_font_ratdeck_14, 0);
lv_obj_set_style_text_font(title, &lv_font_rsdeck_14, 0);
lv_obj_set_style_text_color(title, lv_color_hex(Theme::TEXT_SECONDARY), 0);
lv_label_set_text(title, "No peers heard");
lv_obj_align(title, LV_ALIGN_TOP_MID, 0, 34);
lv_obj_t* hint = lv_label_create(box);
lv_obj_set_style_text_font(hint, &lv_font_ratdeck_10, 0);
lv_obj_set_style_text_font(hint, &lv_font_rsdeck_10, 0);
lv_obj_set_style_text_color(hint, lv_color_hex(Theme::TEXT_MUTED), 0);
lv_label_set_text(hint, "Listening for announces");
lv_obj_align(hint, LV_ALIGN_TOP_MID, 0, 55);
@@ -122,21 +122,21 @@ void LvNodesScreen::createUI(lv_obj_t* parent) {
lv_obj_add_flag(_overlay, LV_OBJ_FLAG_HIDDEN);
_overlayTitle = lv_label_create(_overlay);
lv_obj_set_style_text_font(_overlayTitle, &lv_font_ratdeck_14, 0);
lv_obj_set_style_text_font(_overlayTitle, &lv_font_rsdeck_14, 0);
lv_obj_set_style_text_color(_overlayTitle, lv_color_hex(Theme::ACCENT), 0);
lv_label_set_long_mode(_overlayTitle, LV_LABEL_LONG_CLIP);
lv_obj_set_width(_overlayTitle, 236);
lv_obj_set_pos(_overlayTitle, 12, 9);
_overlayMeta = lv_label_create(_overlay);
lv_obj_set_style_text_font(_overlayMeta, &lv_font_ratdeck_10, 0);
lv_obj_set_style_text_font(_overlayMeta, &lv_font_rsdeck_10, 0);
lv_obj_set_style_text_color(_overlayMeta, lv_color_hex(Theme::TEXT_MUTED), 0);
lv_label_set_long_mode(_overlayMeta, LV_LABEL_LONG_CLIP);
lv_obj_set_width(_overlayMeta, 236);
lv_obj_set_pos(_overlayMeta, 12, 29);
_overlayReach = lv_label_create(_overlay);
lv_obj_set_style_text_font(_overlayReach, &lv_font_ratdeck_10, 0);
lv_obj_set_style_text_font(_overlayReach, &lv_font_rsdeck_10, 0);
lv_obj_set_style_text_color(_overlayReach, lv_color_hex(Theme::TEXT_SECONDARY), 0);
lv_label_set_long_mode(_overlayReach, LV_LABEL_LONG_CLIP);
lv_obj_set_width(_overlayReach, 236);
@@ -166,7 +166,7 @@ void LvNodesScreen::createUI(lv_obj_t* parent) {
}, LV_EVENT_CLICKED, this);
_menuLabels[i] = lv_label_create(btn);
lv_obj_set_style_text_font(_menuLabels[i], &lv_font_ratdeck_14, 0);
lv_obj_set_style_text_font(_menuLabels[i], &lv_font_rsdeck_14, 0);
lv_obj_set_style_text_color(_menuLabels[i], lv_color_hex(Theme::PRIMARY), 0);
lv_label_set_text(_menuLabels[i], menuText[i]);
lv_obj_center(_menuLabels[i]);
@@ -185,13 +185,13 @@ void LvNodesScreen::createUI(lv_obj_t* parent) {
lv_obj_add_flag(_nicknameBox, LV_OBJ_FLAG_HIDDEN);
lv_obj_t* nickTitle = lv_label_create(_nicknameBox);
lv_obj_set_style_text_font(nickTitle, &lv_font_ratdeck_10, 0);
lv_obj_set_style_text_font(nickTitle, &lv_font_rsdeck_10, 0);
lv_obj_set_style_text_color(nickTitle, lv_color_hex(Theme::TEXT_SECONDARY), 0);
lv_label_set_text(nickTitle, "Contact name");
lv_obj_set_pos(nickTitle, 0, 0);
_nicknameLbl = lv_label_create(_nicknameBox);
lv_obj_set_style_text_font(_nicknameLbl, &lv_font_ratdeck_14, 0);
lv_obj_set_style_text_font(_nicknameLbl, &lv_font_rsdeck_14, 0);
lv_obj_set_style_text_color(_nicknameLbl, lv_color_hex(Theme::PRIMARY), 0);
lv_label_set_long_mode(_nicknameLbl, LV_LABEL_LONG_CLIP);
lv_obj_set_width(_nicknameLbl, 232);
@@ -199,7 +199,7 @@ void LvNodesScreen::createUI(lv_obj_t* parent) {
lv_obj_set_pos(_nicknameLbl, 0, 22);
_nicknameHint = lv_label_create(_nicknameBox);
lv_obj_set_style_text_font(_nicknameHint, &lv_font_ratdeck_10, 0);
lv_obj_set_style_text_font(_nicknameHint, &lv_font_rsdeck_10, 0);
lv_obj_set_style_text_color(_nicknameHint, lv_color_hex(Theme::TEXT_MUTED), 0);
lv_label_set_text(_nicknameHint, "Enter saves / Esc keeps");
lv_obj_set_pos(_nicknameHint, 0, 52);
@@ -291,7 +291,7 @@ void LvNodesScreen::rebuildList() {
lv_obj_set_style_pad_all(hdr, 0, 0);
lv_obj_clear_flag(hdr, LV_OBJ_FLAG_SCROLLABLE | LV_OBJ_FLAG_CLICKABLE);
lv_obj_t* lbl = lv_label_create(hdr);
lv_obj_set_style_text_font(lbl, &lv_font_ratdeck_10, 0);
lv_obj_set_style_text_font(lbl, &lv_font_rsdeck_10, 0);
lv_obj_set_style_text_color(lbl, lv_color_hex(Theme::ACCENT), 0);
lv_label_set_text(lbl, text);
lv_obj_set_pos(lbl, 8, 5);
@@ -327,7 +327,7 @@ void LvNodesScreen::rebuildList() {
}, LV_EVENT_FOCUSED, nullptr);
lv_obj_t* nameLbl = lv_label_create(row);
lv_obj_set_style_text_font(nameLbl, &lv_font_ratdeck_12, 0);
lv_obj_set_style_text_font(nameLbl, &lv_font_rsdeck_12, 0);
lv_obj_set_style_text_color(nameLbl, lv_color_hex(
node.saved ? Theme::ACCENT : Theme::PRIMARY), 0);
lv_label_set_long_mode(nameLbl, LV_LABEL_LONG_CLIP);
@@ -337,7 +337,7 @@ void LvNodesScreen::rebuildList() {
lv_obj_set_pos(nameLbl, 8, 3);
lv_obj_t* infoLbl = lv_label_create(row);
lv_obj_set_style_text_font(infoLbl, &lv_font_ratdeck_10, 0);
lv_obj_set_style_text_font(infoLbl, &lv_font_rsdeck_10, 0);
lv_obj_set_style_text_color(infoLbl, lv_color_hex(Theme::TEXT_SECONDARY), 0);
lv_obj_set_style_text_align(infoLbl, LV_TEXT_ALIGN_RIGHT, 0);
lv_label_set_long_mode(infoLbl, LV_LABEL_LONG_CLIP);
@@ -347,7 +347,7 @@ void LvNodesScreen::rebuildList() {
lv_obj_set_pos(infoLbl, Theme::CONTENT_W - 124, 5);
lv_obj_t* idLbl = lv_label_create(row);
lv_obj_set_style_text_font(idLbl, &lv_font_ratdeck_10, 0);
lv_obj_set_style_text_font(idLbl, &lv_font_rsdeck_10, 0);
lv_obj_set_style_text_color(idLbl, lv_color_hex(Theme::TEXT_MUTED), 0);
lv_label_set_long_mode(idLbl, LV_LABEL_LONG_CLIP);
lv_obj_set_width(idLbl, Theme::CONTENT_W - 16);
+3 -3
View File
@@ -20,7 +20,7 @@ void LvQrOverlay::create() {
lv_obj_clear_flag(_overlay, LV_OBJ_FLAG_SCROLLABLE);
lv_obj_t* title = lv_label_create(_overlay);
lv_obj_set_style_text_font(title, &lv_font_ratdeck_14, 0);
lv_obj_set_style_text_font(title, &lv_font_rsdeck_14, 0);
lv_obj_set_style_text_color(title, lv_color_hex(Theme::ACCENT), 0);
lv_label_set_text(title, "Scan to add me");
@@ -31,7 +31,7 @@ void LvQrOverlay::create() {
lv_color_hex(0xFFFFFF));
_lblAddr = lv_label_create(_overlay);
lv_obj_set_style_text_font(_lblAddr, &lv_font_ratdeck_10, 0);
lv_obj_set_style_text_font(_lblAddr, &lv_font_rsdeck_10, 0);
lv_obj_set_style_text_color(_lblAddr, lv_color_hex(Theme::TEXT_MUTED), 0);
lv_label_set_long_mode(_lblAddr, LV_LABEL_LONG_WRAP);
lv_obj_set_width(_lblAddr, Theme::SCREEN_W - 12);
@@ -39,7 +39,7 @@ void LvQrOverlay::create() {
lv_label_set_text(_lblAddr, "");
lv_obj_t* hint = lv_label_create(_overlay);
lv_obj_set_style_text_font(hint, &lv_font_ratdeck_10, 0);
lv_obj_set_style_text_font(hint, &lv_font_rsdeck_10, 0);
lv_obj_set_style_text_color(hint, lv_color_hex(Theme::TEXT_MUTED), 0);
lv_label_set_text(hint, "Any key to close");
+23 -23
View File
@@ -203,20 +203,20 @@ bool LvSettingsScreen::categoryNeedsReboot(int catIdx) const {
bool LvSettingsScreen::confirmableAction(const SettingItem& item) const {
return labelEq(item.label, "Developer Radio Controls")
|| labelEq(item.label, "Format SD Card")
|| labelEq(item.label, "Erase Ratdeck SD Data")
|| labelEq(item.label, "Erase rsDeck SD Data")
|| labelEq(item.label, "Erase Device");
}
bool LvSettingsScreen::armedAction(const SettingItem& item) const {
return (_confirmingInitSD && labelEq(item.label, "Format SD Card")) ||
(_confirmingWipeSD && labelEq(item.label, "Erase Ratdeck SD Data")) ||
(_confirmingWipeSD && labelEq(item.label, "Erase rsDeck SD Data")) ||
(_confirmingReset && labelEq(item.label, "Erase Device")) ||
(_confirmingDevMode && labelEq(item.label, "Developer Radio Controls"));
}
bool LvSettingsScreen::destructiveAction(const SettingItem& item) const {
return labelEq(item.label, "Format SD Card")
|| labelEq(item.label, "Erase Ratdeck SD Data")
|| labelEq(item.label, "Erase rsDeck SD Data")
|| labelEq(item.label, "Erase Device");
}
@@ -255,7 +255,7 @@ void LvSettingsScreen::runFormatSD() {
return;
}
if (_ui) _ui->lvStatusBar().showToast("Formatting SD card...", 2000);
bool ok = _sd->formatForRatdeck();
bool ok = _sd->formatForRsDeck();
if (_ui) _ui->lvStatusBar().showToast(ok ? "SD card formatted" : "SD format failed", 1500);
rebuildItemList();
}
@@ -267,8 +267,8 @@ void LvSettingsScreen::runWipeSD() {
rebuildItemList();
return;
}
if (_ui) _ui->lvStatusBar().showToast("Erasing Ratdeck SD data...", 2000);
bool ok = _sd->wipeRatdeck();
if (_ui) _ui->lvStatusBar().showToast("Erasing rsDeck SD data...", 2000);
bool ok = _sd->wipeRsDeck();
if (_ui) _ui->lvStatusBar().showToast(ok ? "SD data erased" : "SD erase failed", 1500);
rebuildItemList();
}
@@ -276,7 +276,7 @@ void LvSettingsScreen::runWipeSD() {
void LvSettingsScreen::runFactoryReset() {
_confirmingReset = false;
if (_ui) _ui->lvStatusBar().showToast("Erasing device...", 3000);
if (_sd && _sd->isReady()) _sd->wipeRatdeck();
if (_sd && _sd->isReady()) _sd->wipeRsDeck();
if (_flash) _flash->format();
nvs_flash_erase();
delay(1500); // Long enough for key state to clear before reboot
@@ -336,7 +336,7 @@ void LvSettingsScreen::firmwareCheckTask(void* arg) {
HTTPClient http;
http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
http.setTimeout(5000);
if (http.begin("https://api.github.com/repos/ratspeak/ratdeck/releases/latest")) {
if (http.begin("https://api.github.com/repos/ratspeak/rsDeck/releases/latest")) {
http.addHeader("Accept", "application/vnd.github.v3+json");
int httpCode = http.GET();
if (httpCode == 200) {
@@ -355,7 +355,7 @@ void LvSettingsScreen::firmwareCheckTask(void* arg) {
delay(10);
}
if (extractReleaseTag(payload, version, sizeof(version))) {
result = strcmp(version, RATDECK_VERSION_STRING) > 0
result = strcmp(version, RSDECK_VERSION_STRING) > 0
? FirmwareCheckState::AVAILABLE
: FirmwareCheckState::CURRENT;
}
@@ -379,7 +379,7 @@ void LvSettingsScreen::buildItems() {
// Identity & Device
int devStart = idx;
_items.push_back({"Firmware", SettingType::READONLY, nullptr, nullptr,
[](int) { return String(RATDECK_VERSION_STRING); }});
[](int) { return String(RSDECK_VERSION_STRING); }});
idx++;
_items.push_back({"LXMF Address", SettingType::READONLY, nullptr, nullptr,
[this](int) { return _destinationHash.length() > 0 ? _destinationHash : String("unknown"); }});
@@ -1005,7 +1005,7 @@ void LvSettingsScreen::buildItems() {
}
{
SettingItem wipeSD;
wipeSD.label = "Erase Ratdeck SD Data";
wipeSD.label = "Erase rsDeck SD Data";
wipeSD.type = SettingType::ACTION;
wipeSD.formatter = [this](int) {
if (!_sd || !_sd->isReady()) return String("No Card");
@@ -1156,7 +1156,7 @@ void LvSettingsScreen::rebuildCategoryList() {
_rowObjs.clear();
lv_obj_clean(_scrollContainer);
const lv_font_t* font = &lv_font_ratdeck_12;
const lv_font_t* font = &lv_font_rsdeck_12;
// Title
lv_obj_t* titleRow = lv_obj_create(_scrollContainer);
@@ -1177,7 +1177,7 @@ void LvSettingsScreen::rebuildCategoryList() {
if (_rebootNeeded) {
lv_obj_t* pendingLbl = lv_label_create(titleRow);
lv_obj_set_style_text_font(pendingLbl, &lv_font_ratdeck_10, 0);
lv_obj_set_style_text_font(pendingLbl, &lv_font_rsdeck_10, 0);
lv_obj_set_style_text_color(pendingLbl, lv_color_hex(Theme::WARNING_CLR), 0);
lv_label_set_text(pendingLbl, "REBOOT PENDING");
lv_obj_align(pendingLbl, LV_ALIGN_RIGHT_MID, -8, 0);
@@ -1222,7 +1222,7 @@ void LvSettingsScreen::rebuildCategoryList() {
char countBuf[8];
snprintf(countBuf, sizeof(countBuf), "%d", cat.count);
lv_obj_t* countLbl = lv_label_create(row);
lv_obj_set_style_text_font(countLbl, &lv_font_ratdeck_10, 0);
lv_obj_set_style_text_font(countLbl, &lv_font_rsdeck_10, 0);
lv_obj_set_style_text_color(countLbl, lv_color_hex(Theme::TEXT_MUTED), 0);
lv_label_set_text(countLbl, countBuf);
lv_obj_align(countLbl, LV_ALIGN_TOP_RIGHT, -24, 5);
@@ -1230,7 +1230,7 @@ void LvSettingsScreen::rebuildCategoryList() {
// Summary
if (cat.summary) {
lv_obj_t* sumLbl = lv_label_create(row);
lv_obj_set_style_text_font(sumLbl, &lv_font_ratdeck_10, 0);
lv_obj_set_style_text_font(sumLbl, &lv_font_rsdeck_10, 0);
lv_obj_set_style_text_color(sumLbl, lv_color_hex(pending ? Theme::WARNING_CLR : Theme::TEXT_MUTED), 0);
clipLabel(sumLbl, Theme::CONTENT_W - 44);
lv_label_set_text(sumLbl, cat.summary().c_str());
@@ -1259,7 +1259,7 @@ void LvSettingsScreen::rebuildItemList() {
_editValueLbl = nullptr; // Invalidate cached label before destroying widgets
lv_obj_clean(_scrollContainer);
const lv_font_t* font = &lv_font_ratdeck_12;
const lv_font_t* font = &lv_font_rsdeck_12;
// Category header
lv_obj_t* headerRow = lv_obj_create(_scrollContainer);
@@ -1289,7 +1289,7 @@ void LvSettingsScreen::rebuildItemList() {
if (_rebootNeeded) {
lv_obj_t* pendingLbl = lv_label_create(headerRow);
lv_obj_set_style_text_font(pendingLbl, &lv_font_ratdeck_10, 0);
lv_obj_set_style_text_font(pendingLbl, &lv_font_rsdeck_10, 0);
lv_obj_set_style_text_color(pendingLbl, lv_color_hex(Theme::WARNING_CLR), 0);
lv_label_set_text(pendingLbl, "REBOOT NEEDED");
lv_obj_align(pendingLbl, LV_ALIGN_RIGHT_MID, -8, 0);
@@ -1308,7 +1308,7 @@ void LvSettingsScreen::rebuildItemList() {
lv_obj_clear_flag(notice, LV_OBJ_FLAG_SCROLLABLE);
lv_obj_t* noticeLbl = lv_label_create(notice);
lv_obj_set_style_text_font(noticeLbl, &lv_font_ratdeck_10, 0);
lv_obj_set_style_text_font(noticeLbl, &lv_font_rsdeck_10, 0);
lv_obj_set_style_text_color(noticeLbl, lv_color_hex(Theme::WARNING_CLR), 0);
clipLabel(noticeLbl, Theme::CONTENT_W - 16);
lv_label_set_text(noticeLbl, "Saved interface config is pending reboot");
@@ -1331,14 +1331,14 @@ void LvSettingsScreen::rebuildItemList() {
lv_obj_clear_flag(confirm, LV_OBJ_FLAG_SCROLLABLE);
lv_obj_t* confirmTitleLbl = lv_label_create(confirm);
lv_obj_set_style_text_font(confirmTitleLbl, &lv_font_ratdeck_12, 0);
lv_obj_set_style_text_font(confirmTitleLbl, &lv_font_rsdeck_12, 0);
lv_obj_set_style_text_color(confirmTitleLbl, lv_color_hex(confirmColor), 0);
clipLabel(confirmTitleLbl, Theme::CONTENT_W - 16);
lv_label_set_text(confirmTitleLbl, confirmTitle);
lv_obj_align(confirmTitleLbl, LV_ALIGN_TOP_LEFT, 8, 3);
lv_obj_t* confirmDetailLbl = lv_label_create(confirm);
lv_obj_set_style_text_font(confirmDetailLbl, &lv_font_ratdeck_10, 0);
lv_obj_set_style_text_font(confirmDetailLbl, &lv_font_rsdeck_10, 0);
lv_obj_set_style_text_color(confirmDetailLbl, lv_color_hex(Theme::TEXT_PRIMARY), 0);
clipLabel(confirmDetailLbl, Theme::CONTENT_W - 16);
lv_label_set_text(confirmDetailLbl, confirmDetail);
@@ -1515,7 +1515,7 @@ void LvSettingsScreen::rebuildWifiList() {
_rowObjs.clear();
lv_obj_clean(_scrollContainer);
const lv_font_t* font = &lv_font_ratdeck_12;
const lv_font_t* font = &lv_font_rsdeck_12;
// Header
lv_obj_t* headerRow = lv_obj_create(_scrollContainer);
@@ -1591,7 +1591,7 @@ void LvSettingsScreen::rebuildWifiList() {
char sigBuf[12];
snprintf(sigBuf, sizeof(sigBuf), "%ddBm", net.rssi);
lv_obj_t* sigLbl = lv_label_create(row);
lv_obj_set_style_text_font(sigLbl, &lv_font_ratdeck_10, 0);
lv_obj_set_style_text_font(sigLbl, &lv_font_rsdeck_10, 0);
lv_obj_set_style_text_color(sigLbl, lv_color_hex(Theme::TEXT_MUTED), 0);
lv_label_set_text(sigLbl, sigBuf);
lv_obj_align(sigLbl, LV_ALIGN_RIGHT_MID, -4, 0);
@@ -1919,7 +1919,7 @@ bool LvSettingsScreen::handleLongPress() {
runFormatSD();
return true;
}
if (_confirmingWipeSD && labelEq(item.label, "Erase Ratdeck SD Data")) {
if (_confirmingWipeSD && labelEq(item.label, "Erase rsDeck SD Data")) {
runWipeSD();
return true;
}
+5 -5
View File
@@ -54,7 +54,7 @@ lv_obj_t* makeActionButton(lv_obj_t* parent, const char* text, lv_coord_t x,
lv_obj_set_style_pad_all(btn, 0, 0);
lv_obj_t* lbl = lv_label_create(btn);
lv_obj_set_style_text_font(lbl, &lv_font_ratdeck_12, 0);
lv_obj_set_style_text_font(lbl, &lv_font_rsdeck_12, 0);
lv_obj_set_style_text_color(lbl,
lv_color_hex(primary ? Theme::ACCENT : Theme::TEXT_PRIMARY), 0);
lv_label_set_long_mode(lbl, LV_LABEL_LONG_DOT);
@@ -78,7 +78,7 @@ void LvTimezoneScreen::createUI(lv_obj_t* parent) {
lv_obj_set_style_bg_opa(parent, LV_OPA_COVER, 0);
_selectedIdx = clampTimezoneIndex(_selectedIdx);
lv_obj_t* eyebrow = makeLabel(parent, "REGION SETUP", &lv_font_ratdeck_10,
lv_obj_t* eyebrow = makeLabel(parent, "REGION SETUP", &lv_font_rsdeck_10,
Theme::TEXT_SECONDARY, 220, LV_TEXT_ALIGN_CENTER,
LV_LABEL_LONG_DOT);
lv_obj_align(eyebrow, LV_ALIGN_TOP_MID, 0, 8);
@@ -89,7 +89,7 @@ void LvTimezoneScreen::createUI(lv_obj_t* parent) {
lv_obj_align(title, LV_ALIGN_TOP_MID, 0, 24);
lv_obj_t* sub = makeLabel(parent, "Pick the nearest city for time and radio-region hints.",
&lv_font_ratdeck_12, Theme::TEXT_PRIMARY,
&lv_font_rsdeck_12, Theme::TEXT_PRIMARY,
280, LV_TEXT_ALIGN_CENTER);
lv_obj_align(sub, LV_ALIGN_TOP_MID, 0, 48);
@@ -115,12 +115,12 @@ void LvTimezoneScreen::createUI(lv_obj_t* parent) {
lv_roller_set_selected(_roller, _selectedIdx, LV_ANIM_OFF);
lv_obj_add_style(_roller, LvTheme::styleRoller(), LV_PART_MAIN);
lv_obj_set_style_text_font(_roller, &lv_font_ratdeck_14, LV_PART_MAIN);
lv_obj_set_style_text_font(_roller, &lv_font_rsdeck_14, LV_PART_MAIN);
lv_obj_set_style_text_align(_roller, LV_TEXT_ALIGN_CENTER, LV_PART_MAIN);
lv_obj_set_style_bg_color(_roller, lv_color_hex(Theme::BG_HOVER), LV_PART_SELECTED);
lv_obj_set_style_bg_opa(_roller, LV_OPA_COVER, LV_PART_SELECTED);
lv_obj_set_style_text_color(_roller, lv_color_hex(Theme::ACCENT), LV_PART_SELECTED);
lv_obj_set_style_text_font(_roller, &lv_font_ratdeck_14, LV_PART_SELECTED);
lv_obj_set_style_text_font(_roller, &lv_font_rsdeck_14, LV_PART_SELECTED);
lv_obj_set_style_text_align(_roller, LV_TEXT_ALIGN_CENTER, LV_PART_SELECTED);
// Add to focus group for trackball navigation