From d37307cccfea6b35dfb149b6e3d5248d9a8460b3 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Wed, 27 Nov 2024 11:33:12 +0100 Subject: [PATCH] Add Mow mode notation and setting --- data | 2 +- lib/btclock/data_handler.cpp | 4 +- lib/btclock/data_handler.hpp | 2 +- lib/btclock/utils.cpp | 25 ++++++++--- lib/btclock/utils.hpp | 1 + src/lib/defaults.hpp | 2 + src/lib/epd.cpp | 70 +++++++++++++++++++++++++++-- src/lib/screen_handler.cpp | 2 +- src/lib/webserver.cpp | 2 + test/test_datahandler/test_main.cpp | 29 ++++++++++++ 10 files changed, 124 insertions(+), 15 deletions(-) diff --git a/data b/data index 5066032..d74e9da 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit 5066032a55b5436ec5c888cf0eb91bdc9e71bea0 +Subproject commit d74e9dab60772ef11f9b033cfe982d216a9c95ee diff --git a/lib/btclock/data_handler.cpp b/lib/btclock/data_handler.cpp index 7b63db6..3209811 100644 --- a/lib/btclock/data_handler.cpp +++ b/lib/btclock/data_handler.cpp @@ -67,13 +67,13 @@ char getCurrencyChar(const std::string& input) return CURRENCY_USD; // Assuming USD is the default for unknown inputs } -std::array parsePriceData(std::uint32_t price, char currencySymbol, bool useSuffixFormat) +std::array parsePriceData(std::uint32_t price, char currencySymbol, bool useSuffixFormat, bool mowMode) { std::array ret; std::string priceString; if (std::to_string(price).length() >= NUM_SCREENS || useSuffixFormat) { - priceString = getCurrencySymbol(currencySymbol) + formatNumberWithSuffix(price, NUM_SCREENS - 2); + priceString = getCurrencySymbol(currencySymbol) + formatNumberWithSuffix(price, NUM_SCREENS - 2, mowMode); } else { diff --git a/lib/btclock/data_handler.hpp b/lib/btclock/data_handler.hpp index 2d563a4..f8e237c 100644 --- a/lib/btclock/data_handler.hpp +++ b/lib/btclock/data_handler.hpp @@ -19,7 +19,7 @@ const std::string CURRENCY_CODE_JPY = "JPY"; const std::string CURRENCY_CODE_AUD = "AUD"; const std::string CURRENCY_CODE_CAD = "CAD"; -std::array parsePriceData(std::uint32_t price, char currency, bool useSuffixFormat = false); +std::array parsePriceData(std::uint32_t price, char currency, bool useSuffixFormat = false, bool mowMode = false); std::array parseSatsPerCurrency(std::uint32_t price, char currencySymbol, bool withSatsSymbol); std::array parseBlockHeight(std::uint32_t blockHeight); std::array parseHalvingCountdown(std::uint32_t blockHeight, bool asBlocks); diff --git a/lib/btclock/utils.cpp b/lib/btclock/utils.cpp index 53212e4..9056d14 100644 --- a/lib/btclock/utils.cpp +++ b/lib/btclock/utils.cpp @@ -28,7 +28,12 @@ double getSupplyAtBlock(std::uint32_t blockNr) return totalBitcoinInCirculation; } -std::string formatNumberWithSuffix(std::uint64_t num, int numCharacters) +std::string formatNumberWithSuffix(std::uint64_t num, int numCharacters) +{ + return formatNumberWithSuffix(num, numCharacters, false); +} + +std::string formatNumberWithSuffix(std::uint64_t num, int numCharacters, bool mowMode) { static char result[20]; // Adjust size as needed const long long quadrillion = 1000000000000000LL; @@ -56,30 +61,36 @@ std::string formatNumberWithSuffix(std::uint64_t num, int numCharacters) numDouble /= billion; suffix = 'B'; } - else if (num >= million || numDigits > 6) + else if (num >= million || numDigits > 6 || (mowMode && num >= thousand)) { numDouble /= million; suffix = 'M'; } - else if (num >= thousand || numDigits > 3) + else if (!mowMode && (num >= thousand || numDigits > 3)) { numDouble /= thousand; suffix = 'K'; } - else + else if (!mowMode) { snprintf(result, sizeof(result), "%llu", (unsigned long long)num); -// sprintf(result, "%llu", (unsigned long long)num); return result; } + else // mowMode is true and num < 1000 + { + numDouble /= million; + suffix = 'M'; + } // Add suffix int len = snprintf(result, sizeof(result), "%.0f%c", numDouble, suffix); - // If there's room, add decimal places + // If there's room, add more decimal places if (len < numCharacters) { - snprintf(result, sizeof(result), "%.*f%c", numCharacters - len - 1, numDouble, suffix); + int restLen = mowMode ? numCharacters - len : numCharacters - len - 1; + + snprintf(result, sizeof(result), "%.*f%c", restLen, numDouble, suffix); } return result; diff --git a/lib/btclock/utils.hpp b/lib/btclock/utils.hpp index b166cae..cf4a107 100644 --- a/lib/btclock/utils.hpp +++ b/lib/btclock/utils.hpp @@ -11,4 +11,5 @@ int modulo(int x,int N); double getSupplyAtBlock(std::uint32_t blockNr); std::string formatNumberWithSuffix(std::uint64_t num, int numCharacters = 4); +std::string formatNumberWithSuffix(std::uint64_t num, int numCharacters, bool mowMode); int64_t getAmountInSatoshis(std::string bolt11); \ No newline at end of file diff --git a/src/lib/defaults.hpp b/src/lib/defaults.hpp index dd222a5..c665b3b 100644 --- a/src/lib/defaults.hpp +++ b/src/lib/defaults.hpp @@ -18,6 +18,8 @@ #define DEFAULT_DISABLE_FL false #define DEFAULT_OWN_DATA_SOURCE true #define DEFAULT_STAGING_SOURCE false +#define DEFAULT_MOW_MODE false + #define DEFAULT_V2_SOURCE_CURRENCY CURRENCY_USD diff --git a/src/lib/epd.cpp b/src/lib/epd.cpp index a301f17..eac002c 100644 --- a/src/lib/epd.cpp +++ b/src/lib/epd.cpp @@ -283,7 +283,10 @@ void prepareDisplayUpdateTask(void *pvParameters) } else { - if (epdContent[epdIndex].length() > 1 && epdContent[epdIndex].indexOf(".") == -1) + if (epdContent[epdIndex].length() == 2) { + showChars(epdIndex, epdContent[epdIndex], updatePartial, &FONT_BIG); + } + else if (epdContent[epdIndex].length() > 1 && epdContent[epdIndex].indexOf(".") == -1) { if (epdContent[epdIndex].equals("STS")) { @@ -407,6 +410,32 @@ void splitText(const uint dispNum, const String &top, const String &bottom, displays[dispNum].print(bottom); } +// void showChars(const uint dispNum, const String &chars, bool partial, +// const GFXfont *font) +// { +// displays[dispNum].setRotation(2); +// displays[dispNum].setFont(font); +// displays[dispNum].setTextColor(getFgColor()); +// int16_t tbx, tby; +// uint16_t tbw, tbh; + +// displays[dispNum].getTextBounds(chars, 0, 0, &tbx, &tby, &tbw, &tbh); + +// // center the bounding box by transposition of the origin: +// uint16_t x = ((displays[dispNum].width() - tbw) / 2) - tbx; +// uint16_t y = ((displays[dispNum].height() - tbh) / 2) - tby; + +// displays[dispNum].fillScreen(getBgColor()); + +// displays[dispNum].setCursor(x, y); +// displays[dispNum].print(chars); + +// // displays[dispNum].setCursor(10, 3); +// // displays[dispNum].setFont(&FONT_SMALL); +// // displays[dispNum].setTextColor(getFgColor()); +// // displays[dispNum].println("Y = " + y); +// } + void showDigit(const uint dispNum, char chr, bool partial, const GFXfont *font) { @@ -466,6 +495,18 @@ void showDigit(const uint dispNum, char chr, bool partial, // displays[dispNum].println("Y = " + y); } +int16_t calculateDescent(const GFXfont *font) { + int16_t maxDescent = 0; + for (uint16_t i = font->first; i <= font->last; i++) { + GFXglyph *glyph = &font->glyph[i - font->first]; + int16_t descent = glyph->yOffset; + if (descent > maxDescent) { + maxDescent = descent; + } + } + return maxDescent; +} + void showChars(const uint dispNum, const String &chars, bool partial, const GFXfont *font) { @@ -475,12 +516,35 @@ void showChars(const uint dispNum, const String &chars, bool partial, int16_t tbx, tby; uint16_t tbw, tbh; displays[dispNum].getTextBounds(chars, 0, 0, &tbx, &tby, &tbw, &tbh); + + int16_t descent = calculateDescent(font); + // center the bounding box by transposition of the origin: uint16_t x = ((displays[dispNum].width() - tbw) / 2) - tbx; uint16_t y = ((displays[dispNum].height() - tbh) / 2) - tby; displays[dispNum].fillScreen(getBgColor()); - displays[dispNum].setCursor(x, y); - displays[dispNum].print(chars); + // displays[dispNum].setCursor(x, y); + // displays[dispNum].print(chars); + + for (int i = 0; i < chars.length(); i++) { + char c = chars[i]; + if (c == '.' || c == ',') { + // For the dot, calculate its specific descent + GFXglyph *dotGlyph = &font->glyph[c -font->first]; + int16_t dotDescent = dotGlyph->yOffset; + + // Draw the dot with adjusted y-position + displays[dispNum].setCursor(x, y + dotDescent + dotGlyph->height); + displays[dispNum].print(c); + } else { + // For other characters, use the original y-position + displays[dispNum].setCursor(x, y); + displays[dispNum].print(c); + } + + // Move x-position for the next character + x += font->glyph[c - font->first].xAdvance; + } } int getBgColor() { return bgColor; } diff --git a/src/lib/screen_handler.cpp b/src/lib/screen_handler.cpp index d1c6165..47ac609 100644 --- a/src/lib/screen_handler.cpp +++ b/src/lib/screen_handler.cpp @@ -41,7 +41,7 @@ void workerTask(void *pvParameters) { uint price = getPrice(currency); if (getCurrentScreen() == SCREEN_BTC_TICKER) { - taskEpdContent = parsePriceData(price, currency, preferences.getBool("suffixPrice", DEFAULT_SUFFIX_PRICE)); + taskEpdContent = parsePriceData(price, currency, preferences.getBool("suffixPrice", DEFAULT_SUFFIX_PRICE), preferences.getBool("mowMode", DEFAULT_MOW_MODE)); } else if (getCurrentScreen() == SCREEN_SATS_PER_CURRENCY) { taskEpdContent = parseSatsPerCurrency(price, currency, preferences.getBool("useSatsSymbol", DEFAULT_USE_SATS_SYMBOL)); } else { diff --git a/src/lib/webserver.cpp b/src/lib/webserver.cpp index 7a6d28d..c4ad256 100644 --- a/src/lib/webserver.cpp +++ b/src/lib/webserver.cpp @@ -546,6 +546,7 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json) "mdnsEnabled", "otaEnabled", "stealFocus", "mcapBigChar", "useSatsSymbol", "useBlkCountdown", "suffixPrice", "disableLeds", "ownDataSource", + "mowMode", "flAlwaysOn", "flDisable", "flFlashOnUpd", "mempoolSecure", "useNostr", "bitaxeEnabled", "nostrZapNotify", "stagingSource", "httpAuthEnabled"}; @@ -687,6 +688,7 @@ void onApiSettingsGet(AsyncWebServerRequest *request) root["useBlkCountdown"] = preferences.getBool("useBlkCountdown", DEFAULT_USE_BLOCK_COUNTDOWN); root["suffixPrice"] = preferences.getBool("suffixPrice", DEFAULT_SUFFIX_PRICE); root["disableLeds"] = preferences.getBool("disableLeds", DEFAULT_DISABLE_LEDS); + root["mowMode"] = preferences.getBool("mowMode", DEFAULT_MOW_MODE); root["hostnamePrefix"] = preferences.getString("hostnamePrefix", DEFAULT_HOSTNAME_PREFIX); root["hostname"] = getMyHostname(); diff --git a/test/test_datahandler/test_main.cpp b/test/test_datahandler/test_main.cpp index 29d337f..218408c 100644 --- a/test/test_datahandler/test_main.cpp +++ b/test/test_datahandler/test_main.cpp @@ -86,6 +86,33 @@ void test_PriceOf1MillionUsd(void) TEST_ASSERT_EQUAL_STRING("M", output[NUM_SCREENS - 1].c_str()); } +void test_PriceSuffixMode(void) +{ + std::array output = parsePriceData(93000, '$', true, false); + TEST_ASSERT_EQUAL_STRING("BTC/USD", output[0].c_str()); + + TEST_ASSERT_EQUAL_STRING("9", output[NUM_SCREENS - 5].c_str()); + TEST_ASSERT_EQUAL_STRING("3", output[NUM_SCREENS - 4].c_str()); + TEST_ASSERT_EQUAL_STRING(".", output[NUM_SCREENS - 3].c_str()); + TEST_ASSERT_EQUAL_STRING("0", output[NUM_SCREENS - 2].c_str()); + TEST_ASSERT_EQUAL_STRING("K", output[NUM_SCREENS - 1].c_str()); +} + +void test_PriceSuffixModeMow(void) +{ + std::array output = parsePriceData(93000, '$', true, true); + + std::string joined = joinArrayWithBrackets(output); + + TEST_ASSERT_EQUAL_STRING_MESSAGE("$", output[0].c_str(), joined.c_str()); + + TEST_ASSERT_EQUAL_STRING_MESSAGE(".", output[NUM_SCREENS - 5].c_str(), joined.c_str()); + TEST_ASSERT_EQUAL_STRING_MESSAGE("0", output[NUM_SCREENS - 4].c_str(), joined.c_str()); + TEST_ASSERT_EQUAL_STRING_MESSAGE("9", output[NUM_SCREENS - 3].c_str(), joined.c_str()); + TEST_ASSERT_EQUAL_STRING_MESSAGE("3", output[NUM_SCREENS - 2].c_str(), joined.c_str()); + TEST_ASSERT_EQUAL_STRING_MESSAGE("M", output[NUM_SCREENS - 1].c_str(), joined.c_str()); +} + void test_McapLowerUsd(void) { std::array output = parseMarketCap(810000, 26000, '$', true); @@ -203,6 +230,8 @@ int runUnityTests(void) RUN_TEST(test_Mcap1TrillionEurSmallChars); RUN_TEST(test_Mcap1TrillionJpy); RUN_TEST(test_Mcap1TrillionJpySmallChars); + RUN_TEST(test_PriceSuffixMode); + RUN_TEST(test_PriceSuffixModeMow); return UNITY_END(); }