From b4864b1db6e6fd9d0940fde06edf73c521cd47db Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Sun, 5 Jan 2025 18:08:21 +0100 Subject: [PATCH] Improve bitaxe handling code --- lib/btclock/bitaxe_handler.cpp | 72 ++++++++++++++++++------- lib/btclock/bitaxe_handler.hpp | 6 ++- lib/btclock/utils.cpp | 11 ++++ lib/btclock/utils.hpp | 3 +- src/lib/bitaxe_fetch.cpp | 24 ++++++--- src/lib/bitaxe_fetch.hpp | 5 +- src/lib/block_notify.cpp | 16 +++--- src/lib/block_notify.hpp | 16 +++--- test/test_bitaxehandler/test_main.cpp | 75 +++++++++++++++++++++++++++ 9 files changed, 183 insertions(+), 45 deletions(-) create mode 100644 test/test_bitaxehandler/test_main.cpp diff --git a/lib/btclock/bitaxe_handler.cpp b/lib/btclock/bitaxe_handler.cpp index c18b7de..c51ca7c 100644 --- a/lib/btclock/bitaxe_handler.cpp +++ b/lib/btclock/bitaxe_handler.cpp @@ -1,14 +1,20 @@ #include "bitaxe_handler.hpp" -std::array parseBitaxeHashRate(std::string text) +std::array parseBitaxeHashRate(uint64_t hashrate) { std::array ret; ret.fill(""); // Initialize all elements to empty strings - std::size_t textLength = text.length(); + // Convert hashrate to GH/s and round to nearest integer + double hashRateGH = static_cast(hashrate) / std::pow(10, getHashrateMultiplier('G')); + std::string hashRateStr = std::to_string(static_cast(std::round(hashRateGH))); + + // Place the icons + ret[0] = "mdi:bitaxe"; + ret[NUM_SCREENS - 1] = "GH/S"; // Calculate the position where the digits should start - // Account for the position of the "mdi:pickaxe" and the "GH/S" label + std::size_t textLength = hashRateStr.length(); std::size_t startIndex = NUM_SCREENS - 1 - textLength; // Insert the "mdi:pickaxe" icon just before the digits @@ -17,34 +23,64 @@ std::array parseBitaxeHashRate(std::string text) ret[startIndex - 1] = "mdi:pickaxe"; } - // Place the digits + // Place each digit for (std::size_t i = 0; i < textLength; ++i) { - ret[startIndex + i] = text.substr(i, 1); + ret[startIndex + i] = std::string(1, hashRateStr[i]); } - ret[NUM_SCREENS - 1] = "GH/S"; - ret[0] = "mdi:bitaxe"; - return ret; } -std::array parseBitaxeBestDiff(std::string text) +std::array parseBitaxeBestDiff(uint64_t difficulty) { std::array ret; - std::uint32_t firstIndex = 0; + ret.fill(""); - if (text.length() < NUM_SCREENS) - { - text.insert(text.begin(), NUM_SCREENS - text.length(), ' '); - ret[0] = "mdi:bitaxe"; - ret[1] = "mdi:rocket"; - firstIndex = 2; + // Add icons at the start + ret[0] = "mdi:bitaxe"; + ret[1] = "mdi:rocket"; + + if (difficulty == 0) { + ret[NUM_SCREENS - 1] = "0"; + return ret; } - for (std::uint8_t i = firstIndex; i < NUM_SCREENS; i++) + // Find the appropriate suffix and format the number + const std::pair suffixes[] = { + {'Q', 15}, {'T', 12}, {'G', 9}, {'M', 6}, {'K', 3} + }; + + std::string text; + for (const auto& suffix : suffixes) { + if (difficulty >= std::pow(10, suffix.second)) { + double value = difficulty / std::pow(10, suffix.second); + char buffer[32]; + snprintf(buffer, sizeof(buffer), "%.1f", value); + text = buffer; + // Remove trailing zeros and decimal point if not needed + if (text.find('.') != std::string::npos) { + text = text.substr(0, text.find_last_not_of('0') + 1); + if (text.back() == '.') { + text.pop_back(); + } + } + text += suffix.first; + break; + } + } + + if (text.empty()) { + text = std::to_string(difficulty); + } + + // Calculate start position to right-align the text + std::size_t startIndex = NUM_SCREENS - text.length(); + + // Place the formatted difficulty string + for (std::size_t i = 0; i < text.length() && (startIndex + i) < NUM_SCREENS; ++i) { - ret[i] = text[i]; + ret[startIndex + i] = std::string(1, text[i]); } return ret; diff --git a/lib/btclock/bitaxe_handler.hpp b/lib/btclock/bitaxe_handler.hpp index c78c8f7..f1484ef 100644 --- a/lib/btclock/bitaxe_handler.hpp +++ b/lib/btclock/bitaxe_handler.hpp @@ -1,5 +1,7 @@ #include #include +#include +#include "utils.hpp" -std::array parseBitaxeHashRate(std::string text); -std::array parseBitaxeBestDiff(std::string text); +std::array parseBitaxeHashRate(uint64_t hashrate); +std::array parseBitaxeBestDiff(uint64_t difficulty); diff --git a/lib/btclock/utils.cpp b/lib/btclock/utils.cpp index d5c8027..443eb1e 100644 --- a/lib/btclock/utils.cpp +++ b/lib/btclock/utils.cpp @@ -243,3 +243,14 @@ int getHashrateMultiplier(char unit) { }; return multipliers.at(unit); } + +int getDifficultyMultiplier(char unit) { + if (unit == '0') + return 0; + + static const std::unordered_map multipliers = { + {'Q', 15}, {'T', 12}, {'B', 9}, {'M', 6}, {'K', 3}, {'G', 9}, + {'q', 15}, {'t', 12}, {'b', 9}, {'m', 6}, {'k', 3}, {'g', 9} + }; + return multipliers.at(unit); +} diff --git a/lib/btclock/utils.hpp b/lib/btclock/utils.hpp index 44df032..05540d4 100644 --- a/lib/btclock/utils.hpp +++ b/lib/btclock/utils.hpp @@ -16,4 +16,5 @@ 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); void parseHashrateString(const std::string& hashrate, std::string& label, std::string& output, unsigned int maxCharacters); -int getHashrateMultiplier(char unit); \ No newline at end of file +int getHashrateMultiplier(char unit); +int getDifficultyMultiplier(char unit); \ No newline at end of file diff --git a/src/lib/bitaxe_fetch.cpp b/src/lib/bitaxe_fetch.cpp index f439cb4..d2dae13 100644 --- a/src/lib/bitaxe_fetch.cpp +++ b/src/lib/bitaxe_fetch.cpp @@ -2,15 +2,15 @@ TaskHandle_t bitaxeFetchTaskHandle; -std::string bitaxeHashrate; -std::string bitaxeBestDiff; +uint64_t bitaxeHashrate; +uint64_t bitaxeBestDiff; -std::string getBitAxeHashRate() +uint64_t getBitAxeHashRate() { return bitaxeHashrate; } -std::string getBitaxeBestDiff() +uint64_t getBitaxeBestDiff() { return bitaxeBestDiff; } @@ -33,8 +33,20 @@ void taskBitaxeFetch(void *pvParameters) String payload = http.getString(); JsonDocument doc; deserializeJson(doc, payload); - bitaxeHashrate = std::to_string(static_cast(std::round(doc["hashRate"].as()))); - bitaxeBestDiff = doc["bestDiff"].as(); + + // Convert GH/s to H/s (multiply by 10^9) + float hashRateGH = doc["hashRate"].as(); + bitaxeHashrate = static_cast(std::round(hashRateGH * std::pow(10, getHashrateMultiplier('G')))); + + // Parse difficulty string and convert to uint64_t + std::string diffStr = doc["bestDiff"].as(); + char diffUnit = diffStr[diffStr.length() - 1]; + if (std::isalpha(diffUnit)) { + float diffValue = std::stof(diffStr.substr(0, diffStr.length() - 1)); + bitaxeBestDiff = static_cast(std::round(diffValue * std::pow(10, getDifficultyMultiplier(diffUnit)))); + } else { + bitaxeBestDiff = std::stoull(diffStr); + } if (workQueue != nullptr && (ScreenHandler::getCurrentScreen() == SCREEN_BITAXE_HASHRATE || ScreenHandler::getCurrentScreen() == SCREEN_BITAXE_BESTDIFF)) { diff --git a/src/lib/bitaxe_fetch.hpp b/src/lib/bitaxe_fetch.hpp index 8e4f7f3..8e1da37 100644 --- a/src/lib/bitaxe_fetch.hpp +++ b/src/lib/bitaxe_fetch.hpp @@ -2,6 +2,7 @@ #include #include +#include #include "lib/config.hpp" #include "lib/shared.hpp" @@ -11,5 +12,5 @@ extern TaskHandle_t bitaxeFetchTaskHandle; void setupBitaxeFetchTask(); void taskBitaxeFetch(void *pvParameters); -std::string getBitAxeHashRate(); -std::string getBitaxeBestDiff(); \ No newline at end of file +uint64_t getBitAxeHashRate(); +uint64_t getBitaxeBestDiff(); \ No newline at end of file diff --git a/src/lib/block_notify.cpp b/src/lib/block_notify.cpp index a1ce1fc..ec72138 100644 --- a/src/lib/block_notify.cpp +++ b/src/lib/block_notify.cpp @@ -2,8 +2,8 @@ char *wsServer; esp_websocket_client_handle_t blockNotifyClient = NULL; -uint currentBlockHeight = 873400; -uint blockMedianFee = 1; +uint32_t currentBlockHeight = 873400; +uint16_t blockMedianFee = 1; bool blockNotifyInit = false; unsigned long int lastBlockUpdate; @@ -179,7 +179,7 @@ void onWebsocketBlockMessage(esp_websocket_event_data_t *event_data) doc.clear(); } -void processNewBlock(uint newBlockHeight) { +void processNewBlock(uint32_t newBlockHeight) { if (newBlockHeight < currentBlockHeight) return; @@ -222,7 +222,7 @@ void processNewBlock(uint newBlockHeight) { } } -void processNewBlockFee(uint newBlockFee) { +void processNewBlockFee(uint16_t newBlockFee) { if (blockMedianFee == newBlockFee) { return; @@ -238,16 +238,16 @@ void processNewBlockFee(uint newBlockFee) { } } -uint getBlockHeight() { return currentBlockHeight; } +uint32_t getBlockHeight() { return currentBlockHeight; } -void setBlockHeight(uint newBlockHeight) +void setBlockHeight(uint32_t newBlockHeight) { currentBlockHeight = newBlockHeight; } -uint getBlockMedianFee() { return blockMedianFee; } +uint16_t getBlockMedianFee() { return blockMedianFee; } -void setBlockMedianFee(uint newBlockMedianFee) +void setBlockMedianFee(uint16_t newBlockMedianFee) { blockMedianFee = newBlockMedianFee; } diff --git a/src/lib/block_notify.hpp b/src/lib/block_notify.hpp index d5565eb..9c41bf0 100644 --- a/src/lib/block_notify.hpp +++ b/src/lib/block_notify.hpp @@ -22,20 +22,20 @@ void onWebsocketBlockEvent(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data); void onWebsocketBlockMessage(esp_websocket_event_data_t *event_data); -void setBlockHeight(uint newBlockHeight); -uint getBlockHeight(); +void setBlockHeight(uint32_t newBlockHeight); +uint32_t getBlockHeight(); -void setBlockMedianFee(uint blockMedianFee); -uint getBlockMedianFee(); +void setBlockMedianFee(uint16_t blockMedianFee); +uint16_t getBlockMedianFee(); bool isBlockNotifyConnected(); void stopBlockNotify(); void restartBlockNotify(); -void processNewBlock(uint newBlockHeight); -void processNewBlockFee(uint newBlockFee); +void processNewBlock(uint32_t newBlockHeight); +void processNewBlockFee(uint16_t newBlockFee); bool getBlockNotifyInit(); -uint getLastBlockUpdate(); +uint32_t getLastBlockUpdate(); int getBlockFetch(); -void setLastBlockUpdate(uint lastUpdate); \ No newline at end of file +void setLastBlockUpdate(uint32_t lastUpdate); diff --git a/test/test_bitaxehandler/test_main.cpp b/test/test_bitaxehandler/test_main.cpp new file mode 100644 index 0000000..4336107 --- /dev/null +++ b/test/test_bitaxehandler/test_main.cpp @@ -0,0 +1,75 @@ +#include +#include + +template +std::string joinArrayWithBrackets(const std::array& arr, const std::string& separator = " ") { + std::ostringstream result; + for (size_t i = 0; i < N; ++i) { + if (i > 0) { + result << separator; + } + result << '[' << arr[i] << ']'; + } + return result.str(); +} + +void setUp(void) +{ + // set stuff up here +} + +void tearDown(void) +{ + // clean stuff up here +} + +void test_BitaxeParseHashrate(void) +{ + std::array output = parseBitaxeHashRate(656130000000); + + std::string joined = joinArrayWithBrackets(output); + + + TEST_ASSERT_EQUAL_STRING_MESSAGE("mdi:bitaxe", output[0].c_str(), joined.c_str()); + + TEST_ASSERT_EQUAL_STRING_MESSAGE("6", output[NUM_SCREENS - 4].c_str(), joined.c_str()); + TEST_ASSERT_EQUAL_STRING_MESSAGE("5", output[NUM_SCREENS - 3].c_str(), joined.c_str()); + TEST_ASSERT_EQUAL_STRING_MESSAGE("6", output[NUM_SCREENS - 2].c_str(), joined.c_str()); + TEST_ASSERT_EQUAL_STRING_MESSAGE("GH/S", output[NUM_SCREENS - 1].c_str(), joined.c_str()); +} + +void test_BitaxeParseBestDiff(void) +{ + std::array output = parseBitaxeBestDiff(15800000000); + + std::string joined = joinArrayWithBrackets(output); + + TEST_ASSERT_EQUAL_STRING_MESSAGE("mdi:bitaxe", output[0].c_str(), joined.c_str()); + + + TEST_ASSERT_EQUAL_STRING_MESSAGE("1", output[NUM_SCREENS - 5].c_str(), joined.c_str()); + TEST_ASSERT_EQUAL_STRING_MESSAGE("5", output[NUM_SCREENS - 4].c_str(), joined.c_str()); + TEST_ASSERT_EQUAL_STRING_MESSAGE(".", output[NUM_SCREENS - 3].c_str(), joined.c_str()); + TEST_ASSERT_EQUAL_STRING_MESSAGE("8", output[NUM_SCREENS - 2].c_str(), joined.c_str()); + TEST_ASSERT_EQUAL_STRING_MESSAGE("G", output[NUM_SCREENS - 1].c_str(), joined.c_str()); +} + +// not needed when using generate_test_runner.rb +int runUnityTests(void) +{ + UNITY_BEGIN(); + RUN_TEST(test_BitaxeParseHashrate); + RUN_TEST(test_BitaxeParseBestDiff); + + return UNITY_END(); +} + +int main(void) +{ + return runUnityTests(); +} + +extern "C" void app_main() +{ + runUnityTests(); +}