More efficient handling of multiple fonts, restore data bugfix
All checks were successful
BTClock CI / build (push) Successful in 12m16s
BTClock CI / merge (map[name:btclock_rev_b version:esp32s3], 213epd) (push) Successful in 31s
BTClock CI / merge (map[name:btclock_v8 version:esp32s3], 213epd) (push) Successful in 21s
BTClock CI / merge (map[name:lolin_s3_mini version:esp32s3], 213epd) (push) Successful in 29s
BTClock CI / merge (map[name:lolin_s3_mini version:esp32s3], 29epd) (push) Successful in 19s
BTClock CI / release (push) Successful in 39s
All checks were successful
BTClock CI / build (push) Successful in 12m16s
BTClock CI / merge (map[name:btclock_rev_b version:esp32s3], 213epd) (push) Successful in 31s
BTClock CI / merge (map[name:btclock_v8 version:esp32s3], 213epd) (push) Successful in 21s
BTClock CI / merge (map[name:lolin_s3_mini version:esp32s3], 213epd) (push) Successful in 29s
BTClock CI / merge (map[name:lolin_s3_mini version:esp32s3], 29epd) (push) Successful in 19s
BTClock CI / release (push) Successful in 39s
This commit is contained in:
parent
90d91ba216
commit
13c8e67b4c
9 changed files with 96 additions and 94 deletions
2
data
2
data
|
@ -1 +1 @@
|
||||||
Subproject commit 48e585d4ec12bbc441499936d7cbf53d4307b9ec
|
Subproject commit 0041ec3d9a174955383836bba02caf79f3961072
|
|
@ -15,9 +15,35 @@ struct FontData {
|
||||||
const uint8_t yAdvance;
|
const uint8_t yAdvance;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Font name constants
|
||||||
|
namespace FontNames {
|
||||||
|
static const String ANTONIO = "antonio";
|
||||||
|
static const String OSWALD = "oswald";
|
||||||
|
|
||||||
|
static const std::array<String, 2> AVAILABLE_FONTS = {
|
||||||
|
ANTONIO,
|
||||||
|
OSWALD
|
||||||
|
};
|
||||||
|
|
||||||
|
static const std::array<String, 2>& getAvailableFonts() {
|
||||||
|
return AVAILABLE_FONTS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class FontLoader {
|
class FontLoader {
|
||||||
public:
|
public:
|
||||||
|
static GFXfont* loadCompressedFont(const FontData& fontData) {
|
||||||
|
return loadCompressedFont(
|
||||||
|
fontData.compressedData,
|
||||||
|
fontData.glyphs,
|
||||||
|
fontData.compressedSize,
|
||||||
|
fontData.originalSize,
|
||||||
|
fontData.first,
|
||||||
|
fontData.last,
|
||||||
|
fontData.yAdvance
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
static GFXfont* loadCompressedFont(
|
static GFXfont* loadCompressedFont(
|
||||||
const uint8_t* compressedData,
|
const uint8_t* compressedData,
|
||||||
const GFXglyph* glyphs,
|
const GFXglyph* glyphs,
|
||||||
|
|
114
src/lib/epd.cpp
114
src/lib/epd.cpp
|
@ -161,73 +161,21 @@ void forceFullRefresh()
|
||||||
|
|
||||||
GFXfont font90;
|
GFXfont font90;
|
||||||
|
|
||||||
void setupDisplays()
|
void loadFonts(const String& fontName) {
|
||||||
{
|
if (fontName == FontNames::ANTONIO) {
|
||||||
String fontName = preferences.getString("fontName", DEFAULT_FONT_NAME); // Default to antonio
|
|
||||||
|
|
||||||
if (fontName == "antonio")
|
|
||||||
{
|
|
||||||
// Load Antonio fonts
|
// Load Antonio fonts
|
||||||
antonioFonts.big = FontLoader::loadCompressedFont(
|
antonioFonts.big = FontLoader::loadCompressedFont(Antonio_SemiBold90pt7b_Properties);
|
||||||
Antonio_SemiBold90pt7b_Properties.compressedData,
|
antonioFonts.medium = FontLoader::loadCompressedFont(Antonio_SemiBold40pt7b_Properties);
|
||||||
Antonio_SemiBold90pt7b_Properties.glyphs,
|
antonioFonts.small = FontLoader::loadCompressedFont(Antonio_SemiBold20pt7b_Properties);
|
||||||
Antonio_SemiBold90pt7b_Properties.compressedSize,
|
|
||||||
Antonio_SemiBold90pt7b_Properties.originalSize,
|
|
||||||
Antonio_SemiBold90pt7b_Properties.first,
|
|
||||||
Antonio_SemiBold90pt7b_Properties.last,
|
|
||||||
Antonio_SemiBold90pt7b_Properties.yAdvance);
|
|
||||||
|
|
||||||
antonioFonts.medium = FontLoader::loadCompressedFont(
|
|
||||||
Antonio_SemiBold40pt7b_Properties.compressedData,
|
|
||||||
Antonio_SemiBold40pt7b_Properties.glyphs,
|
|
||||||
Antonio_SemiBold40pt7b_Properties.compressedSize,
|
|
||||||
Antonio_SemiBold40pt7b_Properties.originalSize,
|
|
||||||
Antonio_SemiBold40pt7b_Properties.first,
|
|
||||||
Antonio_SemiBold40pt7b_Properties.last,
|
|
||||||
Antonio_SemiBold40pt7b_Properties.yAdvance);
|
|
||||||
|
|
||||||
antonioFonts.small = FontLoader::loadCompressedFont(
|
|
||||||
Antonio_SemiBold20pt7b_Properties.compressedData,
|
|
||||||
Antonio_SemiBold20pt7b_Properties.glyphs,
|
|
||||||
Antonio_SemiBold20pt7b_Properties.compressedSize,
|
|
||||||
Antonio_SemiBold20pt7b_Properties.originalSize,
|
|
||||||
Antonio_SemiBold20pt7b_Properties.first,
|
|
||||||
Antonio_SemiBold20pt7b_Properties.last,
|
|
||||||
Antonio_SemiBold20pt7b_Properties.yAdvance);
|
|
||||||
|
|
||||||
FONT_BIG = antonioFonts.big;
|
FONT_BIG = antonioFonts.big;
|
||||||
FONT_MEDIUM = antonioFonts.medium;
|
FONT_MEDIUM = antonioFonts.medium;
|
||||||
FONT_SMALL = antonioFonts.small;
|
FONT_SMALL = antonioFonts.small;
|
||||||
}
|
} else if (fontName == FontNames::OSWALD) {
|
||||||
else if (fontName == "oswald")
|
|
||||||
{
|
|
||||||
// Load Oswald fonts
|
// Load Oswald fonts
|
||||||
oswaldFonts.big = FontLoader::loadCompressedFont(
|
oswaldFonts.big = FontLoader::loadCompressedFont(Oswald_Medium80pt7b_Properties);
|
||||||
Oswald_Medium80pt7b_Properties.compressedData,
|
oswaldFonts.medium = FontLoader::loadCompressedFont(Oswald_Medium30pt7b_Properties);
|
||||||
Oswald_Medium80pt7b_Properties.glyphs,
|
oswaldFonts.small = FontLoader::loadCompressedFont(Oswald_Medium20pt7b_Properties);
|
||||||
Oswald_Medium80pt7b_Properties.compressedSize,
|
|
||||||
Oswald_Medium80pt7b_Properties.originalSize,
|
|
||||||
Oswald_Medium80pt7b_Properties.first,
|
|
||||||
Oswald_Medium80pt7b_Properties.last,
|
|
||||||
Oswald_Medium80pt7b_Properties.yAdvance);
|
|
||||||
|
|
||||||
oswaldFonts.medium = FontLoader::loadCompressedFont(
|
|
||||||
Oswald_Medium30pt7b_Properties.compressedData,
|
|
||||||
Oswald_Medium30pt7b_Properties.glyphs,
|
|
||||||
Oswald_Medium30pt7b_Properties.compressedSize,
|
|
||||||
Oswald_Medium30pt7b_Properties.originalSize,
|
|
||||||
Oswald_Medium30pt7b_Properties.first,
|
|
||||||
Oswald_Medium30pt7b_Properties.last,
|
|
||||||
Oswald_Medium30pt7b_Properties.yAdvance);
|
|
||||||
|
|
||||||
oswaldFonts.small = FontLoader::loadCompressedFont(
|
|
||||||
Oswald_Medium20pt7b_Properties.compressedData,
|
|
||||||
Oswald_Medium20pt7b_Properties.glyphs,
|
|
||||||
Oswald_Medium20pt7b_Properties.compressedSize,
|
|
||||||
Oswald_Medium20pt7b_Properties.originalSize,
|
|
||||||
Oswald_Medium20pt7b_Properties.first,
|
|
||||||
Oswald_Medium20pt7b_Properties.last,
|
|
||||||
Oswald_Medium20pt7b_Properties.yAdvance);
|
|
||||||
|
|
||||||
FONT_BIG = oswaldFonts.big;
|
FONT_BIG = oswaldFonts.big;
|
||||||
FONT_MEDIUM = oswaldFonts.medium;
|
FONT_MEDIUM = oswaldFonts.medium;
|
||||||
|
@ -235,53 +183,49 @@ void setupDisplays()
|
||||||
}
|
}
|
||||||
|
|
||||||
FONT_SATSYMBOL = &Satoshi_Symbol90pt7b;
|
FONT_SATSYMBOL = &Satoshi_Symbol90pt7b;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setupDisplays() {
|
||||||
|
// Load fonts based on preference
|
||||||
|
String fontName = preferences.getString("fontName", DEFAULT_FONT_NAME);
|
||||||
|
loadFonts(fontName);
|
||||||
|
|
||||||
|
// Initialize displays
|
||||||
std::lock_guard<std::mutex> lockMcp(mcpMutex);
|
std::lock_guard<std::mutex> lockMcp(mcpMutex);
|
||||||
|
for (uint i = 0; i < NUM_SCREENS; i++) {
|
||||||
for (uint i = 0; i < NUM_SCREENS; i++)
|
|
||||||
{
|
|
||||||
displays[i].init(0, true, 30);
|
displays[i].init(0, true, 30);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create update queue and task
|
||||||
updateQueue = xQueueCreate(UPDATE_QUEUE_SIZE, sizeof(UpdateDisplayTaskItem));
|
updateQueue = xQueueCreate(UPDATE_QUEUE_SIZE, sizeof(UpdateDisplayTaskItem));
|
||||||
|
|
||||||
xTaskCreate(prepareDisplayUpdateTask, "PrepareUpd", EPD_TASK_STACK_SIZE * 2, NULL, 11, NULL);
|
xTaskCreate(prepareDisplayUpdateTask, "PrepareUpd", EPD_TASK_STACK_SIZE * 2, NULL, 11, NULL);
|
||||||
|
|
||||||
for (uint i = 0; i < NUM_SCREENS; i++)
|
// Create display update tasks
|
||||||
{
|
for (uint i = 0; i < NUM_SCREENS; i++) {
|
||||||
int *taskParam = new int;
|
int *taskParam = new int;
|
||||||
*taskParam = i;
|
*taskParam = i;
|
||||||
|
xTaskCreate(updateDisplay, ("EpdUpd" + String(i)).c_str(), EPD_TASK_STACK_SIZE, taskParam, 11, &tasks[i]);
|
||||||
xTaskCreate(updateDisplay, ("EpdUpd" + String(i)).c_str(), EPD_TASK_STACK_SIZE, taskParam,
|
|
||||||
11, &tasks[i]); // create task
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hold lower button to enable "storage mode" (prevents burn-in of ePaper displays)
|
// Check for storage mode (prevents burn-in)
|
||||||
if (mcp1.read1(0) == LOW)
|
if (mcp1.read1(0) == LOW) {
|
||||||
{
|
|
||||||
setFgColor(GxEPD_BLACK);
|
setFgColor(GxEPD_BLACK);
|
||||||
setBgColor(GxEPD_WHITE);
|
setBgColor(GxEPD_WHITE);
|
||||||
|
|
||||||
epdContent.fill("");
|
epdContent.fill("");
|
||||||
}
|
} else {
|
||||||
else
|
// Initialize with custom text or default
|
||||||
{
|
|
||||||
// Get custom text from preferences or use default "BTCLOCK"
|
|
||||||
String customText = preferences.getString("displayText", DEFAULT_BOOT_TEXT);
|
String customText = preferences.getString("displayText", DEFAULT_BOOT_TEXT);
|
||||||
|
|
||||||
// Initialize array with spaces
|
|
||||||
std::array<String, NUM_SCREENS> newContent;
|
std::array<String, NUM_SCREENS> newContent;
|
||||||
newContent.fill(" ");
|
newContent.fill(" ");
|
||||||
|
|
||||||
// Fill in the custom text, truncating if longer than NUM_SCREENS
|
|
||||||
for (size_t i = 0; i < std::min(customText.length(), (size_t)NUM_SCREENS); i++) {
|
for (size_t i = 0; i < std::min(customText.length(), (size_t)NUM_SCREENS); i++) {
|
||||||
newContent[i] = String(customText[i]);
|
newContent[i] = String(customText[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
epdContent = newContent;
|
epdContent = newContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
setEpdContent(epdContent);
|
setEpdContent(epdContent);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setEpdContent(std::array<String, NUM_SCREENS> newEpdContent)
|
void setEpdContent(std::array<String, NUM_SCREENS> newEpdContent)
|
||||||
|
@ -527,8 +471,8 @@ void showDigit(const uint dispNum, char chr, bool partial, const GFXfont *font)
|
||||||
|
|
||||||
if (chr == '.')
|
if (chr == '.')
|
||||||
{
|
{
|
||||||
displays[dispNum].fillRect(x, y, displays[dispNum].width(),
|
displays[dispNum].fillRect(0, 0, displays[dispNum].width(),
|
||||||
round(displays[dispNum].height() * 0.9), getBgColor());
|
round(displays[dispNum].height() * 0.67), getBgColor());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,6 @@
|
||||||
#ifdef USE_QR
|
#ifdef USE_QR
|
||||||
#include "qrcodegen.h"
|
#include "qrcodegen.h"
|
||||||
#endif
|
#endif
|
||||||
// extern TaskHandle_t epdTaskHandle;
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char dispNum;
|
char dispNum;
|
||||||
|
@ -39,6 +38,7 @@ typedef struct {
|
||||||
|
|
||||||
void forceFullRefresh();
|
void forceFullRefresh();
|
||||||
void setupDisplays();
|
void setupDisplays();
|
||||||
|
void loadFonts(const String& fontName);
|
||||||
|
|
||||||
void splitText(const uint dispNum, const String &top, const String &bottom,
|
void splitText(const uint dispNum, const String &top, const String &bottom,
|
||||||
bool partial);
|
bool partial);
|
||||||
|
|
|
@ -110,15 +110,17 @@ void processNewPrice(uint newPrice, char currency)
|
||||||
if (lastUpdateMap.find(currency) == lastUpdateMap.end() ||
|
if (lastUpdateMap.find(currency) == lastUpdateMap.end() ||
|
||||||
(currentTime - lastUpdateMap[currency]) > minSecPriceUpd)
|
(currentTime - lastUpdateMap[currency]) > minSecPriceUpd)
|
||||||
{
|
{
|
||||||
// const unsigned long oldPrice = currentPrice;
|
|
||||||
currencyMap[currency] = newPrice;
|
currencyMap[currency] = newPrice;
|
||||||
if (currency == CURRENCY_USD && ( lastUpdateMap[currency] == 0 ||
|
|
||||||
(currentTime - lastUpdateMap[currency]) > 120))
|
// Store price in preferences if enough time has passed
|
||||||
|
if (lastUpdateMap[currency] == 0 || (currentTime - lastUpdateMap[currency]) > 120)
|
||||||
{
|
{
|
||||||
preferences.putUInt("lastPrice", currentPrice);
|
String prefKey = String("lastPrice_") + getCurrencyCode(currency).c_str();
|
||||||
|
preferences.putUInt(prefKey.c_str(), newPrice);
|
||||||
}
|
}
|
||||||
|
|
||||||
lastUpdateMap[currency] = currentTime;
|
lastUpdateMap[currency] = currentTime;
|
||||||
// if (abs((int)(oldPrice-currentPrice)) > round(0.0015*oldPrice)) {
|
|
||||||
if (workQueue != nullptr && (ScreenHandler::getCurrentScreen() == SCREEN_BTC_TICKER ||
|
if (workQueue != nullptr && (ScreenHandler::getCurrentScreen() == SCREEN_BTC_TICKER ||
|
||||||
ScreenHandler::getCurrentScreen() == SCREEN_SATS_PER_CURRENCY ||
|
ScreenHandler::getCurrentScreen() == SCREEN_SATS_PER_CURRENCY ||
|
||||||
ScreenHandler::getCurrentScreen() == SCREEN_MARKET_CAP))
|
ScreenHandler::getCurrentScreen() == SCREEN_MARKET_CAP))
|
||||||
|
@ -126,7 +128,24 @@ void processNewPrice(uint newPrice, char currency)
|
||||||
WorkItem priceUpdate = {TASK_PRICE_UPDATE, currency};
|
WorkItem priceUpdate = {TASK_PRICE_UPDATE, currency};
|
||||||
xQueueSend(workQueue, &priceUpdate, portMAX_DELAY);
|
xQueueSend(workQueue, &priceUpdate, portMAX_DELAY);
|
||||||
}
|
}
|
||||||
//}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void loadStoredPrices()
|
||||||
|
{
|
||||||
|
// Load prices for all supported currencies
|
||||||
|
std::vector<std::string> currencies = getAvailableCurrencies();
|
||||||
|
|
||||||
|
for (const std::string ¤cy : currencies) {
|
||||||
|
// Get first character as the currency identifier
|
||||||
|
String prefKey = String("lastPrice_") + currency.c_str();
|
||||||
|
uint storedPrice = preferences.getUInt(prefKey.c_str(), 0);
|
||||||
|
|
||||||
|
if (storedPrice > 0) {
|
||||||
|
currencyMap[getCurrencyChar(currency)] = storedPrice;
|
||||||
|
// Initialize lastUpdateMap to 0 so next update will store immediately
|
||||||
|
lastUpdateMap[getCurrencyChar(currency)] = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,4 +27,5 @@ void stopPriceNotify();
|
||||||
void restartPriceNotify();
|
void restartPriceNotify();
|
||||||
|
|
||||||
bool getPriceNotifyInit();
|
bool getPriceNotifyInit();
|
||||||
uint getLastPriceUpdate(char currency);
|
uint getLastPriceUpdate(char currency);
|
||||||
|
void loadStoredPrices();
|
|
@ -321,6 +321,7 @@ void taskScreenRotate(void *pvParameters) {
|
||||||
|
|
||||||
void setupTasks() {
|
void setupTasks() {
|
||||||
workQueue = xQueueCreate(WORK_QUEUE_SIZE, sizeof(WorkItem));
|
workQueue = xQueueCreate(WORK_QUEUE_SIZE, sizeof(WorkItem));
|
||||||
|
loadStoredPrices();
|
||||||
|
|
||||||
xTaskCreate(workerTask, "workerTask", 4096, NULL, tskIDLE_PRIORITY,
|
xTaskCreate(workerTask, "workerTask", 4096, NULL, tskIDLE_PRIORITY,
|
||||||
&workerTaskHandle);
|
&workerTaskHandle);
|
||||||
|
|
|
@ -97,6 +97,16 @@ namespace ArduinoJson {
|
||||||
array.add(item);
|
array.add(item);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <size_t N>
|
||||||
|
struct Converter<std::array<String, N>> {
|
||||||
|
static void toJson(const std::array<String, N>& src, JsonVariant dst) {
|
||||||
|
JsonArray array = dst.to<JsonArray>();
|
||||||
|
for (const String& item : src) {
|
||||||
|
array.add(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
class HttpHelper {
|
class HttpHelper {
|
||||||
|
|
|
@ -676,6 +676,7 @@ void onApiSettingsGet(AsyncWebServerRequest *request)
|
||||||
root["nostrZapPubkey"] = preferences.getString("nostrZapPubkey", DEFAULT_ZAP_NOTIFY_PUBKEY);
|
root["nostrZapPubkey"] = preferences.getString("nostrZapPubkey", DEFAULT_ZAP_NOTIFY_PUBKEY);
|
||||||
root["ledFlashOnZap"] = preferences.getBool("ledFlashOnZap", DEFAULT_LED_FLASH_ON_ZAP);
|
root["ledFlashOnZap"] = preferences.getBool("ledFlashOnZap", DEFAULT_LED_FLASH_ON_ZAP);
|
||||||
root["fontName"] = preferences.getString("fontName", DEFAULT_FONT_NAME);
|
root["fontName"] = preferences.getString("fontName", DEFAULT_FONT_NAME);
|
||||||
|
root["availableFonts"] = FontNames::getAvailableFonts();
|
||||||
// Custom endpoint settings (only used for CUSTOM_SOURCE)
|
// Custom endpoint settings (only used for CUSTOM_SOURCE)
|
||||||
root["customEndpoint"] = preferences.getString("customEndpoint", DEFAULT_CUSTOM_ENDPOINT);
|
root["customEndpoint"] = preferences.getString("customEndpoint", DEFAULT_CUSTOM_ENDPOINT);
|
||||||
root["customEndpointDisableSSL"] = preferences.getBool("customEndpointDisableSSL", DEFAULT_CUSTOM_ENDPOINT_DISABLE_SSL);
|
root["customEndpointDisableSSL"] = preferences.getBool("customEndpointDisableSSL", DEFAULT_CUSTOM_ENDPOINT_DISABLE_SSL);
|
||||||
|
|
Loading…
Reference in a new issue