diff --git a/Firmware/sdk/backend_interface/include/cardboy/sdk/platform.hpp b/Firmware/sdk/backend_interface/include/cardboy/sdk/platform.hpp index 9002800..3fa3f56 100644 --- a/Firmware/sdk/backend_interface/include/cardboy/sdk/platform.hpp +++ b/Firmware/sdk/backend_interface/include/cardboy/sdk/platform.hpp @@ -1,7 +1,7 @@ #pragma once -#include "input_state.hpp" #include "cardboy/sdk/framebuffer_hooks.hpp" +#include "input_state.hpp" #include #include diff --git a/Firmware/sdk/core/include/cardboy/sdk/app_system.hpp b/Firmware/sdk/core/include/cardboy/sdk/app_system.hpp index 796786b..13a271e 100644 --- a/Firmware/sdk/core/include/cardboy/sdk/app_system.hpp +++ b/Firmware/sdk/core/include/cardboy/sdk/app_system.hpp @@ -20,12 +20,12 @@ public: void run(); - [[nodiscard]] std::size_t appCount() const { return factories.size(); } + [[nodiscard]] std::size_t appCount() const { return factories.size(); } [[nodiscard]] const IAppFactory* factoryAt(std::size_t index) const; [[nodiscard]] std::size_t indexOfFactory(const IAppFactory* factory) const; [[nodiscard]] std::size_t currentFactoryIndex() const { return activeIndex; } - [[nodiscard]] const IApp* currentApp() const { return current.get(); } + [[nodiscard]] const IApp* currentApp() const { return current.get(); } [[nodiscard]] const IAppFactory* currentFactory() const { return activeFactory; } private: @@ -52,15 +52,15 @@ private: TimerRecord* findTimer(AppTimerHandle handle); bool handlePendingSwitchRequest(); - AppContext context; + AppContext context; std::vector> factories; - std::unique_ptr current; - IAppFactory* activeFactory = nullptr; + std::unique_ptr current; + IAppFactory* activeFactory = nullptr; std::size_t activeIndex = static_cast(-1); - std::vector timers; - AppTimerHandle nextTimerId = 1; - std::uint32_t currentGeneration = 0; - InputState lastInputState{}; + std::vector timers; + AppTimerHandle nextTimerId = 1; + std::uint32_t currentGeneration = 0; + InputState lastInputState{}; }; inline AppTimerHandle AppContext::scheduleTimerInternal(std::uint32_t delay_ms, bool repeat) { diff --git a/Firmware/sdk/core/include/cardboy/sdk/status_bar.hpp b/Firmware/sdk/core/include/cardboy/sdk/status_bar.hpp index bd8ff12..8d78e7f 100644 --- a/Firmware/sdk/core/include/cardboy/sdk/status_bar.hpp +++ b/Firmware/sdk/core/include/cardboy/sdk/status_bar.hpp @@ -19,8 +19,8 @@ public: void setServices(Services* services) { services_ = services; } - void setEnabled(bool value); - void toggle(); + void setEnabled(bool value); + void toggle(); [[nodiscard]] bool isEnabled() const { return enabled_; } void setCurrentAppName(std::string_view name); @@ -43,32 +43,41 @@ private: if (width <= 0) return; + const int barHeight = font16x8::kGlyphHeight + 2; + const int fillHeight = std::min(barHeight, fb.height()); + if (fillHeight <= 0) + return; + const std::string leftText = prepareLeftText(width); const std::string rightText = prepareRightText(); + for (int y = 0; y < fillHeight; ++y) { + for (int x = 0; x < width; ++x) + fb.drawPixel(x, y, true); + } + for (int x = 0; x < width; ++x) - fb.drawPixel(x, 0, true); + fb.drawPixel(x, 0, false); const int textY = 1; - const int barHeight = font16x8::kGlyphHeight + 2; const int bottomSeparatorY = textY + font16x8::kGlyphHeight + 1; - if (bottomSeparatorY < barHeight && bottomSeparatorY < fb.height()) { + if (bottomSeparatorY < fillHeight) { for (int x = 0; x < width; ++x) - fb.drawPixel(x, bottomSeparatorY, (x % 2) == 0); + fb.drawPixel(x, bottomSeparatorY, (x % 2) != 0); } const int leftX = 2; if (!leftText.empty()) - font16x8::drawText(fb, leftX, textY, leftText, 1, true, 1); + font16x8::drawText(fb, leftX, textY, leftText, 1, false, 1); if (!rightText.empty()) { - int rightWidth = font16x8::measureText(rightText, 1, 1); - int rightX = width - rightWidth - 2; - const int minRightX = leftX + font16x8::measureText(leftText, 1, 1) + 6; + int rightWidth = font16x8::measureText(rightText, 1, 1); + int rightX = width - rightWidth - 2; + const int minRightX = leftX + font16x8::measureText(leftText, 1, 1) + 6; if (rightX < minRightX) rightX = std::max(minRightX, width / 2); if (rightX < width) - font16x8::drawText(fb, rightX, textY, rightText, 1, true, 1); + font16x8::drawText(fb, rightX, textY, rightText, 1, false, 1); } } diff --git a/Firmware/sdk/core/src/app_system.cpp b/Firmware/sdk/core/src/app_system.cpp index e422ca3..d023626 100644 --- a/Firmware/sdk/core/src/app_system.cpp +++ b/Firmware/sdk/core/src/app_system.cpp @@ -25,7 +25,7 @@ void statusBarPreSendHook(void* framebuffer, void* userData) { } // namespace AppSystem::AppSystem(AppContext ctx) : context(std::move(ctx)) { - context.system = this; + context.system = this; auto& statusBar = StatusBar::instance(); statusBar.setServices(context.services); using FBType = typename AppContext::Framebuffer; @@ -252,4 +252,3 @@ bool AppSystem::handlePendingSwitchRequest() { } } // namespace cardboy::sdk - diff --git a/Firmware/sdk/core/src/framebuffer_hooks.cpp b/Firmware/sdk/core/src/framebuffer_hooks.cpp index 13d3142..a4c9764 100644 --- a/Firmware/sdk/core/src/framebuffer_hooks.cpp +++ b/Firmware/sdk/core/src/framebuffer_hooks.cpp @@ -2,8 +2,8 @@ namespace cardboy::sdk { -FramebufferHooks::PreSendHook FramebufferHooks::hook_ = nullptr; -void* FramebufferHooks::userData_ = nullptr; +FramebufferHooks::PreSendHook FramebufferHooks::hook_ = nullptr; +void* FramebufferHooks::userData_ = nullptr; void FramebufferHooks::setPreSendHook(PreSendHook hook, void* userData) { hook_ = hook; diff --git a/Firmware/sdk/core/src/status_bar.cpp b/Firmware/sdk/core/src/status_bar.cpp index e29728a..66ef423 100644 --- a/Firmware/sdk/core/src/status_bar.cpp +++ b/Firmware/sdk/core/src/status_bar.cpp @@ -2,6 +2,7 @@ #include #include +#include #include namespace cardboy::sdk { @@ -21,9 +22,8 @@ void StatusBar::toggle() { void StatusBar::setCurrentAppName(std::string_view name) { appName_.assign(name.begin(), name.end()); - std::transform(appName_.begin(), appName_.end(), appName_.begin(), [](unsigned char ch) { - return static_cast(std::toupper(ch)); - }); + std::transform(appName_.begin(), appName_.end(), appName_.begin(), + [](unsigned char ch) { return static_cast(std::toupper(ch)); }); } bool StatusBar::handleToggleInput(const InputState& current, const InputState& previous) { @@ -37,7 +37,7 @@ bool StatusBar::handleToggleInput(const InputState& current, const InputState& p } std::string StatusBar::prepareLeftText(int displayWidth) const { - std::string text = appName_.empty() ? std::string("CARDBOY") : appName_; + std::string text = appName_.empty() ? std::string("CARDBOY") : appName_; int maxWidth = std::max(0, displayWidth - 32); while (!text.empty() && font16x8::measureText(text, 1, 1) > maxWidth) text.pop_back(); @@ -50,13 +50,16 @@ std::string StatusBar::prepareRightText() const { std::string right; if (services_->battery && services_->battery->hasData()) { - const float charge = services_->battery->charge(); - char buf[32]; - if (charge > 0.0f && charge <= 1.5f) { - const int pct = std::clamp(static_cast(charge * 100.0f + 0.5f), 0, 100); - std::snprintf(buf, sizeof(buf), "BAT %d%%", pct); + const float current = services_->battery->current(); + const float chargeMah = services_->battery->charge(); + const float fallbackV = services_->battery->voltage(); + char buf[64]; + if (std::isfinite(current) && std::isfinite(chargeMah)) { + const long currentRounded = std::lround(static_cast(current)); + const long chargeRounded = std::lround(static_cast(chargeMah)); + std::snprintf(buf, sizeof(buf), "CUR %+ldMA CAP %ldMAH", currentRounded, std::max(0L, chargeRounded)); } else { - std::snprintf(buf, sizeof(buf), "BAT %.2fV", static_cast(services_->battery->voltage())); + std::snprintf(buf, sizeof(buf), "BAT %.2fV", static_cast(fallbackV)); } right.assign(buf); }