mirror of
https://github.com/usatiuk/cardboy.git
synced 2025-10-28 15:17:48 +01:00
battery percentage
This commit is contained in:
@@ -18,6 +18,7 @@ public:
|
|||||||
float get_voltage() const;
|
float get_voltage() const;
|
||||||
float get_charge() const;
|
float get_charge() const;
|
||||||
float get_current() const;
|
float get_current() const;
|
||||||
|
float get_percentage() const;
|
||||||
|
|
||||||
void pooler(); // FIXME:
|
void pooler(); // FIXME:
|
||||||
private:
|
private:
|
||||||
@@ -33,6 +34,7 @@ private:
|
|||||||
volatile float _voltage;
|
volatile float _voltage;
|
||||||
volatile float _current;
|
volatile float _current;
|
||||||
volatile float _charge;
|
volatile float _charge;
|
||||||
|
volatile float _percentage;
|
||||||
|
|
||||||
TaskHandle_t _pooler_task;
|
TaskHandle_t _pooler_task;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -48,6 +48,8 @@ static constexpr uint16_t DesignCapMah = 180; // 100mOhm
|
|||||||
|
|
||||||
constexpr float mahToCap(float mah) { return mah * (1000.0 / 5.0) * RSense; }
|
constexpr float mahToCap(float mah) { return mah * (1000.0 / 5.0) * RSense; }
|
||||||
constexpr float capToMah(uint16_t cap) { return cap * (5.0 / 1000.0) / RSense; }
|
constexpr float capToMah(uint16_t cap) { return cap * (5.0 / 1000.0) / RSense; }
|
||||||
|
// lsb is 1/256%
|
||||||
|
constexpr float regToPercent(uint16_t reg) { return static_cast<float>(reg) / 256.0f; }
|
||||||
constexpr float regToCurrent(uint16_t reg) {
|
constexpr float regToCurrent(uint16_t reg) {
|
||||||
return static_cast<float>(static_cast<int16_t>(reg)) * 0.0015625f / RSense; // Convert to mA
|
return static_cast<float>(static_cast<int16_t>(reg)) * 0.0015625f / RSense; // Convert to mA
|
||||||
}
|
}
|
||||||
@@ -103,6 +105,7 @@ void BatMon::pooler() {
|
|||||||
_charge = capToMah(ReadRegister(0x05));
|
_charge = capToMah(ReadRegister(0x05));
|
||||||
_current = regToCurrent(ReadRegister(0x0B));
|
_current = regToCurrent(ReadRegister(0x0B));
|
||||||
_voltage = regToVoltage(ReadRegister(0x09));
|
_voltage = regToVoltage(ReadRegister(0x09));
|
||||||
|
_percentage = regToPercent(ReadRegister(0x06));
|
||||||
vTaskDelay(pdMS_TO_TICKS(10000));
|
vTaskDelay(pdMS_TO_TICKS(10000));
|
||||||
if (_voltage < 3.0f) {
|
if (_voltage < 3.0f) {
|
||||||
Shutdowner::get().shutdown();
|
Shutdowner::get().shutdown();
|
||||||
@@ -113,3 +116,4 @@ void BatMon::pooler() {
|
|||||||
float BatMon::get_voltage() const { return _voltage; }
|
float BatMon::get_voltage() const { return _voltage; }
|
||||||
float BatMon::get_charge() const { return _charge; }
|
float BatMon::get_charge() const { return _charge; }
|
||||||
float BatMon::get_current() const { return _current; }
|
float BatMon::get_current() const { return _current; }
|
||||||
|
float BatMon::get_percentage() const { return _percentage; }
|
||||||
|
|||||||
@@ -78,6 +78,7 @@ public:
|
|||||||
[[nodiscard]] float voltage() const override { return BatMon::get().get_voltage(); }
|
[[nodiscard]] float voltage() const override { return BatMon::get().get_voltage(); }
|
||||||
[[nodiscard]] float charge() const override { return BatMon::get().get_charge(); }
|
[[nodiscard]] float charge() const override { return BatMon::get().get_charge(); }
|
||||||
[[nodiscard]] float current() const override { return BatMon::get().get_current(); }
|
[[nodiscard]] float current() const override { return BatMon::get().get_current(); }
|
||||||
|
[[nodiscard]] float percentage() const override { return BatMon::get().get_percentage(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
class EspRuntime::StorageService final : public cardboy::sdk::IStorage {
|
class EspRuntime::StorageService final : public cardboy::sdk::IStorage {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <cmath>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -446,6 +447,18 @@ private:
|
|||||||
|
|
||||||
framebuffer.frameReady();
|
framebuffer.frameReady();
|
||||||
|
|
||||||
|
if (auto* battery = context.battery(); battery && battery->hasData()) {
|
||||||
|
const float percentage = battery->percentage();
|
||||||
|
if (std::isfinite(percentage) && percentage >= 0.0f) {
|
||||||
|
char pct[8];
|
||||||
|
std::snprintf(pct, sizeof(pct), "%.0f%%", static_cast<double>(percentage));
|
||||||
|
const int pctWidth = font16x8::measureText(pct, 1, 1);
|
||||||
|
const int pctX = framebuffer.width() - pctWidth - 4;
|
||||||
|
const int pctY = 4;
|
||||||
|
font16x8::drawText(framebuffer, pctX, pctY, pct, 1, true, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const int scaleTime = 4;
|
const int scaleTime = 4;
|
||||||
const int scaleSeconds = 2;
|
const int scaleSeconds = 2;
|
||||||
const int scaleSmall = 1;
|
const int scaleSmall = 1;
|
||||||
@@ -531,10 +544,10 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const int defaultTimeY = (framebuffer.height() - font16x8::kGlyphHeight * scaleTime) / 2 - 8;
|
const int defaultTimeY = (framebuffer.height() - font16x8::kGlyphHeight * scaleTime) / 2 - 8;
|
||||||
const int minTimeY = (cardHeight > 0) ? (cardMarginTop + cardHeight + 12) : 16;
|
const int minTimeY = (cardHeight > 0) ? (cardMarginTop + cardHeight + 12) : 16;
|
||||||
const int maxTimeY = std::max(minTimeY, framebuffer.height() - font16x8::kGlyphHeight * scaleTime - 48);
|
const int maxTimeY = std::max(minTimeY, framebuffer.height() - font16x8::kGlyphHeight * scaleTime - 48);
|
||||||
const int timeY = std::clamp(defaultTimeY, minTimeY, maxTimeY);
|
const int timeY = std::clamp(defaultTimeY, minTimeY, maxTimeY);
|
||||||
|
|
||||||
char hoursMinutes[6];
|
char hoursMinutes[6];
|
||||||
std::snprintf(hoursMinutes, sizeof(hoursMinutes), "%02d:%02d", snap.hour24, snap.minute);
|
std::snprintf(hoursMinutes, sizeof(hoursMinutes), "%02d:%02d", snap.hour24, snap.minute);
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ public:
|
|||||||
[[nodiscard]] virtual float voltage() const { return 0.0f; }
|
[[nodiscard]] virtual float voltage() const { return 0.0f; }
|
||||||
[[nodiscard]] virtual float charge() const { return 0.0f; }
|
[[nodiscard]] virtual float charge() const { return 0.0f; }
|
||||||
[[nodiscard]] virtual float current() const { return 0.0f; }
|
[[nodiscard]] virtual float current() const { return 0.0f; }
|
||||||
|
[[nodiscard]] virtual float percentage() const { return 0.0f; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class IStorage {
|
class IStorage {
|
||||||
|
|||||||
@@ -40,233 +40,232 @@ public:
|
|||||||
class DesktopBattery final : public cardboy::sdk::IBatteryMonitor {
|
class DesktopBattery final : public cardboy::sdk::IBatteryMonitor {
|
||||||
public:
|
public:
|
||||||
[[nodiscard]] bool hasData() const override { return false; }
|
[[nodiscard]] bool hasData() const override { return false; }
|
||||||
};
|
|
||||||
|
|
||||||
class DesktopStorage final : public cardboy::sdk::IStorage {
|
class DesktopStorage final : public cardboy::sdk::IStorage {
|
||||||
public:
|
public:
|
||||||
[[nodiscard]] bool readUint32(std::string_view ns, std::string_view key, std::uint32_t& out) override;
|
[[nodiscard]] bool readUint32(std::string_view ns, std::string_view key, std::uint32_t& out) override;
|
||||||
void writeUint32(std::string_view ns, std::string_view key, std::uint32_t value) override;
|
void writeUint32(std::string_view ns, std::string_view key, std::uint32_t value) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unordered_map<std::string, std::uint32_t> data;
|
std::unordered_map<std::string, std::uint32_t> data;
|
||||||
|
|
||||||
static std::string composeKey(std::string_view ns, std::string_view key);
|
static std::string composeKey(std::string_view ns, std::string_view key);
|
||||||
};
|
|
||||||
|
|
||||||
class DesktopRandom final : public cardboy::sdk::IRandom {
|
|
||||||
public:
|
|
||||||
DesktopRandom();
|
|
||||||
|
|
||||||
[[nodiscard]] std::uint32_t nextUint32() override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::mt19937 rng;
|
|
||||||
std::uniform_int_distribution<std::uint32_t> dist;
|
|
||||||
};
|
|
||||||
|
|
||||||
class DesktopHighResClock final : public cardboy::sdk::IHighResClock {
|
|
||||||
public:
|
|
||||||
DesktopHighResClock();
|
|
||||||
|
|
||||||
[[nodiscard]] std::uint64_t micros() override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
const std::chrono::steady_clock::time_point start;
|
|
||||||
};
|
|
||||||
|
|
||||||
class DesktopFilesystem final : public cardboy::sdk::IFilesystem {
|
|
||||||
public:
|
|
||||||
DesktopFilesystem();
|
|
||||||
|
|
||||||
bool mount() override;
|
|
||||||
[[nodiscard]] bool isMounted() const override { return mounted; }
|
|
||||||
[[nodiscard]] std::string basePath() const override { return basePathPath.string(); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::filesystem::path basePathPath;
|
|
||||||
bool mounted = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
class DesktopNotificationCenter final : public cardboy::sdk::INotificationCenter {
|
|
||||||
public:
|
|
||||||
void pushNotification(Notification notification) override;
|
|
||||||
[[nodiscard]] std::uint32_t revision() const override;
|
|
||||||
[[nodiscard]] std::vector<Notification> recent(std::size_t limit) const override;
|
|
||||||
void markAllRead() override;
|
|
||||||
void clear() override;
|
|
||||||
void removeById(std::uint64_t id) override;
|
|
||||||
void removeByExternalId(std::uint64_t externalId) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
static constexpr std::size_t kMaxEntries = 8;
|
|
||||||
|
|
||||||
mutable std::mutex mutex;
|
|
||||||
std::vector<Notification> entries;
|
|
||||||
std::uint64_t nextId = 1;
|
|
||||||
std::uint32_t revisionCounter = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
class DesktopLoopHooks final : public cardboy::sdk::ILoopHooks {
|
|
||||||
public:
|
|
||||||
explicit DesktopLoopHooks(DesktopRuntime& owner);
|
|
||||||
|
|
||||||
void onLoopIteration() override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
DesktopRuntime& runtime;
|
|
||||||
};
|
|
||||||
|
|
||||||
class DesktopEventBus final : public cardboy::sdk::IEventBus {
|
|
||||||
public:
|
|
||||||
void post(const cardboy::sdk::AppEvent& event) override;
|
|
||||||
std::optional<cardboy::sdk::AppEvent> pop(std::optional<std::uint32_t> timeout_ms = std::nullopt) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::mutex mutex;
|
|
||||||
std::condition_variable cv;
|
|
||||||
std::deque<cardboy::sdk::AppEvent> queue;
|
|
||||||
};
|
|
||||||
|
|
||||||
class DesktopTimerService final : public cardboy::sdk::ITimerService {
|
|
||||||
public:
|
|
||||||
DesktopTimerService(DesktopRuntime& owner, cardboy::sdk::IEventBus& eventBus);
|
|
||||||
~DesktopTimerService() override;
|
|
||||||
|
|
||||||
cardboy::sdk::AppTimerHandle scheduleTimer(std::uint32_t delay_ms, bool repeat) override;
|
|
||||||
void cancelTimer(cardboy::sdk::AppTimerHandle handle) override;
|
|
||||||
void cancelAllTimers() override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct TimerRecord {
|
|
||||||
cardboy::sdk::AppTimerHandle handle = cardboy::sdk::kInvalidAppTimer;
|
|
||||||
std::chrono::steady_clock::time_point due;
|
|
||||||
std::chrono::milliseconds interval{0};
|
|
||||||
bool repeat = false;
|
|
||||||
bool active = true;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void workerLoop();
|
class DesktopRandom final : public cardboy::sdk::IRandom {
|
||||||
void wakeWorker();
|
public:
|
||||||
void cleanupInactive();
|
DesktopRandom();
|
||||||
|
|
||||||
DesktopRuntime& runtime;
|
[[nodiscard]] std::uint32_t nextUint32() override;
|
||||||
cardboy::sdk::IEventBus& eventBus;
|
|
||||||
std::mutex mutex;
|
|
||||||
std::condition_variable cv;
|
|
||||||
std::vector<TimerRecord> timers;
|
|
||||||
bool stopWorker = false;
|
|
||||||
std::thread worker;
|
|
||||||
cardboy::sdk::AppTimerHandle nextHandle = 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
class DesktopAppServiceProvider final : public cardboy::sdk::IAppServiceProvider {
|
private:
|
||||||
public:
|
std::mt19937 rng;
|
||||||
DesktopAppServiceProvider(DesktopRuntime& owner, cardboy::sdk::IEventBus& bus);
|
std::uniform_int_distribution<std::uint32_t> dist;
|
||||||
|
|
||||||
[[nodiscard]] std::unique_ptr<cardboy::sdk::AppScopedServices>
|
|
||||||
createScopedServices(std::uint64_t generation) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct ScopedServices final : cardboy::sdk::AppScopedServices {
|
|
||||||
std::unique_ptr<DesktopTimerService> ownedTimer;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
DesktopRuntime& runtime;
|
class DesktopHighResClock final : public cardboy::sdk::IHighResClock {
|
||||||
cardboy::sdk::IEventBus& eventBus;
|
public:
|
||||||
};
|
DesktopHighResClock();
|
||||||
|
|
||||||
class DesktopFramebuffer final : public cardboy::sdk::FramebufferFacade<DesktopFramebuffer> {
|
[[nodiscard]] std::uint64_t micros() override;
|
||||||
public:
|
|
||||||
explicit DesktopFramebuffer(DesktopRuntime& runtime);
|
|
||||||
|
|
||||||
[[nodiscard]] int width_impl() const;
|
private:
|
||||||
[[nodiscard]] int height_impl() const;
|
const std::chrono::steady_clock::time_point start;
|
||||||
void drawPixel_impl(int x, int y, bool on);
|
};
|
||||||
void clear_impl(bool on);
|
|
||||||
void frameReady_impl();
|
|
||||||
void sendFrame_impl(bool clearAfterSend);
|
|
||||||
[[nodiscard]] bool frameInFlight_impl() const { return false; }
|
|
||||||
|
|
||||||
private:
|
class DesktopFilesystem final : public cardboy::sdk::IFilesystem {
|
||||||
DesktopRuntime& runtime;
|
public:
|
||||||
};
|
DesktopFilesystem();
|
||||||
|
|
||||||
class DesktopInput final : public cardboy::sdk::InputFacade<DesktopInput> {
|
bool mount() override;
|
||||||
public:
|
[[nodiscard]] bool isMounted() const override { return mounted; }
|
||||||
explicit DesktopInput(DesktopRuntime& runtime);
|
[[nodiscard]] std::string basePath() const override { return basePathPath.string(); }
|
||||||
|
|
||||||
cardboy::sdk::InputState readState_impl();
|
private:
|
||||||
void handleKey(sf::Keyboard::Key key, bool pressed);
|
std::filesystem::path basePathPath;
|
||||||
|
bool mounted = false;
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
class DesktopNotificationCenter final : public cardboy::sdk::INotificationCenter {
|
||||||
DesktopRuntime& runtime;
|
public:
|
||||||
cardboy::sdk::InputState state{};
|
void pushNotification(Notification notification) override;
|
||||||
};
|
[[nodiscard]] std::uint32_t revision() const override;
|
||||||
|
[[nodiscard]] std::vector<Notification> recent(std::size_t limit) const override;
|
||||||
|
void markAllRead() override;
|
||||||
|
void clear() override;
|
||||||
|
void removeById(std::uint64_t id) override;
|
||||||
|
void removeByExternalId(std::uint64_t externalId) override;
|
||||||
|
|
||||||
class DesktopClock final : public cardboy::sdk::ClockFacade<DesktopClock> {
|
private:
|
||||||
public:
|
static constexpr std::size_t kMaxEntries = 8;
|
||||||
explicit DesktopClock(DesktopRuntime& runtime);
|
|
||||||
|
|
||||||
std::uint32_t millis_impl();
|
mutable std::mutex mutex;
|
||||||
void sleep_ms_impl(std::uint32_t ms);
|
std::vector<Notification> entries;
|
||||||
|
std::uint64_t nextId = 1;
|
||||||
|
std::uint32_t revisionCounter = 0;
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
class DesktopLoopHooks final : public cardboy::sdk::ILoopHooks {
|
||||||
DesktopRuntime& runtime;
|
public:
|
||||||
const std::chrono::steady_clock::time_point start;
|
explicit DesktopLoopHooks(DesktopRuntime& owner);
|
||||||
};
|
|
||||||
|
|
||||||
class DesktopRuntime {
|
void onLoopIteration() override;
|
||||||
public:
|
|
||||||
DesktopRuntime();
|
|
||||||
|
|
||||||
cardboy::sdk::Services& serviceRegistry();
|
private:
|
||||||
void processEvents();
|
DesktopRuntime& runtime;
|
||||||
void presentIfNeeded();
|
};
|
||||||
void sleepFor(std::uint32_t ms);
|
|
||||||
|
|
||||||
[[nodiscard]] bool isRunning() const { return running; }
|
class DesktopEventBus final : public cardboy::sdk::IEventBus {
|
||||||
|
public:
|
||||||
|
void post(const cardboy::sdk::AppEvent& event) override;
|
||||||
|
std::optional<cardboy::sdk::AppEvent> pop(std::optional<std::uint32_t> timeout_ms = std::nullopt) override;
|
||||||
|
|
||||||
DesktopFramebuffer framebuffer;
|
private:
|
||||||
DesktopInput input;
|
std::mutex mutex;
|
||||||
DesktopClock clock;
|
std::condition_variable cv;
|
||||||
|
std::deque<cardboy::sdk::AppEvent> queue;
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
class DesktopTimerService final : public cardboy::sdk::ITimerService {
|
||||||
friend class DesktopFramebuffer;
|
public:
|
||||||
friend class DesktopInput;
|
DesktopTimerService(DesktopRuntime& owner, cardboy::sdk::IEventBus& eventBus);
|
||||||
friend class DesktopClock;
|
~DesktopTimerService() override;
|
||||||
|
|
||||||
void setPixel(int x, int y, bool on);
|
cardboy::sdk::AppTimerHandle scheduleTimer(std::uint32_t delay_ms, bool repeat) override;
|
||||||
void clearPixels(bool on);
|
void cancelTimer(cardboy::sdk::AppTimerHandle handle) override;
|
||||||
|
void cancelAllTimers() override;
|
||||||
|
|
||||||
sf::RenderWindow window;
|
private:
|
||||||
sf::Texture texture;
|
struct TimerRecord {
|
||||||
sf::Sprite sprite;
|
cardboy::sdk::AppTimerHandle handle = cardboy::sdk::kInvalidAppTimer;
|
||||||
std::vector<std::uint8_t> pixels;
|
std::chrono::steady_clock::time_point due;
|
||||||
bool dirty = true;
|
std::chrono::milliseconds interval{0};
|
||||||
bool running = true;
|
bool repeat = false;
|
||||||
bool clearNextFrame = true;
|
bool active = true;
|
||||||
|
};
|
||||||
|
|
||||||
DesktopBuzzer buzzerService;
|
void workerLoop();
|
||||||
DesktopBattery batteryService;
|
void wakeWorker();
|
||||||
DesktopStorage storageService;
|
void cleanupInactive();
|
||||||
DesktopRandom randomService;
|
|
||||||
DesktopHighResClock highResService;
|
|
||||||
DesktopFilesystem filesystemService;
|
|
||||||
DesktopEventBus eventBusService;
|
|
||||||
DesktopAppServiceProvider appServiceProvider;
|
|
||||||
DesktopNotificationCenter notificationService;
|
|
||||||
DesktopLoopHooks loopHooksService;
|
|
||||||
cardboy::sdk::Services services{};
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Backend {
|
DesktopRuntime& runtime;
|
||||||
using Framebuffer = DesktopFramebuffer;
|
cardboy::sdk::IEventBus& eventBus;
|
||||||
using Input = DesktopInput;
|
std::mutex mutex;
|
||||||
using Clock = DesktopClock;
|
std::condition_variable cv;
|
||||||
};
|
std::vector<TimerRecord> timers;
|
||||||
|
bool stopWorker = false;
|
||||||
|
std::thread worker;
|
||||||
|
cardboy::sdk::AppTimerHandle nextHandle = 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DesktopAppServiceProvider final : public cardboy::sdk::IAppServiceProvider {
|
||||||
|
public:
|
||||||
|
DesktopAppServiceProvider(DesktopRuntime& owner, cardboy::sdk::IEventBus& bus);
|
||||||
|
|
||||||
|
[[nodiscard]] std::unique_ptr<cardboy::sdk::AppScopedServices>
|
||||||
|
createScopedServices(std::uint64_t generation) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct ScopedServices final : cardboy::sdk::AppScopedServices {
|
||||||
|
std::unique_ptr<DesktopTimerService> ownedTimer;
|
||||||
|
};
|
||||||
|
|
||||||
|
DesktopRuntime& runtime;
|
||||||
|
cardboy::sdk::IEventBus& eventBus;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DesktopFramebuffer final : public cardboy::sdk::FramebufferFacade<DesktopFramebuffer> {
|
||||||
|
public:
|
||||||
|
explicit DesktopFramebuffer(DesktopRuntime& runtime);
|
||||||
|
|
||||||
|
[[nodiscard]] int width_impl() const;
|
||||||
|
[[nodiscard]] int height_impl() const;
|
||||||
|
void drawPixel_impl(int x, int y, bool on);
|
||||||
|
void clear_impl(bool on);
|
||||||
|
void frameReady_impl();
|
||||||
|
void sendFrame_impl(bool clearAfterSend);
|
||||||
|
[[nodiscard]] bool frameInFlight_impl() const { return false; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
DesktopRuntime& runtime;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DesktopInput final : public cardboy::sdk::InputFacade<DesktopInput> {
|
||||||
|
public:
|
||||||
|
explicit DesktopInput(DesktopRuntime& runtime);
|
||||||
|
|
||||||
|
cardboy::sdk::InputState readState_impl();
|
||||||
|
void handleKey(sf::Keyboard::Key key, bool pressed);
|
||||||
|
|
||||||
|
private:
|
||||||
|
DesktopRuntime& runtime;
|
||||||
|
cardboy::sdk::InputState state{};
|
||||||
|
};
|
||||||
|
|
||||||
|
class DesktopClock final : public cardboy::sdk::ClockFacade<DesktopClock> {
|
||||||
|
public:
|
||||||
|
explicit DesktopClock(DesktopRuntime& runtime);
|
||||||
|
|
||||||
|
std::uint32_t millis_impl();
|
||||||
|
void sleep_ms_impl(std::uint32_t ms);
|
||||||
|
|
||||||
|
private:
|
||||||
|
DesktopRuntime& runtime;
|
||||||
|
const std::chrono::steady_clock::time_point start;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DesktopRuntime {
|
||||||
|
public:
|
||||||
|
DesktopRuntime();
|
||||||
|
|
||||||
|
cardboy::sdk::Services& serviceRegistry();
|
||||||
|
void processEvents();
|
||||||
|
void presentIfNeeded();
|
||||||
|
void sleepFor(std::uint32_t ms);
|
||||||
|
|
||||||
|
[[nodiscard]] bool isRunning() const { return running; }
|
||||||
|
|
||||||
|
DesktopFramebuffer framebuffer;
|
||||||
|
DesktopInput input;
|
||||||
|
DesktopClock clock;
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class DesktopFramebuffer;
|
||||||
|
friend class DesktopInput;
|
||||||
|
friend class DesktopClock;
|
||||||
|
|
||||||
|
void setPixel(int x, int y, bool on);
|
||||||
|
void clearPixels(bool on);
|
||||||
|
|
||||||
|
sf::RenderWindow window;
|
||||||
|
sf::Texture texture;
|
||||||
|
sf::Sprite sprite;
|
||||||
|
std::vector<std::uint8_t> pixels;
|
||||||
|
bool dirty = true;
|
||||||
|
bool running = true;
|
||||||
|
bool clearNextFrame = true;
|
||||||
|
|
||||||
|
DesktopBuzzer buzzerService;
|
||||||
|
DesktopBattery batteryService;
|
||||||
|
DesktopStorage storageService;
|
||||||
|
DesktopRandom randomService;
|
||||||
|
DesktopHighResClock highResService;
|
||||||
|
DesktopFilesystem filesystemService;
|
||||||
|
DesktopEventBus eventBusService;
|
||||||
|
DesktopAppServiceProvider appServiceProvider;
|
||||||
|
DesktopNotificationCenter notificationService;
|
||||||
|
DesktopLoopHooks loopHooksService;
|
||||||
|
cardboy::sdk::Services services{};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Backend {
|
||||||
|
using Framebuffer = DesktopFramebuffer;
|
||||||
|
using Input = DesktopInput;
|
||||||
|
using Clock = DesktopClock;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace cardboy::backend::desktop
|
} // namespace cardboy::backend::desktop
|
||||||
|
|
||||||
namespace cardboy::backend {
|
namespace cardboy::backend {
|
||||||
using DesktopBackend = desktop::Backend;
|
using DesktopBackend = desktop::Backend;
|
||||||
} // namespace cardboy::backend
|
} // namespace cardboy::backend
|
||||||
|
|||||||
@@ -50,16 +50,12 @@ std::string StatusBar::prepareRightText() const {
|
|||||||
|
|
||||||
std::string right;
|
std::string right;
|
||||||
if (_services->battery && _services->battery->hasData()) {
|
if (_services->battery && _services->battery->hasData()) {
|
||||||
const float current = _services->battery->current();
|
const float current = _services->battery->current();
|
||||||
const float chargeMah = _services->battery->charge();
|
const float chargeMah = _services->battery->charge();
|
||||||
const float fallbackV = _services->battery->voltage();
|
const float percentage = _services->battery->percentage();
|
||||||
char buf[64];
|
char buf[64];
|
||||||
if (std::isfinite(current) && std::isfinite(chargeMah)) {
|
std::snprintf(buf, sizeof(buf), "%.2fmA %.2fmAh %.0f%%", static_cast<double>(current),
|
||||||
std::snprintf(buf, sizeof(buf), "cur %.2fmA chr %.2fmAh", static_cast<double>(current),
|
static_cast<double>(chargeMah), static_cast<double>(percentage));
|
||||||
static_cast<double>(chargeMah));
|
|
||||||
} else {
|
|
||||||
std::snprintf(buf, sizeof(buf), "vol %.2fV", static_cast<double>(fallbackV));
|
|
||||||
}
|
|
||||||
right.assign(buf);
|
right.assign(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user