diff --git a/data b/data index 3f20d67..1b8ab93 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit 3f20d67f1abc10b20ddecfb5aa0ff4eb78c4c149 +Subproject commit 1b8ab93da64dd7383a2fb34c967b75fdab072718 diff --git a/dependencies.lock b/dependencies.lock index 7d35282..345aa6f 100644 --- a/dependencies.lock +++ b/dependencies.lock @@ -1,11 +1,11 @@ dependencies: esp_littlefs: - component_hash: 0e4812e62ac02a17f2b6a2bb3b6daf9b39e9599a6e319c745ef2a2817c15a073 + component_hash: 66d5afe7ad323d0159d04e296c14ffa0e39156502bc15e0520eff2af392d3aa4 source: git: https://github.com/joltwallet/esp_littlefs.git path: . type: git - version: 5a0a9a0a39549ac55fd51d55bd3f895ffe700a0a + version: 41873c20fb5cdbcf28d7d6cc04e4bcb4a1305317 idf: component_hash: null source: diff --git a/lib/btclock/data_handler.cpp b/lib/btclock/data_handler.cpp index 28f13d0..8719626 100644 --- a/lib/btclock/data_handler.cpp +++ b/lib/btclock/data_handler.cpp @@ -5,7 +5,7 @@ std::array parsePriceData(std::uint32_t price, char cu std::array ret; std::string priceString; if (std::to_string(price).length() >= NUM_SCREENS) { - priceString = formatNumberWithSuffix(price); + priceString = formatNumberWithSuffix(price, NUM_SCREENS-2); } else { priceString = currencySymbol + std::to_string(price); } @@ -32,15 +32,18 @@ std::array parsePriceData(std::uint32_t price, char cu return ret; } -std::array parseSatsPerCurrency(std::uint32_t price, char currencySymbol) +std::array parseSatsPerCurrency(std::uint32_t price, char currencySymbol, bool withSatsSymbol) { std::array ret; std::string priceString = std::to_string(int(round(1 / float(price) * 10e7))); std::uint32_t firstIndex = 0; + uint insertSatSymbol = NUM_SCREENS - priceString.length() - 1; if (priceString.length() < (NUM_SCREENS)) { priceString.insert(priceString.begin(), NUM_SCREENS - priceString.length(), ' '); + + if (currencySymbol == '[') { ret[0] = "SATS/EUR"; @@ -55,6 +58,10 @@ std::array parseSatsPerCurrency(std::uint32_t price, c { ret[i] = priceString[i]; } + + if (withSatsSymbol) { + ret[insertSatSymbol] = "STS"; + } } return ret; } @@ -80,24 +87,43 @@ std::array parseBlockHeight(std::uint32_t blockHeight) return ret; } -std::array parseHalvingCountdown(std::uint32_t blockHeight) +std::array parseHalvingCountdown(std::uint32_t blockHeight, bool asBlocks) { std::array ret; - const std::uint32_t nextHalvingBlock = 210000 - (blockHeight % 210000); const std::uint32_t minutesToHalving = nextHalvingBlock * 10; - const int years = floor(minutesToHalving / 525600); - const int days = floor((minutesToHalving - (years * 525600)) / (24 * 60)); - const int hours = floor((minutesToHalving - (years * 525600) - (days * (24 * 60))) / 60); - const int mins = floor(minutesToHalving - (years * 525600) - (days * (24 * 60)) - (hours * 60)); - ret[0] = "BIT/COIN"; - ret[1] = "HALV/ING"; - ret[(NUM_SCREENS - 5)] = std::to_string(years) + "/YRS"; - ret[(NUM_SCREENS - 4)] = std::to_string(days) + "/DAYS"; - ret[(NUM_SCREENS - 3)] = std::to_string(hours) + "/HRS"; - ret[(NUM_SCREENS - 2)] = std::to_string(mins) + "/MINS"; - ret[(NUM_SCREENS - 1)] = "TO/GO"; + if (asBlocks) { + std::string blockNrString = std::to_string(nextHalvingBlock); + std::uint32_t firstIndex = 0; + + if (blockNrString.length() < NUM_SCREENS) + { + blockNrString.insert(blockNrString.begin(), NUM_SCREENS - blockNrString.length(), ' '); + ret[0] = "HAL/VING"; + firstIndex = 1; + } + + for (std::uint32_t i = firstIndex; i < NUM_SCREENS; i++) + { + ret[i] = blockNrString[i]; + } + + } else { + + + const int years = floor(minutesToHalving / 525600); + const int days = floor((minutesToHalving - (years * 525600)) / (24 * 60)); + const int hours = floor((minutesToHalving - (years * 525600) - (days * (24 * 60))) / 60); + const int mins = floor(minutesToHalving - (years * 525600) - (days * (24 * 60)) - (hours * 60)); + ret[0] = "BIT/COIN"; + ret[1] = "HAL/VING"; + ret[(NUM_SCREENS - 5)] = std::to_string(years) + "/YRS"; + ret[(NUM_SCREENS - 4)] = std::to_string(days) + "/DAYS"; + ret[(NUM_SCREENS - 3)] = std::to_string(hours) + "/HRS"; + ret[(NUM_SCREENS - 2)] = std::to_string(mins) + "/MINS"; + ret[(NUM_SCREENS - 1)] = "TO/GO"; + } return ret; } @@ -120,8 +146,9 @@ std::array parseMarketCap(std::uint32_t blockHeight, s if (bigChars) { firstIndex = 1; - - std::string priceString = currencySymbol + formatNumberWithSuffix(marketCap); + // Serial.print("Market cap: "); + // Serial.println(marketCap); + std::string priceString = currencySymbol + formatNumberWithSuffix(marketCap, (NUM_SCREENS-2)); priceString.insert(priceString.begin(), NUM_SCREENS - priceString.length(), ' '); for (std::uint32_t i = firstIndex; i < NUM_SCREENS; i++) diff --git a/lib/btclock/data_handler.hpp b/lib/btclock/data_handler.hpp index 3ac52c6..d385cef 100644 --- a/lib/btclock/data_handler.hpp +++ b/lib/btclock/data_handler.hpp @@ -6,7 +6,7 @@ #include "utils.hpp" std::array parsePriceData(std::uint32_t price, char currencySymbol); -std::array parseSatsPerCurrency(std::uint32_t price, char currencySymbol); +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); +std::array parseHalvingCountdown(std::uint32_t blockHeight, bool asBlocks); std::array parseMarketCap(std::uint32_t blockHeight, std::uint32_t price, char currencySymbol, bool bigChars); \ No newline at end of file diff --git a/lib/btclock/utils.cpp b/lib/btclock/utils.cpp index 2234ebb..b801fc2 100644 --- a/lib/btclock/utils.cpp +++ b/lib/btclock/utils.cpp @@ -5,18 +5,21 @@ int modulo(int x, int N) return (x % N + N) % N; } -double getSupplyAtBlock(std::uint32_t blockNr) { - if (blockNr >= 33 * 210000) { +double getSupplyAtBlock(std::uint32_t blockNr) +{ + if (blockNr >= 33 * 210000) + { return 20999999.9769; - } + } const int initialBlockReward = 50; // Initial block reward - const int halvingInterval = 210000; // Number of blocks before halving + const int halvingInterval = 210000; // Number of blocks before halving int halvingCount = blockNr / halvingInterval; double totalBitcoinInCirculation = 0; - for (int i = 0; i < halvingCount; ++i) { + for (int i = 0; i < halvingCount; ++i) + { totalBitcoinInCirculation += halvingInterval * initialBlockReward * std::pow(0.5, i); } @@ -25,24 +28,58 @@ double getSupplyAtBlock(std::uint32_t blockNr) { return totalBitcoinInCirculation; } -std::string formatNumberWithSuffix(std::uint64_t num) { +std::string formatNumberWithSuffix(std::uint64_t num, int numCharacters) +{ + static char result[20]; // Adjust size as needed const long long quadrillion = 1000000000000000LL; const long long trillion = 1000000000000LL; const long long billion = 1000000000; const long long million = 1000000; const long long thousand = 1000; - if (num >= quadrillion) { - return std::to_string(num / quadrillion) + "Q"; - } else if (num >= trillion) { - return std::to_string(num / trillion) + "T"; - } else if (num >= billion) { - return std::to_string(num / billion) + "B"; - } else if (num >= million) { - return std::to_string(num / million) + "M"; - } else if (num >= thousand) { - return std::to_string(num / thousand) + "K"; - } else { - return std::to_string(num); + double numDouble = (double)num; + int numDigits = (int)log10(num) + 1; + char suffix; + + if (num >= quadrillion || numDigits > 15) + { + numDouble /= quadrillion; + suffix = 'Q'; } -} + else if (num >= trillion || numDigits > 12) + { + numDouble /= trillion; + suffix = 'T'; + } + else if (num >= billion || numDigits > 9) + { + numDouble /= billion; + suffix = 'B'; + } + else if (num >= million || numDigits > 6) + { + numDouble /= million; + suffix = 'M'; + } + else if (num >= thousand || numDigits > 3) + { + numDouble /= thousand; + suffix = 'K'; + } + else + { + sprintf(result, "%llu", (unsigned long long)num); + return result; + } + + // Add suffix + int len = snprintf(result, sizeof(result), "%.0f%c", numDouble, suffix); + + // If there's room, add decimal places + if (len < numCharacters) + { + snprintf(result, sizeof(result), "%.*f%c", numCharacters - len - 1, numDouble, suffix); + } + + return result; +} \ No newline at end of file diff --git a/lib/btclock/utils.hpp b/lib/btclock/utils.hpp index b44c978..db338c0 100644 --- a/lib/btclock/utils.hpp +++ b/lib/btclock/utils.hpp @@ -3,9 +3,11 @@ #include #include #include +#include +#include int modulo(int x,int N); double getSupplyAtBlock(std::uint32_t blockNr); -std::string formatNumberWithSuffix(std::uint64_t num); \ No newline at end of file +std::string formatNumberWithSuffix(std::uint64_t num, int numCharacters = 4); \ No newline at end of file diff --git a/src/fonts/antonio-semibold90.h b/src/fonts/antonio-semibold90.h index 123e4ab..b55d5df 100644 --- a/src/fonts/antonio-semibold90.h +++ b/src/fonts/antonio-semibold90.h @@ -5046,7 +5046,7 @@ const GFXglyph Antonio_SemiBold90pt7bGlyphs[] PROGMEM = { {9988, 53, 55, 63, 5, -94}, // 0x2B '+' {10353, 23, 50, 41, 10, -20}, // 0x2C ',' {10497, 39, 14, 60, 8, -75}, // 0x2D '-' - {10566, 17, 19, 46, 14, -18}, // 0x2E '.' + {10566, 17, 19, 46, 14, 106}, // 0x2E '.' {10607, 55, 152, 66, 6, 105}, // 0x2F '/' {11652, 59, 155, 79, 10, 104}, // 0x30 '0' {12796, 41, 151, 67, 8, 106}, // 0x31 '1' diff --git a/src/fonts/fonts.hpp b/src/fonts/fonts.hpp index 01ef327..1504d45 100644 --- a/src/fonts/fonts.hpp +++ b/src/fonts/fonts.hpp @@ -4,6 +4,8 @@ #include "antonio-semibold30.h" #include "antonio-semibold40.h" #include "antonio-semibold90.h" +#include "sats-symbol.h" + // #include "oswald-20.h" // #include "oswald-30.h" // #include "oswald-90.h" diff --git a/src/fonts/sats-symbol.h b/src/fonts/sats-symbol.h new file mode 100644 index 0000000..d21a9a5 --- /dev/null +++ b/src/fonts/sats-symbol.h @@ -0,0 +1,201 @@ +const uint8_t Satoshi_Symbol90pt7bBitmaps[] PROGMEM = { + 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, + 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFE, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, + 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF8, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFE, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFE, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, + 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, + 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, + 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, + 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, + 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, + 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, + 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, + 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, + 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, + 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, + 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, + 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, + 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xE0 }; + +const GFXglyph Satoshi_Symbol90pt7bGlyphs[] PROGMEM = { + { 0, 82, 127, 99, 8, -126 }, { 1302, 71, 109, 93, 0, -117 } }; // 0x53 'S' + +const GFXfont Satoshi_Symbol90pt7b PROGMEM = { + (uint8_t *)Satoshi_Symbol90pt7bBitmaps, + (GFXglyph *)Satoshi_Symbol90pt7bGlyphs, + 0x53, 0x53, 192 }; + +// Approx. 2284 bytes diff --git a/src/lib/block_notify.cpp b/src/lib/block_notify.cpp index 56a2df2..897d7dd 100644 --- a/src/lib/block_notify.cpp +++ b/src/lib/block_notify.cpp @@ -162,8 +162,7 @@ void onWebsocketMessage(esp_websocket_event_data_t *event_data) { } } - if (getCurrentScreen() == SCREEN_BLOCK_HEIGHT && - preferences.getBool("ledFlashOnUpd", false)) { + if (preferences.getBool("ledFlashOnUpd", false)) { vTaskDelay(pdMS_TO_TICKS(250)); // Wait until screens are updated queueLedEffect(LED_FLASH_BLOCK_NOTIFY); } diff --git a/src/lib/config.cpp b/src/lib/config.cpp index 09cf4fc..068f8fb 100644 --- a/src/lib/config.cpp +++ b/src/lib/config.cpp @@ -10,16 +10,19 @@ Adafruit_MCP23X17 mcp2; std::vector screenNameMap(SCREEN_COUNT); std::mutex mcpMutex; -void setup() { +void setup() +{ setupPreferences(); setupHardware(); setupDisplays(); - if (preferences.getBool("ledTestOnPower", true)) { + if (preferences.getBool("ledTestOnPower", true)) + { queueLedEffect(LED_POWER_TEST); } { std::lock_guard lockMcp(mcpMutex); - if (mcp1.digitalRead(3) == LOW) { + if (mcp1.digitalRead(3) == LOW) + { preferences.putBool("wifiConfigured", false); preferences.remove("txPower"); @@ -49,12 +52,25 @@ void setup() { forceFullRefresh(); } -void tryImprovSetup() { +void tryImprovSetup() +{ WiFi.onEvent(WiFiEvent); + WiFi.setAutoConnect(true); + WiFi.setAutoReconnect(true); + WiFi.begin(); + if (preferences.getInt("txPower", 0)) + { + if (WiFi.setTxPower( + static_cast(preferences.getInt("txPower", 0)))) + { + Serial.printf("WiFi max tx power set to %d\n", + preferences.getInt("txPower", 0)); + } + } + + // if (!preferences.getBool("wifiConfigured", false)) + { - if (!preferences.getBool("wifiConfigured", false)) { - setFgColor(GxEPD_BLACK); - setBgColor(GxEPD_WHITE); queueLedEffect(LED_EFFECT_WIFI_WAIT_FOR_CONFIG); uint8_t x_buffer[16]; @@ -84,13 +100,15 @@ void tryImprovSetup() { wm.setDebugOutput(false); wm.setConfigPortalBlocking(true); - wm.setAPCallback([&](WiFiManager *wifiManager) { + wm.setAPCallback([&](WiFiManager *wifiManager) + { // Serial.printf("Entered config mode:ip=%s, ssid='%s', pass='%s'\n", // WiFi.softAPIP().toString().c_str(), // wifiManager->getConfigPortalSSID().c_str(), // softAP_password.c_str()); // delay(6000); - + setFgColor(GxEPD_BLACK); + setBgColor(GxEPD_WHITE); const String qrText = "qrWIFI:S:" + wifiManager->getConfigPortalSSID() + ";T:WPA;P:" + softAP_password.c_str() + ";;"; const String explainText = "*SSID: *\r\n" + @@ -102,18 +120,17 @@ void tryImprovSetup() { "To setup\r\nscan QR or\r\nconnect\r\nmanually", "Para\r\nconfigurar\r\nescanear QR\r\no conectar\r\nmanualmente", explainText, - " ", + "*Hostname*:\r\n" + getMyHostname(), qrText}; - setEpdContent(epdContent); - }); + setEpdContent(epdContent); }); - wm.setSaveConfigCallback([]() { + wm.setSaveConfigCallback([]() + { preferences.putBool("wifiConfigured", true); delay(1000); // just restart after succes - ESP.restart(); - }); + ESP.restart(); }); bool ac = wm.autoConnect(softAP_SSID.c_str(), softAP_password.c_str()); @@ -154,31 +171,26 @@ void tryImprovSetup() { } setFgColor(preferences.getUInt("fgColor", DEFAULT_FG_COLOR)); setBgColor(preferences.getUInt("bgColor", DEFAULT_BG_COLOR)); - } else { - WiFi.setAutoConnect(true); - WiFi.setAutoReconnect(true); - WiFi.begin(); - if (preferences.getInt("txPower", 0)) { - if (WiFi.setTxPower( - static_cast(preferences.getInt("txPower", 0)))) { - Serial.printf("WiFi max tx power set to %d\n", - preferences.getInt("txPower", 0)); - } - } - - while (WiFi.status() != WL_CONNECTED) { - vTaskDelay(pdMS_TO_TICKS(400)); - } } + // else + // { + + // while (WiFi.status() != WL_CONNECTED) + // { + // vTaskDelay(pdMS_TO_TICKS(400)); + // } + // } // queueLedEffect(LED_EFFECT_WIFI_CONNECT_SUCCESS); } -void setupTime() { +void setupTime() +{ configTime(preferences.getInt("gmtOffset", TIME_OFFSET_SECONDS), 0, NTP_SERVER); struct tm timeinfo; - while (!getLocalTime(&timeinfo)) { + while (!getLocalTime(&timeinfo)) + { configTime(preferences.getInt("gmtOffset", TIME_OFFSET_SECONDS), 0, NTP_SERVER); delay(500); @@ -186,7 +198,8 @@ void setupTime() { } } -void setupPreferences() { +void setupPreferences() +{ preferences.begin("btclock", false); setFgColor(preferences.getUInt("fgColor", DEFAULT_FG_COLOR)); @@ -202,36 +215,46 @@ void setupPreferences() { screenNameMap[SCREEN_MARKET_CAP] = "Market Cap"; } -void setupWebsocketClients(void *pvParameters) { +void setupWebsocketClients(void *pvParameters) +{ setupBlockNotify(); - if (preferences.getBool("fetchEurPrice", false)) { + if (preferences.getBool("fetchEurPrice", false)) + { setupPriceFetchTask(); - } else { + } + else + { setupPriceNotify(); } vTaskDelete(NULL); } -void setupTimers() { +void setupTimers() +{ xTaskCreate(setupTimeUpdateTimer, "setupTimeUpdateTimer", 2048, NULL, tskIDLE_PRIORITY, NULL); xTaskCreate(setupScreenRotateTimer, "setupScreenRotateTimer", 2048, NULL, tskIDLE_PRIORITY, NULL); } -void finishSetup() { - if (preferences.getBool("ledStatus", false)) { +void finishSetup() +{ + if (preferences.getBool("ledStatus", false)) + { restoreLedState(); - } else { + } + else + { clearLeds(); } } std::vector getScreenNameMap() { return screenNameMap; } -void setupMcp() { +void setupMcp() +{ #ifdef IS_BTCLOCK_S3 const int mcp1AddrPins[] = {MCP1_A0_PIN, MCP1_A1_PIN, MCP1_A2_PIN}; const int mcp1AddrValues[] = {LOW, LOW, LOW}; @@ -242,7 +265,8 @@ void setupMcp() { pinMode(MCP_RESET_PIN, OUTPUT); digitalWrite(MCP_RESET_PIN, HIGH); - for (int i = 0; i < 3; ++i) { + for (int i = 0; i < 3; ++i) + { pinMode(mcp1AddrPins[i], OUTPUT); digitalWrite(mcp1AddrPins[i], mcp1AddrValues[i]); @@ -256,19 +280,23 @@ void setupMcp() { #endif } -void setupHardware() { - if (!LittleFS.begin(true)) { +void setupHardware() +{ + if (!LittleFS.begin(true)) + { Serial.println(F("An Error has occurred while mounting LittleFS")); } - if (!LittleFS.open("/index.html.gz", "r")) { + if (!LittleFS.open("/index.html.gz", "r")) + { Serial.println("Error loading WebUI"); } setupLeds(); WiFi.setHostname(getMyHostname().c_str()); - if (!psramInit()) { + if (!psramInit()) + { Serial.println(F("PSRAM not available")); } @@ -276,28 +304,34 @@ void setupHardware() { Wire.begin(I2C_SDA_PIN, I2C_SCK_PIN, 400000); - if (!mcp1.begin_I2C(0x20)) { + if (!mcp1.begin_I2C(0x20)) + { Serial.println(F("Error MCP23017")); // while (1) // ; - } else { + } + else + { pinMode(MCP_INT_PIN, INPUT_PULLUP); mcp1.setupInterrupts(false, false, LOW); - for (int i = 0; i < 4; i++) { + for (int i = 0; i < 4; i++) + { mcp1.pinMode(i, INPUT_PULLUP); mcp1.setupInterruptPin(i, LOW); } #ifndef IS_BTCLOCK_S3 - for (int i = 8; i <= 14; i++) { + for (int i = 8; i <= 14; i++) + { mcp1.pinMode(i, OUTPUT); } #endif } #ifdef IS_BTCLOCK_S3 - if (!mcp2.begin_I2C(0x21)) { + if (!mcp2.begin_I2C(0x21)) + { Serial.println(F("Error MCP23017")); // while (1) @@ -306,10 +340,12 @@ void setupHardware() { #endif } -void improvGetAvailableWifiNetworks() { +void improvGetAvailableWifiNetworks() +{ int networkNum = WiFi.scanNetworks(); - for (int id = 0; id < networkNum; ++id) { + for (int id = 0; id < networkNum; ++id) + { std::vector data = improv::build_rpc_response( improv::GET_WIFI_NETWORKS, {WiFi.SSID(id), String(WiFi.RSSI(id)), @@ -323,15 +359,18 @@ void improvGetAvailableWifiNetworks() { improv_send_response(data); } -bool improv_connectWifi(std::string ssid, std::string password) { +bool improv_connectWifi(std::string ssid, std::string password) +{ uint8_t count = 0; WiFi.begin(ssid.c_str(), password.c_str()); - while (WiFi.status() != WL_CONNECTED) { + while (WiFi.status() != WL_CONNECTED) + { blinkDelay(500, 2); - if (count > MAX_ATTEMPTS_WIFI_CONNECTION) { + if (count > MAX_ATTEMPTS_WIFI_CONNECTION) + { WiFi.disconnect(); return false; } @@ -341,7 +380,8 @@ bool improv_connectWifi(std::string ssid, std::string password) { return true; } -void onImprovErrorCallback(improv::Error err) { +void onImprovErrorCallback(improv::Error err) +{ blinkDelayColor(100, 1, 255, 0, 0); // pixels.setPixelColor(0, pixels.Color(255, 0, 0)); // pixels.setPixelColor(1, pixels.Color(255, 0, 0)); @@ -355,94 +395,110 @@ void onImprovErrorCallback(improv::Error err) { // vTaskDelay(pdMS_TO_TICKS(100)); } -std::vector getLocalUrl() { +std::vector getLocalUrl() +{ return {// URL where user can finish onboarding or use device // Recommended to use website hosted by device String("http://" + WiFi.localIP().toString()).c_str()}; } -bool onImprovCommandCallback(improv::ImprovCommand cmd) { - switch (cmd.command) { - case improv::Command::GET_CURRENT_STATE: { - if ((WiFi.status() == WL_CONNECTED)) { - improv_set_state(improv::State::STATE_PROVISIONED); - std::vector data = improv::build_rpc_response( - improv::GET_CURRENT_STATE, getLocalUrl(), false); - improv_send_response(data); - } else { - improv_set_state(improv::State::STATE_AUTHORIZED); - } - - break; - } - - case improv::Command::WIFI_SETTINGS: { - if (cmd.ssid.length() == 0) { - improv_set_error(improv::Error::ERROR_INVALID_RPC); - break; - } - - improv_set_state(improv::STATE_PROVISIONING); - queueLedEffect(LED_EFFECT_WIFI_CONNECTING); - - if (improv_connectWifi(cmd.ssid, cmd.password)) { - queueLedEffect(LED_EFFECT_WIFI_CONNECT_SUCCESS); - - // std::array epdContent = {"S", "U", "C", "C", - // "E", "S", "S"}; setEpdContent(epdContent); - - preferences.putBool("wifiConfigured", true); - - improv_set_state(improv::STATE_PROVISIONED); - std::vector data = improv::build_rpc_response( - improv::WIFI_SETTINGS, getLocalUrl(), false); - improv_send_response(data); - - delay(2500); - ESP.restart(); - setupWebserver(); - } else { - queueLedEffect(LED_EFFECT_WIFI_CONNECT_ERROR); - - improv_set_state(improv::STATE_STOPPED); - improv_set_error(improv::Error::ERROR_UNABLE_TO_CONNECT); - } - - break; - } - - case improv::Command::GET_DEVICE_INFO: { - std::vector infos = {// Firmware name - "BTClock", - // Firmware version - "1.0.0", - // Hardware chip/variant - "ESP32S3", - // Device name - "BTClock"}; - std::vector data = - improv::build_rpc_response(improv::GET_DEVICE_INFO, infos, false); +bool onImprovCommandCallback(improv::ImprovCommand cmd) +{ + switch (cmd.command) + { + case improv::Command::GET_CURRENT_STATE: + { + if ((WiFi.status() == WL_CONNECTED)) + { + improv_set_state(improv::State::STATE_PROVISIONED); + std::vector data = improv::build_rpc_response( + improv::GET_CURRENT_STATE, getLocalUrl(), false); improv_send_response(data); + } + else + { + improv_set_state(improv::State::STATE_AUTHORIZED); + } + + break; + } + + case improv::Command::WIFI_SETTINGS: + { + if (cmd.ssid.length() == 0) + { + improv_set_error(improv::Error::ERROR_INVALID_RPC); break; } - case improv::Command::GET_WIFI_NETWORKS: { - improvGetAvailableWifiNetworks(); - // std::array epdContent = {"W", "E", "B", "W", "I", - // "F", "I"}; setEpdContent(epdContent); - break; + improv_set_state(improv::STATE_PROVISIONING); + queueLedEffect(LED_EFFECT_WIFI_CONNECTING); + + if (improv_connectWifi(cmd.ssid, cmd.password)) + { + queueLedEffect(LED_EFFECT_WIFI_CONNECT_SUCCESS); + + // std::array epdContent = {"S", "U", "C", "C", + // "E", "S", "S"}; setEpdContent(epdContent); + + preferences.putBool("wifiConfigured", true); + + improv_set_state(improv::STATE_PROVISIONED); + std::vector data = improv::build_rpc_response( + improv::WIFI_SETTINGS, getLocalUrl(), false); + improv_send_response(data); + + delay(2500); + ESP.restart(); + setupWebserver(); + } + else + { + queueLedEffect(LED_EFFECT_WIFI_CONNECT_ERROR); + + improv_set_state(improv::STATE_STOPPED); + improv_set_error(improv::Error::ERROR_UNABLE_TO_CONNECT); } - default: { - improv_set_error(improv::ERROR_UNKNOWN_RPC); - return false; - } + break; + } + + case improv::Command::GET_DEVICE_INFO: + { + std::vector infos = {// Firmware name + "BTClock", + // Firmware version + "1.0.0", + // Hardware chip/variant + "ESP32S3", + // Device name + "BTClock"}; + std::vector data = + improv::build_rpc_response(improv::GET_DEVICE_INFO, infos, false); + improv_send_response(data); + break; + } + + case improv::Command::GET_WIFI_NETWORKS: + { + improvGetAvailableWifiNetworks(); + // std::array epdContent = {"W", "E", "B", "W", "I", + // "F", "I"}; setEpdContent(epdContent); + break; + } + + default: + { + improv_set_error(improv::ERROR_UNKNOWN_RPC); + return false; + } } return true; } -void improv_set_state(improv::State state) { +void improv_set_state(improv::State state) +{ std::vector data = {'I', 'M', 'P', 'R', 'O', 'V'}; data.resize(11); data[6] = improv::IMPROV_SERIAL_VERSION; @@ -451,13 +507,15 @@ void improv_set_state(improv::State state) { data[9] = state; uint8_t checksum = 0x00; - for (uint8_t d : data) checksum += d; + for (uint8_t d : data) + checksum += d; data[10] = checksum; Serial.write(data.data(), data.size()); } -void improv_send_response(std::vector &response) { +void improv_send_response(std::vector &response) +{ std::vector data = {'I', 'M', 'P', 'R', 'O', 'V'}; data.resize(9); data[6] = improv::IMPROV_SERIAL_VERSION; @@ -466,13 +524,15 @@ void improv_send_response(std::vector &response) { data.insert(data.end(), response.begin(), response.end()); uint8_t checksum = 0x00; - for (uint8_t d : data) checksum += d; + for (uint8_t d : data) + checksum += d; data.push_back(checksum); Serial.write(data.data(), data.size()); } -void improv_set_error(improv::Error error) { +void improv_set_error(improv::Error error) +{ std::vector data = {'I', 'M', 'P', 'R', 'O', 'V'}; data.resize(11); data[6] = improv::IMPROV_SERIAL_VERSION; @@ -481,89 +541,97 @@ void improv_set_error(improv::Error error) { data[9] = error; uint8_t checksum = 0x00; - for (uint8_t d : data) checksum += d; + for (uint8_t d : data) + checksum += d; data[10] = checksum; Serial.write(data.data(), data.size()); } -void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) { +void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) +{ static bool first_connect = true; Serial.printf("[WiFi-event] event: %d\n", event); - switch (event) { - case ARDUINO_EVENT_WIFI_READY: - Serial.println("WiFi interface ready"); - break; - case ARDUINO_EVENT_WIFI_SCAN_DONE: - Serial.println("Completed scan for access points"); - break; - case ARDUINO_EVENT_WIFI_STA_START: - Serial.println("WiFi client started"); - break; - case ARDUINO_EVENT_WIFI_STA_STOP: - Serial.println("WiFi clients stopped"); - break; - case ARDUINO_EVENT_WIFI_STA_CONNECTED: - Serial.println("Connected to access point"); - break; - case ARDUINO_EVENT_WIFI_STA_DISCONNECTED: { - if (!first_connect) { - Serial.println("Disconnected from WiFi access point"); - queueLedEffect(LED_EFFECT_WIFI_CONNECT_ERROR); - uint8_t reason = info.wifi_sta_disconnected.reason; - if (reason) - Serial.printf("Disconnect reason: %s, ", - WiFi.disconnectReasonName((wifi_err_reason_t)reason)); - } - break; - } - case ARDUINO_EVENT_WIFI_STA_AUTHMODE_CHANGE: - Serial.println("Authentication mode of access point has changed"); - break; - case ARDUINO_EVENT_WIFI_STA_GOT_IP: { - Serial.print("Obtained IP address: "); - Serial.println(WiFi.localIP()); - if (!first_connect) queueLedEffect(LED_EFFECT_WIFI_CONNECT_SUCCESS); - first_connect = false; - break; - } - case ARDUINO_EVENT_WIFI_STA_LOST_IP: - Serial.println("Lost IP address and IP address is reset to 0"); + switch (event) + { + case ARDUINO_EVENT_WIFI_READY: + Serial.println("WiFi interface ready"); + break; + case ARDUINO_EVENT_WIFI_SCAN_DONE: + Serial.println("Completed scan for access points"); + break; + case ARDUINO_EVENT_WIFI_STA_START: + Serial.println("WiFi client started"); + break; + case ARDUINO_EVENT_WIFI_STA_STOP: + Serial.println("WiFi clients stopped"); + break; + case ARDUINO_EVENT_WIFI_STA_CONNECTED: + Serial.println("Connected to access point"); + break; + case ARDUINO_EVENT_WIFI_STA_DISCONNECTED: + { + if (!first_connect) + { + Serial.println("Disconnected from WiFi access point"); queueLedEffect(LED_EFFECT_WIFI_CONNECT_ERROR); - WiFi.reconnect(); - break; - case ARDUINO_EVENT_WIFI_AP_START: - Serial.println("WiFi access point started"); - break; - case ARDUINO_EVENT_WIFI_AP_STOP: - Serial.println("WiFi access point stopped"); - break; - case ARDUINO_EVENT_WIFI_AP_STACONNECTED: - Serial.println("Client connected"); - break; - case ARDUINO_EVENT_WIFI_AP_STADISCONNECTED: - Serial.println("Client disconnected"); - break; - case ARDUINO_EVENT_WIFI_AP_STAIPASSIGNED: - Serial.println("Assigned IP address to client"); - break; - case ARDUINO_EVENT_WIFI_AP_PROBEREQRECVED: - Serial.println("Received probe request"); - break; - case ARDUINO_EVENT_WIFI_AP_GOT_IP6: - Serial.println("AP IPv6 is preferred"); - break; - case ARDUINO_EVENT_WIFI_STA_GOT_IP6: - Serial.println("STA IPv6 is preferred"); - break; - default: - break; + uint8_t reason = info.wifi_sta_disconnected.reason; + if (reason) + Serial.printf("Disconnect reason: %s, ", + WiFi.disconnectReasonName((wifi_err_reason_t)reason)); + } + break; + } + case ARDUINO_EVENT_WIFI_STA_AUTHMODE_CHANGE: + Serial.println("Authentication mode of access point has changed"); + break; + case ARDUINO_EVENT_WIFI_STA_GOT_IP: + { + Serial.print("Obtained IP address: "); + Serial.println(WiFi.localIP()); + if (!first_connect) + queueLedEffect(LED_EFFECT_WIFI_CONNECT_SUCCESS); + first_connect = false; + break; + } + case ARDUINO_EVENT_WIFI_STA_LOST_IP: + Serial.println("Lost IP address and IP address is reset to 0"); + queueLedEffect(LED_EFFECT_WIFI_CONNECT_ERROR); + WiFi.reconnect(); + break; + case ARDUINO_EVENT_WIFI_AP_START: + Serial.println("WiFi access point started"); + break; + case ARDUINO_EVENT_WIFI_AP_STOP: + Serial.println("WiFi access point stopped"); + break; + case ARDUINO_EVENT_WIFI_AP_STACONNECTED: + Serial.println("Client connected"); + break; + case ARDUINO_EVENT_WIFI_AP_STADISCONNECTED: + Serial.println("Client disconnected"); + break; + case ARDUINO_EVENT_WIFI_AP_STAIPASSIGNED: + Serial.println("Assigned IP address to client"); + break; + case ARDUINO_EVENT_WIFI_AP_PROBEREQRECVED: + Serial.println("Received probe request"); + break; + case ARDUINO_EVENT_WIFI_AP_GOT_IP6: + Serial.println("AP IPv6 is preferred"); + break; + case ARDUINO_EVENT_WIFI_STA_GOT_IP6: + Serial.println("STA IPv6 is preferred"); + break; + default: + break; } } -String getMyHostname() { +String getMyHostname() +{ uint8_t mac[6]; // WiFi.macAddress(mac); esp_efuse_mac_get_default(mac); diff --git a/src/lib/epd.cpp b/src/lib/epd.cpp index 921cc44..92d13d3 100644 --- a/src/lib/epd.cpp +++ b/src/lib/epd.cpp @@ -16,12 +16,21 @@ Native_Pin EPD_CS[NUM_SCREENS] = { #endif }; Native_Pin EPD_BUSY[NUM_SCREENS] = { - Native_Pin(3), Native_Pin(5), Native_Pin(7), Native_Pin(9), - Native_Pin(37), Native_Pin(18), Native_Pin(16), + Native_Pin(3), + Native_Pin(5), + Native_Pin(7), + Native_Pin(9), + Native_Pin(37), + Native_Pin(18), + Native_Pin(16), }; MCP23X17_Pin EPD_RESET_MPD[NUM_SCREENS] = { - MCP23X17_Pin(mcp1, 8), MCP23X17_Pin(mcp1, 9), MCP23X17_Pin(mcp1, 10), - MCP23X17_Pin(mcp1, 11), MCP23X17_Pin(mcp1, 12), MCP23X17_Pin(mcp1, 13), + MCP23X17_Pin(mcp1, 8), + MCP23X17_Pin(mcp1, 9), + MCP23X17_Pin(mcp1, 10), + MCP23X17_Pin(mcp1, 11), + MCP23X17_Pin(mcp1, 12), + MCP23X17_Pin(mcp1, 13), MCP23X17_Pin(mcp1, 14), }; @@ -30,20 +39,30 @@ Native_Pin EPD_DC = Native_Pin(14); Native_Pin EPD_DC = Native_Pin(38); MCP23X17_Pin EPD_BUSY[NUM_SCREENS] = { - MCP23X17_Pin(mcp1, 8), MCP23X17_Pin(mcp1, 9), MCP23X17_Pin(mcp1, 10), - MCP23X17_Pin(mcp1, 11), MCP23X17_Pin(mcp1, 12), MCP23X17_Pin(mcp1, 13), - MCP23X17_Pin(mcp1, 14), MCP23X17_Pin(mcp1, 4), + MCP23X17_Pin(mcp1, 8), + MCP23X17_Pin(mcp1, 9), + MCP23X17_Pin(mcp1, 10), + MCP23X17_Pin(mcp1, 11), + MCP23X17_Pin(mcp1, 12), + MCP23X17_Pin(mcp1, 13), + MCP23X17_Pin(mcp1, 14), + MCP23X17_Pin(mcp1, 4), }; MCP23X17_Pin EPD_CS[NUM_SCREENS] = { - MCP23X17_Pin(mcp2, 8), MCP23X17_Pin(mcp2, 10), MCP23X17_Pin(mcp2, 12), - MCP23X17_Pin(mcp2, 14), MCP23X17_Pin(mcp2, 0), MCP23X17_Pin(mcp2, 2), - MCP23X17_Pin(mcp2, 4), MCP23X17_Pin(mcp2, 6)}; + MCP23X17_Pin(mcp2, 8), MCP23X17_Pin(mcp2, 10), MCP23X17_Pin(mcp2, 12), + MCP23X17_Pin(mcp2, 14), MCP23X17_Pin(mcp2, 0), MCP23X17_Pin(mcp2, 2), + MCP23X17_Pin(mcp2, 4), MCP23X17_Pin(mcp2, 6)}; MCP23X17_Pin EPD_RESET_MPD[NUM_SCREENS] = { - MCP23X17_Pin(mcp2, 9), MCP23X17_Pin(mcp2, 11), MCP23X17_Pin(mcp2, 13), - MCP23X17_Pin(mcp2, 15), MCP23X17_Pin(mcp2, 1), MCP23X17_Pin(mcp2, 3), - MCP23X17_Pin(mcp2, 5), MCP23X17_Pin(mcp2, 7), + MCP23X17_Pin(mcp2, 9), + MCP23X17_Pin(mcp2, 11), + MCP23X17_Pin(mcp2, 13), + MCP23X17_Pin(mcp2, 15), + MCP23X17_Pin(mcp2, 1), + MCP23X17_Pin(mcp2, 3), + MCP23X17_Pin(mcp2, 5), + MCP23X17_Pin(mcp2, 7), }; #endif @@ -78,24 +97,30 @@ int bgColor = GxEPD_BLACK; #define FONT_SMALL Antonio_SemiBold20pt7b #define FONT_BIG Antonio_SemiBold90pt7b #define FONT_MEDIUM Antonio_SemiBold40pt7b +#define FONT_SATSYMBOL Satoshi_Symbol90pt7b std::mutex epdUpdateMutex; std::mutex epdMutex[NUM_SCREENS]; uint8_t qrcode[800]; -void forceFullRefresh() { - for (uint i = 0; i < NUM_SCREENS; i++) { +void forceFullRefresh() +{ + for (uint i = 0; i < NUM_SCREENS; i++) + { lastFullRefresh[i] = NULL; } } -void refreshFromMemory() { - for (uint i = 0; i < NUM_SCREENS; i++) { +void refreshFromMemory() +{ + for (uint i = 0; i < NUM_SCREENS; i++) + { int *taskParam = new int; *taskParam = i; xTaskCreate( - [](void *pvParameters) { + [](void *pvParameters) + { const int epdIndex = *(int *)pvParameters; delete (int *)pvParameters; displays[epdIndex].refresh(false); @@ -105,10 +130,12 @@ void refreshFromMemory() { } } -void setupDisplays() { +void setupDisplays() +{ std::lock_guard lockMcp(mcpMutex); - for (uint i = 0; i < NUM_SCREENS; i++) { + for (uint i = 0; i < NUM_SCREENS; i++) + { displays[i].init(0, true, 30); } @@ -116,7 +143,8 @@ void setupDisplays() { xTaskCreate(prepareDisplayUpdateTask, "PrepareUpd", 4096, NULL, 11, NULL); - for (uint i = 0; i < NUM_SCREENS; i++) { + for (uint i = 0; i < NUM_SCREENS; i++) + { // epdUpdateSemaphore[i] = xSemaphoreCreateBinary(); // xSemaphoreGive(epdUpdateSemaphore[i]); @@ -124,7 +152,7 @@ void setupDisplays() { *taskParam = i; xTaskCreate(updateDisplay, ("EpdUpd" + String(i)).c_str(), 2048, taskParam, - 11, &tasks[i]); // create task + 11, &tasks[i]); // create task } epdContent = {"B", "T", "C", "L", "O", "C", "K"}; @@ -132,14 +160,17 @@ void setupDisplays() { setEpdContent(epdContent); } -void setEpdContent(std::array newEpdContent) { +void setEpdContent(std::array newEpdContent) +{ setEpdContent(newEpdContent, false); } -void setEpdContent(std::array newEpdContent) { +void setEpdContent(std::array newEpdContent) +{ std::array conv; - for (size_t i = 0; i < newEpdContent.size(); ++i) { + for (size_t i = 0; i < newEpdContent.size(); ++i) + { conv[i] = String(newEpdContent[i].c_str()); } @@ -147,13 +178,16 @@ void setEpdContent(std::array newEpdContent) { } void setEpdContent(std::array newEpdContent, - bool forceUpdate) { + bool forceUpdate) +{ std::lock_guard lock(epdUpdateMutex); waitUntilNoneBusy(); - for (uint i = 0; i < NUM_SCREENS; i++) { - if (newEpdContent[i].compareTo(currentEpdContent[i]) != 0 || forceUpdate) { + for (uint i = 0; i < NUM_SCREENS; i++) + { + if (newEpdContent[i].compareTo(currentEpdContent[i]) != 0 || forceUpdate) + { epdContent[i] = newEpdContent[i]; UpdateDisplayTaskItem dispUpdate = {i}; xQueueSend(updateQueue, &dispUpdate, portMAX_DELAY); @@ -161,12 +195,15 @@ void setEpdContent(std::array newEpdContent, } } -void prepareDisplayUpdateTask(void *pvParameters) { +void prepareDisplayUpdateTask(void *pvParameters) +{ UpdateDisplayTaskItem receivedItem; - while (1) { + while (1) + { // Wait for a work item to be available in the queue - if (xQueueReceive(updateQueue, &receivedItem, portMAX_DELAY)) { + if (xQueueReceive(updateQueue, &receivedItem, portMAX_DELAY)) + { uint epdIndex = receivedItem.dispNum; std::lock_guard lock(epdMutex[epdIndex]); // displays[epdIndex].init(0, false); // Little longer reset duration @@ -174,23 +211,43 @@ void prepareDisplayUpdateTask(void *pvParameters) { bool updatePartial = true; - if (strstr(epdContent[epdIndex].c_str(), "/") != NULL) { + if (strstr(epdContent[epdIndex].c_str(), "/") != NULL) + { String top = epdContent[epdIndex].substring( 0, epdContent[epdIndex].indexOf("/")); String bottom = epdContent[epdIndex].substring( epdContent[epdIndex].indexOf("/") + 1); splitText(epdIndex, top, bottom, updatePartial); - } else if (epdContent[epdIndex].startsWith(F("qr"))) { + } + else if (epdContent[epdIndex].startsWith(F("qr"))) + { renderQr(epdIndex, epdContent[epdIndex], updatePartial); - } else if (epdContent[epdIndex].length() > 5) { + } + else if (epdContent[epdIndex].length() > 5) + { renderText(epdIndex, epdContent[epdIndex], updatePartial); - } else { - if (epdContent[epdIndex].length() > 1) { - showChars(epdIndex, epdContent[epdIndex], updatePartial, - &FONT_MEDIUM); - } else { + } + else + { + if (epdContent[epdIndex].length() > 1 && epdContent[epdIndex].indexOf(".") == -1) + { + if (epdContent[epdIndex].equals("STS")) + { + showDigit(epdIndex, 'S', updatePartial, + &FONT_SATSYMBOL); + } + else + { + showChars(epdIndex, epdContent[epdIndex], updatePartial, + &FONT_MEDIUM); + } + } + else + { + showDigit(epdIndex, epdContent[epdIndex].c_str()[0], updatePartial, &FONT_BIG); + } } @@ -199,11 +256,13 @@ void prepareDisplayUpdateTask(void *pvParameters) { } } -extern "C" void updateDisplay(void *pvParameters) noexcept { +extern "C" void updateDisplay(void *pvParameters) noexcept +{ const int epdIndex = *(int *)pvParameters; delete (int *)pvParameters; - for (;;) { + for (;;) + { // Wait for the task notification ulTaskNotifyTake(pdTRUE, portMAX_DELAY); @@ -215,7 +274,8 @@ extern "C" void updateDisplay(void *pvParameters) noexcept { displays[epdIndex].init(0, false, 40); } uint count = 0; - while (EPD_BUSY[epdIndex].digitalRead() == HIGH || count < 10) { + while (EPD_BUSY[epdIndex].digitalRead() == HIGH || count < 10) + { vTaskDelay(pdMS_TO_TICKS(100)); count++; } @@ -227,16 +287,20 @@ extern "C" void updateDisplay(void *pvParameters) noexcept { (millis() - lastFullRefresh[epdIndex]) > (preferences.getUInt("fullRefreshMin", DEFAULT_MINUTES_FULL_REFRESH) * - 60 * 1000)) { + 60 * 1000)) + { updatePartial = false; } char tries = 0; - while (tries < 3) { - if (displays[epdIndex].displayWithReturn(updatePartial)) { + while (tries < 3) + { + if (displays[epdIndex].displayWithReturn(updatePartial)) + { displays[epdIndex].powerOff(); currentEpdContent[epdIndex] = epdContent[epdIndex]; - if (!updatePartial) lastFullRefresh[epdIndex] = millis(); + if (!updatePartial) + lastFullRefresh[epdIndex] = millis(); if (eventSourceTaskHandle != NULL) xTaskNotifyGive(eventSourceTaskHandle); @@ -251,7 +315,8 @@ extern "C" void updateDisplay(void *pvParameters) noexcept { } void splitText(const uint dispNum, const String &top, const String &bottom, - bool partial) { + bool partial) +{ displays[dispNum].setRotation(2); displays[dispNum].setFont(&FONT_SMALL); displays[dispNum].setTextColor(getFgColor()); @@ -290,24 +355,67 @@ void splitText(const uint dispNum, const String &top, const String &bottom, } void showDigit(const uint dispNum, char chr, bool partial, - const GFXfont *font) { + const GFXfont *font) +{ String str(chr); + + if (chr == '.') + { + str = "!"; + } displays[dispNum].setRotation(2); displays[dispNum].setFont(font); displays[dispNum].setTextColor(getFgColor()); int16_t tbx, tby; uint16_t tbw, tbh; + displays[dispNum].getTextBounds(str, 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; + + // if (str.equals(".")) + // { + // // int16_t yAdvance = font->yAdvance; + // // uint8_t charIndex = 46 - font->first; + // // GFXglyph *glyph = (&font->glyph)[charIndex]; + // int16_t tbx2, tby2; + // uint16_t tbw2, tbh2; + // displays[dispNum].getTextBounds(".!", 0, 0, &tbx2, &tby2, &tbw2, &tbh2); + + // y = ((displays[dispNum].height() - tbh2) / 2) - tby2; + // // Serial.print("yAdvance"); + // // Serial.println(yAdvance); + // // if (glyph != nullptr) { + // // Serial.print("height"); + // // Serial.println(glyph->height); + // // Serial.print("yOffset"); + // // Serial.println(glyph->yOffset); + // // } + + // // y = 250-99+18+19; + // } + displays[dispNum].fillScreen(getBgColor()); + displays[dispNum].setCursor(x, y); displays[dispNum].print(str); + + if (chr == '.') + { + displays[dispNum].fillRect(x,y,displays[dispNum].width(),round(displays[dispNum].height() * 0.9), getBgColor()); + } + + // displays[dispNum].setCursor(10, 3); + // displays[dispNum].setFont(&FONT_SMALL); + // displays[dispNum].setTextColor(getFgColor()); + // displays[dispNum].println("Y = " + y); } void showChars(const uint dispNum, const String &chars, bool partial, - const GFXfont *font) { + const GFXfont *font) +{ displays[dispNum].setRotation(2); displays[dispNum].setFont(font); displays[dispNum].setTextColor(getFgColor()); @@ -330,10 +438,12 @@ void setBgColor(int color) { bgColor = color; } void setFgColor(int color) { fgColor = color; } -std::array getCurrentEpdContent() { +std::array getCurrentEpdContent() +{ return currentEpdContent; } -void renderText(const uint dispNum, const String &text, bool partial) { +void renderText(const uint dispNum, const String &text, bool partial) +{ displays[dispNum].setRotation(2); displays[dispNum].setPartialWindow(0, 0, displays[dispNum].width(), displays[dispNum].height()); @@ -346,20 +456,25 @@ void renderText(const uint dispNum, const String &text, bool partial) { std::string line; - while (std::getline(ss, line, '\n')) { - if (line.rfind("*", 0) == 0) { + while (std::getline(ss, line, '\n')) + { + if (line.rfind("*", 0) == 0) + { line.erase(std::remove(line.begin(), line.end(), '*'), line.end()); displays[dispNum].setFont(&FreeSansBold9pt7b); displays[dispNum].println(line.c_str()); - } else { + } + else + { displays[dispNum].setFont(&FreeSans9pt7b); displays[dispNum].println(line.c_str()); } } } -void renderQr(const uint dispNum, const String &text, bool partial) { +void renderQr(const uint dispNum, const String &text, bool partial) +{ #ifdef USE_QR uint8_t tempBuffer[800]; @@ -379,8 +494,10 @@ void renderQr(const uint dispNum, const String &text, bool partial) { displays[dispNum].fillScreen(GxEPD_WHITE); const int border = 0; - for (int y = -border; y < size * 4 + border; y++) { - for (int x = -border; x < size * 4 + border; x++) { + for (int y = -border; y < size * 4 + border; y++) + { + for (int x = -border; x < size * 4 + border; x++) + { displays[dispNum].drawPixel( padding + x, paddingY + y, qrcodegen_getModule(qrcode, floor(float(x) / 4), floor(float(y) / 4)) @@ -391,16 +508,22 @@ void renderQr(const uint dispNum, const String &text, bool partial) { #endif } -void waitUntilNoneBusy() { - for (int i = 0; i < NUM_SCREENS; i++) { +void waitUntilNoneBusy() +{ + for (int i = 0; i < NUM_SCREENS; i++) + { uint count = 0; - while (EPD_BUSY[i].digitalRead()) { + while (EPD_BUSY[i].digitalRead()) + { count++; vTaskDelay(10); - if (count == 200) { + if (count == 200) + { // displays[i].init(0, false); vTaskDelay(100); - } else if (count > 205) { + } + else if (count > 205) + { Serial.printf("Busy timeout %d", i); break; } diff --git a/src/lib/screen_handler.cpp b/src/lib/screen_handler.cpp index dd30233..be2e8ca 100644 --- a/src/lib/screen_handler.cpp +++ b/src/lib/screen_handler.cpp @@ -36,7 +36,7 @@ void workerTask(void *pvParameters) { if (getCurrentScreen() == SCREEN_BTC_TICKER) { taskEpdContent = parsePriceData(price, priceSymbol); } else if (getCurrentScreen() == SCREEN_MSCW_TIME) { - taskEpdContent = parseSatsPerCurrency(price, priceSymbol); + taskEpdContent = parseSatsPerCurrency(price, priceSymbol, preferences.getBool("useSatsSymbol", false)); } else { taskEpdContent = parseMarketCap(getBlockHeight(), price, priceSymbol, @@ -50,7 +50,7 @@ void workerTask(void *pvParameters) { if (getCurrentScreen() != SCREEN_HALVING_COUNTDOWN) { taskEpdContent = parseBlockHeight(getBlockHeight()); } else { - taskEpdContent = parseHalvingCountdown(getBlockHeight()); + taskEpdContent = parseHalvingCountdown(getBlockHeight(), preferences.getBool("useBlkCountdown", false)); } if (getCurrentScreen() == SCREEN_HALVING_COUNTDOWN || diff --git a/src/lib/webserver.cpp b/src/lib/webserver.cpp index bc57f06..69f3bc9 100644 --- a/src/lib/webserver.cpp +++ b/src/lib/webserver.cpp @@ -11,7 +11,7 @@ void setupWebserver() { server.addHandler(&events); // server.serveStatic("/css", LittleFS, "/css/"); - // server.serveStatic("/js", LittleFS, "/js/"); + server.serveStatic("/fonts", LittleFS, "/fonts/"); server.serveStatic("/build", LittleFS, "/build"); server.serveStatic("/swagger.json", LittleFS, "/swagger.json"); server.serveStatic("/api.html", LittleFS, "/api.html"); @@ -320,7 +320,7 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json) { String boolSettings[] = {"fetchEurPrice", "ledTestOnPower", "ledFlashOnUpd", "mdnsEnabled", "otaEnabled", "stealFocus", - "mcapBigChar"}; + "mcapBigChar", "useSatsSymbol", "useBlkCountdown"}; for (String setting : boolSettings) { if (settings.containsKey(setting)) { @@ -402,11 +402,14 @@ void onApiSettingsGet(AsyncWebServerRequest *request) { root["ledTestOnPower"] = preferences.getBool("ledTestOnPower", true); root["ledFlashOnUpd"] = preferences.getBool("ledFlashOnUpd", false); root["ledBrightness"] = preferences.getUInt("ledBrightness", 128); - root["stealFocus"] = preferences.getBool("stealFocus", true); + root["stealFocus"] = preferences.getBool("stealFocus", false); root["mcapBigChar"] = preferences.getBool("mcapBigChar", true); root["mdnsEnabled"] = preferences.getBool("mdnsEnabled", true); root["otaEnabled"] = preferences.getBool("otaEnabled", true); root["fetchEurPrice"] = preferences.getBool("fetchEurPrice", false); + root["useSatsSymbol"] = preferences.getBool("useSatsSymbol", false); + root["useBlkCountdown"] = preferences.getBool("useBlkCountdown", false); + root["hostnamePrefix"] = preferences.getString("hostnamePrefix", "btclock"); root["hostname"] = getMyHostname(); root["ip"] = WiFi.localIP(); diff --git a/test/test_datahandler/test_main.cpp b/test/test_datahandler/test_main.cpp index ba6b011..f863551 100644 --- a/test/test_datahandler/test_main.cpp +++ b/test/test_datahandler/test_main.cpp @@ -10,7 +10,7 @@ void tearDown(void) { } void test_CorrectSatsPerDollarConversion(void) { - std::array output = parseSatsPerCurrency(37253, '$'); + std::array output = parseSatsPerCurrency(37253, '$', false); TEST_ASSERT_EQUAL_STRING("MSCW/TIME", output[0].c_str()); TEST_ASSERT_EQUAL_STRING("2", output[NUM_SCREENS-4].c_str()); TEST_ASSERT_EQUAL_STRING("6", output[NUM_SCREENS-3].c_str()); @@ -40,13 +40,49 @@ void test_PriceOf100kusd(void) { void test_PriceOf1MillionUsd(void) { std::array output = parsePriceData(1000000, '$'); TEST_ASSERT_EQUAL_STRING("BTC/USD", output[0].c_str()); - for (int i = 1; i <= NUM_SCREENS-3; i++) { - TEST_ASSERT_EQUAL_STRING(" ", output[i].c_str()); - } - TEST_ASSERT_EQUAL_STRING("1", output[NUM_SCREENS-2].c_str()); + + TEST_ASSERT_EQUAL_STRING("1", output[NUM_SCREENS-5].c_str()); + TEST_ASSERT_EQUAL_STRING(".", output[NUM_SCREENS-4].c_str()); + TEST_ASSERT_EQUAL_STRING("0", output[NUM_SCREENS-3].c_str()); + TEST_ASSERT_EQUAL_STRING("0", output[NUM_SCREENS-2].c_str()); TEST_ASSERT_EQUAL_STRING("M", output[NUM_SCREENS-1].c_str()); } +void test_McapLowerUsd(void) { + std::array output = parseMarketCap(810000, 26000, '$', true); + TEST_ASSERT_EQUAL_STRING("USD/MCAP", output[0].c_str()); + +// TEST_ASSERT_EQUAL_STRING("$", output[NUM_SCREENS-6].c_str()); + TEST_ASSERT_EQUAL_STRING("$", output[NUM_SCREENS-5].c_str()); + TEST_ASSERT_EQUAL_STRING("5", output[NUM_SCREENS-4].c_str()); + TEST_ASSERT_EQUAL_STRING("0", output[NUM_SCREENS-3].c_str()); + TEST_ASSERT_EQUAL_STRING("7", output[NUM_SCREENS-2].c_str()); + TEST_ASSERT_EQUAL_STRING("B", output[NUM_SCREENS-1].c_str()); +} + +void test_Mcap1TrillionUsd(void) { + std::array output = parseMarketCap(831000, 52000, '$', true); + TEST_ASSERT_EQUAL_STRING("USD/MCAP", output[0].c_str()); + + TEST_ASSERT_EQUAL_STRING("$", output[NUM_SCREENS-6].c_str()); + TEST_ASSERT_EQUAL_STRING("1", output[NUM_SCREENS-5].c_str()); + TEST_ASSERT_EQUAL_STRING(".", output[NUM_SCREENS-4].c_str()); + TEST_ASSERT_EQUAL_STRING("0", output[NUM_SCREENS-3].c_str()); + TEST_ASSERT_EQUAL_STRING("2", output[NUM_SCREENS-2].c_str()); + TEST_ASSERT_EQUAL_STRING("T", output[NUM_SCREENS-1].c_str()); +} + +void test_Mcap1TrillionEur(void) { + std::array output = parseMarketCap(831000, 52000, '[', true); + TEST_ASSERT_EQUAL_STRING("EUR/MCAP", output[0].c_str()); + TEST_ASSERT_EQUAL_STRING("[", output[NUM_SCREENS-6].c_str()); + TEST_ASSERT_EQUAL_STRING("1", output[NUM_SCREENS-5].c_str()); + TEST_ASSERT_EQUAL_STRING(".", output[NUM_SCREENS-4].c_str()); + TEST_ASSERT_EQUAL_STRING("0", output[NUM_SCREENS-3].c_str()); + TEST_ASSERT_EQUAL_STRING("2", output[NUM_SCREENS-2].c_str()); + TEST_ASSERT_EQUAL_STRING("T", output[NUM_SCREENS-1].c_str()); +} + // not needed when using generate_test_runner.rb int runUnityTests(void) { UNITY_BEGIN(); @@ -54,7 +90,10 @@ int runUnityTests(void) { RUN_TEST(test_SixCharacterBlockHeight); RUN_TEST(test_SevenCharacterBlockHeight); RUN_TEST(test_PriceOf100kusd); - RUN_TEST(test_PriceOf1MillionUsd); + RUN_TEST(test_McapLowerUsd); + RUN_TEST(test_Mcap1TrillionUsd); + RUN_TEST(test_Mcap1TrillionEur); + //RUN_TEST(test_Mcap1MillionEur); return UNITY_END(); }